Skip to content

Instantly share code, notes, and snippets.

@patitonar
Created December 9, 2019 18:03
Show Gist options
  • Save patitonar/fe4888e786e9b6cdbfaeedaf8fe99b78 to your computer and use it in GitHub Desktop.
Save patitonar/fe4888e786e9b6cdbfaeedaf8fe99b78 to your computer and use it in GitHub Desktop.
BridgeValidators.sol for foreign xDai bridge in ethereum mainnet. Related to https://github.com/poanetwork/tokenbridge-contracts/pull/319
// File: contracts/upgradeability/EternalStorage.sol
pragma solidity 0.4.24;
/**
* @title EternalStorage
* @dev This contract holds all the necessary state variables to carry out the storage of any contract.
*/
contract EternalStorage {
mapping(bytes32 => uint256) internal uintStorage;
mapping(bytes32 => string) internal stringStorage;
mapping(bytes32 => address) internal addressStorage;
mapping(bytes32 => bytes) internal bytesStorage;
mapping(bytes32 => bool) internal boolStorage;
mapping(bytes32 => int256) internal intStorage;
}
// File: contracts/upgradeable_contracts/Ownable.sol
pragma solidity 0.4.24;
/**
* @title Ownable
* @dev This contract has an owner address providing basic authorization control
*/
contract Ownable is EternalStorage {
/**
* @dev Event to show ownership has been transferred
* @param previousOwner representing the address of the previous owner
* @param newOwner representing the address of the new owner
*/
event OwnershipTransferred(address previousOwner, address newOwner);
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner());
/* solcov ignore next */
_;
}
bytes32 internal constant OWNER = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0; // keccak256(abi.encodePacked("owner"))
/**
* @dev Tells the address of the owner
* @return the address of the owner
*/
function owner() public view returns (address) {
return addressStorage[OWNER];
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner the address to transfer ownership to.
*/
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0));
setOwner(newOwner);
}
/**
* @dev Sets a new owner address
*/
function setOwner(address newOwner) internal {
emit OwnershipTransferred(owner(), newOwner);
addressStorage[OWNER] = newOwner;
}
}
// File: openzeppelin-solidity/contracts/math/SafeMath.sol
pragma solidity ^0.4.24;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (_a == 0) {
return 0;
}
c = _a * _b;
assert(c / _a == _b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
// assert(_b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return _a / _b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_b <= _a);
return _a - _b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
c = _a + _b;
assert(c >= _a);
return c;
}
}
// File: contracts/upgradeable_contracts/Initializable.sol
pragma solidity 0.4.24;
contract Initializable is EternalStorage {
bytes32 internal constant INITIALIZED = 0x0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba; // keccak256(abi.encodePacked("isInitialized"))
function setInitialize() internal {
boolStorage[INITIALIZED] = true;
}
function isInitialized() public view returns (bool) {
return boolStorage[INITIALIZED];
}
}
// File: contracts/upgradeable_contracts/InitializableBridge.sol
pragma solidity 0.4.24;
contract InitializableBridge is Initializable {
bytes32 internal constant DEPLOYED_AT_BLOCK = 0xb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b0; // keccak256(abi.encodePacked("deployedAtBlock"))
function deployedAtBlock() external view returns (uint256) {
return uintStorage[DEPLOYED_AT_BLOCK];
}
}
// File: contracts/upgradeable_contracts/BaseBridgeValidators.sol
pragma solidity 0.4.24;
contract BaseBridgeValidators is InitializableBridge, Ownable {
using SafeMath for uint256;
address public constant F_ADDR = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
uint256 internal constant MAX_VALIDATORS = 100;
bytes32 internal constant REQUIRED_SIGNATURES = 0xd18ea17c351d6834a0e568067fb71804d2a588d5e26d60f792b1c724b1bd53b1; // keccak256(abi.encodePacked("requiredSignatures"))
bytes32 internal constant VALIDATOR_COUNT = 0x8656d603d9f985c3483946a92789d52202f49736384ba131cb92f62c4c1aa082; // keccak256(abi.encodePacked("validatorCount"))
event ValidatorAdded(address indexed validator);
event ValidatorRemoved(address indexed validator);
event RequiredSignaturesChanged(uint256 requiredSignatures);
function setRequiredSignatures(uint256 _requiredSignatures) external onlyOwner {
require(validatorCount() >= _requiredSignatures);
require(_requiredSignatures != 0);
uintStorage[REQUIRED_SIGNATURES] = _requiredSignatures;
emit RequiredSignaturesChanged(_requiredSignatures);
}
function getBridgeValidatorsInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (2, 3, 0);
}
function validatorList() external view returns (address[]) {
address[] memory list = new address[](validatorCount());
uint256 counter = 0;
address nextValidator = getNextValidator(F_ADDR);
require(nextValidator != address(0));
while (nextValidator != F_ADDR) {
list[counter] = nextValidator;
nextValidator = getNextValidator(nextValidator);
counter++;
require(nextValidator != address(0));
}
return list;
}
function _addValidator(address _validator) internal {
require(_validator != address(0) && _validator != F_ADDR);
require(!isValidator(_validator));
address firstValidator = getNextValidator(F_ADDR);
require(firstValidator != address(0));
setNextValidator(_validator, firstValidator);
setNextValidator(F_ADDR, _validator);
setValidatorCount(validatorCount().add(1));
}
function _removeValidator(address _validator) internal {
require(validatorCount() > requiredSignatures());
require(isValidator(_validator));
address validatorsNext = getNextValidator(_validator);
address index = F_ADDR;
address next = getNextValidator(index);
require(next != address(0));
while (next != _validator) {
index = next;
next = getNextValidator(index);
require(next != F_ADDR && next != address(0));
}
setNextValidator(index, validatorsNext);
deleteItemFromAddressStorage("validatorsList", _validator);
setValidatorCount(validatorCount().sub(1));
}
function requiredSignatures() public view returns (uint256) {
return uintStorage[REQUIRED_SIGNATURES];
}
function validatorCount() public view returns (uint256) {
return uintStorage[VALIDATOR_COUNT];
}
function isValidator(address _validator) public view returns (bool) {
return _validator != F_ADDR && getNextValidator(_validator) != address(0);
}
function getNextValidator(address _address) public view returns (address) {
return addressStorage[keccak256(abi.encodePacked("validatorsList", _address))];
}
function deleteItemFromAddressStorage(string _mapName, address _address) internal {
delete addressStorage[keccak256(abi.encodePacked(_mapName, _address))];
}
function setValidatorCount(uint256 _validatorCount) internal {
uintStorage[VALIDATOR_COUNT] = _validatorCount;
}
function setNextValidator(address _prevValidator, address _validator) internal {
addressStorage[keccak256(abi.encodePacked("validatorsList", _prevValidator))] = _validator;
}
function isValidatorDuty(address _validator) external view returns (bool) {
uint256 counter = 0;
address next = getNextValidator(F_ADDR);
require(next != address(0));
while (next != F_ADDR) {
if (next == _validator) {
return (block.number % validatorCount() == counter);
}
next = getNextValidator(next);
counter++;
require(next != address(0));
}
return false;
}
}
// File: contracts/upgradeable_contracts/BridgeValidators.sol
pragma solidity 0.4.24;
contract BridgeValidators is BaseBridgeValidators {
function initialize(uint256 _requiredSignatures, address[] _initialValidators, address _owner)
external
returns (bool)
{
require(!isInitialized());
require(_owner != address(0));
setOwner(_owner);
require(_requiredSignatures != 0);
require(_initialValidators.length >= _requiredSignatures);
require(_initialValidators.length <= MAX_VALIDATORS);
for (uint256 i = 0; i < _initialValidators.length; i++) {
require(_initialValidators[i] != address(0) && _initialValidators[i] != F_ADDR);
require(!isValidator(_initialValidators[i]));
if (i == 0) {
setNextValidator(F_ADDR, _initialValidators[i]);
if (_initialValidators.length == 1) {
setNextValidator(_initialValidators[i], F_ADDR);
}
} else if (i == _initialValidators.length - 1) {
setNextValidator(_initialValidators[i - 1], _initialValidators[i]);
setNextValidator(_initialValidators[i], F_ADDR);
} else {
setNextValidator(_initialValidators[i - 1], _initialValidators[i]);
}
emit ValidatorAdded(_initialValidators[i]);
}
setValidatorCount(_initialValidators.length);
uintStorage[REQUIRED_SIGNATURES] = _requiredSignatures;
uintStorage[DEPLOYED_AT_BLOCK] = block.number;
setInitialize();
emit RequiredSignaturesChanged(_requiredSignatures);
return isInitialized();
}
function addValidator(address _validator) external onlyOwner {
_addValidator(_validator);
emit ValidatorAdded(_validator);
}
function removeValidator(address _validator) external onlyOwner {
_removeValidator(_validator);
emit ValidatorRemoved(_validator);
}
function upgradeToV230() public {
bytes32 upgradeStorage = 0x2e8a0420c66b3c19df2ac1cd4ffadb5637da547c6fd49388c7fe28dc8c13a8dd; // keccak256(abi.encodePacked('isUpgradedToV230'))
require(!boolStorage[upgradeStorage]);
address validator1 = 0x9ad83402C19Af24F76afa1930a2B2EEC2F47A8C5;
address validator2 = 0x4D1c96B9A49C4469A0b720a22b74b034EDdFe051;
address validator3 = 0x491FC792e78CDadd7D31446Bb7bDDef876a69AD6;
address validator4 = 0xc073C8E5ED9Aa11CF6776C69b3e13b259Ba9F506;
setNextValidator(F_ADDR, validator1);
setNextValidator(validator1, validator2);
setNextValidator(validator2, validator3);
setNextValidator(validator3, validator4);
setNextValidator(validator4, F_ADDR);
boolStorage[upgradeStorage] = true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment