make contracts upgradeable
This commit is contained in:
parent
5eaa480b23
commit
fb28fd067c
|
@ -1,10 +0,0 @@
|
|||
pragma solidity ^0.4.19;
|
||||
|
||||
|
||||
contract BridgeDeploymentAddressStorage {
|
||||
uint256 public deployedAtBlock;
|
||||
|
||||
function BridgeDeploymentAddressStorage() public {
|
||||
deployedAtBlock = block.number;
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
pragma solidity 0.4.19;
|
||||
import "./libraries/SafeMath.sol";
|
||||
import "./libraries/Helpers.sol";
|
||||
import "./libraries/Message.sol";
|
||||
import "./IBridgeValidators.sol";
|
||||
import "./Validatable.sol";
|
||||
import "./BridgeDeploymentAddressStorage.sol";
|
||||
import "./IBurnableMintableERC677Token.sol";
|
||||
import "./ERC677Receiver.sol";
|
||||
|
||||
contract ForeignBridge is ERC677Receiver, Validatable, BridgeDeploymentAddressStorage {
|
||||
using SafeMath for uint256;
|
||||
uint256 public gasLimitDepositRelay;
|
||||
uint256 public gasLimitWithdrawConfirm;
|
||||
uint256 homeGasPrice = 1000000000 wei;
|
||||
uint256 public foreignDailyLimit;
|
||||
mapping (bytes32 => bytes) messages;
|
||||
mapping (bytes32 => bytes) signatures;
|
||||
mapping (bytes32 => bool) messages_signed;
|
||||
mapping (bytes32 => uint256) num_messages_signed;
|
||||
mapping (bytes32 => bool) deposits_signed;
|
||||
mapping (bytes32 => uint256) num_deposits_signed;
|
||||
mapping (uint256 => uint256) totalSpentPerDay;
|
||||
|
||||
IBurnableMintableERC677Token public erc677token;
|
||||
|
||||
/// triggered when relay of deposit from HomeBridge is complete
|
||||
event Deposit(address recipient, uint value);
|
||||
|
||||
/// Event created on money withdraw.
|
||||
event Withdraw(address recipient, uint256 value, uint256 homeGasPrice);
|
||||
|
||||
/// Collected signatures which should be relayed to home chain.
|
||||
event CollectedSignatures(address authorityResponsibleForRelay, bytes32 messageHash);
|
||||
|
||||
event GasConsumptionLimitsUpdated(uint256 gasLimitDepositRelay, uint256 gasLimitWithdrawConfirm);
|
||||
|
||||
event SignedForDeposit(address indexed signer, bytes32 message);
|
||||
event SignedForWithdraw(address indexed signer, bytes32 message);
|
||||
event DailyLimit(uint256 newLimit);
|
||||
|
||||
function ForeignBridge(
|
||||
address _validatorContract,
|
||||
address _erc677token,
|
||||
uint256 _foreignDailyLimit
|
||||
) public Validatable(_validatorContract) {
|
||||
require(_foreignDailyLimit > 0);
|
||||
erc677token = IBurnableMintableERC677Token(_erc677token);
|
||||
foreignDailyLimit = _foreignDailyLimit;
|
||||
}
|
||||
|
||||
function setGasLimitDepositRelay(uint256 _gas) public onlyOwner {
|
||||
gasLimitDepositRelay = _gas;
|
||||
|
||||
GasConsumptionLimitsUpdated(gasLimitDepositRelay, gasLimitWithdrawConfirm);
|
||||
}
|
||||
|
||||
function setGasLimitWithdrawConfirm(uint256 gas) public onlyOwner {
|
||||
gasLimitWithdrawConfirm = gas;
|
||||
|
||||
GasConsumptionLimitsUpdated(gasLimitDepositRelay, gasLimitWithdrawConfirm);
|
||||
}
|
||||
|
||||
function deposit(address recipient, uint value, bytes32 transactionHash) public onlyValidator {
|
||||
require(erc677token != address(0x0));
|
||||
|
||||
// Protection from misbehaing authority
|
||||
bytes32 hash_msg = keccak256(recipient, value, transactionHash);
|
||||
bytes32 hash_sender = keccak256(msg.sender, hash_msg);
|
||||
|
||||
// Duplicated deposits
|
||||
require(!deposits_signed[hash_sender]);
|
||||
deposits_signed[hash_sender] = true;
|
||||
|
||||
uint256 signed = num_deposits_signed[hash_msg] + 1;
|
||||
num_deposits_signed[hash_msg] = signed;
|
||||
|
||||
SignedForDeposit(msg.sender, transactionHash);
|
||||
|
||||
if (signed == validatorContract.requiredSignatures()) {
|
||||
// If the bridge contract does not own enough tokens to transfer
|
||||
// it will couse funds lock on the home side of the bridge
|
||||
erc677token.mint(recipient, value);
|
||||
Deposit(recipient, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns(bool) {
|
||||
require(erc677token != address(0x0));
|
||||
require(msg.sender == address(erc677token));
|
||||
require(withinLimit(_value));
|
||||
totalSpentPerDay[getCurrentDay()] = totalSpentPerDay[getCurrentDay()].add(_value);
|
||||
erc677token.burn(_value);
|
||||
Withdraw(_from, _value, homeGasPrice);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Should be used as sync tool
|
||||
///
|
||||
/// Message is a message that should be relayed to main chain once authorities sign it.
|
||||
///
|
||||
/// for withdraw message contains:
|
||||
/// withdrawal recipient (bytes20)
|
||||
/// withdrawal value (uint)
|
||||
/// foreign transaction hash (bytes32) // to avoid transaction duplication
|
||||
function submitSignature(bytes signature, bytes message) public onlyValidator {
|
||||
// ensure that `signature` is really `message` signed by `msg.sender`
|
||||
require(msg.sender == MessageSigning.recoverAddressFromSignedMessage(signature, message));
|
||||
|
||||
require(message.length == 116);
|
||||
bytes32 hash = keccak256(message);
|
||||
bytes32 hash_sender = keccak256(msg.sender, hash);
|
||||
|
||||
uint signed = num_messages_signed[hash_sender] + 1;
|
||||
|
||||
if (signed > 1) {
|
||||
// Duplicated signatures
|
||||
require(!messages_signed[hash_sender]);
|
||||
}
|
||||
else {
|
||||
// check if it will really reduce gas usage in case of the second transaction
|
||||
// with the same hash
|
||||
messages[hash] = message;
|
||||
}
|
||||
messages_signed[hash_sender] = true;
|
||||
|
||||
bytes32 sign_idx = keccak256(hash, (signed-1));
|
||||
signatures[sign_idx] = signature;
|
||||
|
||||
num_messages_signed[hash_sender] = signed;
|
||||
|
||||
// TODO: this may cause troubles if requiredSignatures len is changed
|
||||
SignedForWithdraw(msg.sender, hash);
|
||||
if (signed == validatorContract.requiredSignatures()) {
|
||||
CollectedSignatures(msg.sender, hash);
|
||||
}
|
||||
}
|
||||
|
||||
function signature(bytes32 hash, uint index) public view returns (bytes) {
|
||||
bytes32 sign_idx = keccak256(hash, index);
|
||||
return signatures[sign_idx];
|
||||
}
|
||||
|
||||
/// Get message
|
||||
function message(bytes32 hash) public view returns (bytes) {
|
||||
return messages[hash];
|
||||
}
|
||||
|
||||
function getCurrentDay() public view returns(uint256) {
|
||||
return now / 1 days;
|
||||
}
|
||||
|
||||
function setDailyLimit(uint256 _foreignDailyLimit) public onlyOwner {
|
||||
require(_foreignDailyLimit > 0);
|
||||
foreignDailyLimit = _foreignDailyLimit;
|
||||
DailyLimit(foreignDailyLimit);
|
||||
}
|
||||
|
||||
function withinLimit(uint256 _amount) public view returns(bool) {
|
||||
uint256 nextLimit = totalSpentPerDay[getCurrentDay()].add(_amount);
|
||||
return foreignDailyLimit >= nextLimit;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
pragma solidity ^0.4.19;
|
||||
import "./libraries/SafeMath.sol";
|
||||
import "./libraries/Helpers.sol";
|
||||
import "./libraries/Message.sol";
|
||||
import "./IBridgeValidators.sol";
|
||||
import "./Validatable.sol";
|
||||
import "./BridgeDeploymentAddressStorage.sol";
|
||||
|
||||
|
||||
contract HomeBridge is Validatable, BridgeDeploymentAddressStorage {
|
||||
using SafeMath for uint256;
|
||||
uint256 public gasLimitWithdrawRelay;
|
||||
uint256 public homeDailyLimit;
|
||||
mapping (uint256 => uint256) totalSpentPerDay;
|
||||
mapping (bytes32 => bool) withdraws;
|
||||
|
||||
event GasConsumptionLimitsUpdated(uint256 gas);
|
||||
event Deposit (address recipient, uint256 value);
|
||||
event Withdraw (address recipient, uint256 value);
|
||||
event DailyLimit(uint256 newLimit);
|
||||
|
||||
function HomeBridge (
|
||||
address _validatorContract,
|
||||
uint256 _homeDailyLimit
|
||||
) public Validatable(_validatorContract) {
|
||||
require(_homeDailyLimit > 0);
|
||||
homeDailyLimit = _homeDailyLimit;
|
||||
DailyLimit(homeDailyLimit);
|
||||
}
|
||||
|
||||
/// Should be used to deposit money.
|
||||
function () public payable {
|
||||
require(msg.value > 0);
|
||||
require(withinLimit(msg.value));
|
||||
totalSpentPerDay[getCurrentDay()] = totalSpentPerDay[getCurrentDay()].add(msg.value);
|
||||
Deposit(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
function setGasLimitWithdrawRelay(uint256 _gas) public onlyOwner {
|
||||
gasLimitWithdrawRelay = _gas;
|
||||
GasConsumptionLimitsUpdated(gasLimitWithdrawRelay);
|
||||
}
|
||||
|
||||
function withdraw(uint8[] vs, bytes32[] rs, bytes32[] ss, bytes message) public {
|
||||
require(message.length == 116);
|
||||
require(Helpers.hasEnoughValidSignatures(message, vs, rs, ss, validatorContract));
|
||||
|
||||
address recipient = Message.getRecipient(message);
|
||||
uint256 value = Message.getValue(message);
|
||||
bytes32 hash = Message.getTransactionHash(message);
|
||||
require(!withdraws[hash]);
|
||||
// Order of operations below is critical to avoid TheDAO-like re-entry bug
|
||||
withdraws[hash] = true;
|
||||
|
||||
// pay out recipient
|
||||
recipient.transfer(value);
|
||||
|
||||
Withdraw(recipient, value);
|
||||
}
|
||||
|
||||
function setDailyLimit(uint256 _homeDailyLimit) public onlyOwner {
|
||||
require(_homeDailyLimit > 0);
|
||||
homeDailyLimit = _homeDailyLimit;
|
||||
DailyLimit(homeDailyLimit);
|
||||
}
|
||||
|
||||
function getCurrentDay() public view returns(uint256) {
|
||||
return now / 1 days;
|
||||
}
|
||||
|
||||
function withinLimit(uint256 _amount) public view returns(bool) {
|
||||
uint256 nextLimit = totalSpentPerDay[getCurrentDay()].add(_amount);
|
||||
return homeDailyLimit >= nextLimit;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
pragma solidity ^0.4.19;
|
||||
import "./IBridgeValidators.sol";
|
||||
|
||||
|
||||
contract Validatable {
|
||||
IBridgeValidators public validatorContract;
|
||||
|
||||
modifier onlyValidator() {
|
||||
require(validatorContract.isValidator(msg.sender));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(validatorContract.currentOwner() == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
||||
function Validatable(address _validatorContract) public {
|
||||
require(_validatorContract != address(0));
|
||||
validatorContract = IBridgeValidators(_validatorContract);
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ library Helpers {
|
|||
bytes32[] _rs,
|
||||
bytes32[] _ss,
|
||||
IBridgeValidators _validatorContract) internal view returns (bool) {
|
||||
uint8 requiredSignatures = _validatorContract.requiredSignatures();
|
||||
uint256 requiredSignatures = _validatorContract.requiredSignatures();
|
||||
require(_vs.length >= requiredSignatures);
|
||||
bytes32 hash = MessageSigning.hashMessage(_message);
|
||||
address[] memory encounteredAddresses = new address[](requiredSignatures);
|
||||
|
|
|
@ -11,15 +11,17 @@ contract BridgeValidators is IBridgeValidators, Ownable, OwnedUpgradeabilityStor
|
|||
event ValidatorAdded (address validator);
|
||||
event ValidatorRemoved (address validator);
|
||||
|
||||
function BridgeValidators(uint8 _requiredSignatures, address[] _initialValidators) public Ownable() {
|
||||
function initialize(uint256 _requiredSignatures, address[] _initialValidators, address _owner) public {
|
||||
require(!isInitialized());
|
||||
setOwner(_owner);
|
||||
require(_requiredSignatures != 0);
|
||||
require(_initialValidators.length >= _requiredSignatures);
|
||||
setValidatorCount(_initialValidators.length);
|
||||
for (uint i = 0; i < _initialValidators.length; i++) {
|
||||
require(!isValidator(_initialValidators[i]) && _initialValidators[i] != address(0));
|
||||
addValidator(_initialValidators[i]);
|
||||
}
|
||||
setRequiredSignatures(_requiredSignatures);
|
||||
setInitialize(true);
|
||||
}
|
||||
|
||||
function addValidator(address _validator) public onlyOwner {
|
||||
|
@ -57,6 +59,10 @@ contract BridgeValidators is IBridgeValidators, Ownable, OwnedUpgradeabilityStor
|
|||
return validators(_validator) == true;
|
||||
}
|
||||
|
||||
function isInitialized() public view returns(bool) {
|
||||
return boolStorage[keccak256("isInitialized")];
|
||||
}
|
||||
|
||||
function setValidatorCount(uint256 _validatorCount) private {
|
||||
uintStorage[keccak256("validatorCount")] = _validatorCount;
|
||||
}
|
||||
|
@ -64,4 +70,8 @@ contract BridgeValidators is IBridgeValidators, Ownable, OwnedUpgradeabilityStor
|
|||
function setValidator(address _validator, bool _status) private {
|
||||
boolStorage[keccak256("validators", _validator)] = _status;
|
||||
}
|
||||
|
||||
function setInitialize(bool _status) private {
|
||||
boolStorage[keccak256("isInitialized")] = _status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
pragma solidity ^0.4.19;
|
||||
import "../libraries/SafeMath.sol";
|
||||
import "../libraries/Helpers.sol";
|
||||
import "../libraries/Message.sol";
|
||||
// import "./IBridgeValidators.sol";
|
||||
import "./U_Validatable.sol";
|
||||
// import "./BridgeDeploymentAddressStorage.sol";
|
||||
import "../IBurnableMintableERC677Token.sol";
|
||||
import "../ERC677Receiver.sol";
|
||||
|
||||
|
||||
contract ForeignBridge is ERC677Receiver, Validatable {
|
||||
using SafeMath for uint256;
|
||||
/// triggered when relay of deposit from HomeBridge is complete
|
||||
event Deposit(address recipient, uint value);
|
||||
|
||||
/// Event created on money withdraw.
|
||||
event Withdraw(address recipient, uint256 value, uint256 homeGasPrice);
|
||||
|
||||
/// Collected signatures which should be relayed to home chain.
|
||||
event CollectedSignatures(address authorityResponsibleForRelay, bytes32 messageHash);
|
||||
|
||||
event GasConsumptionLimitsUpdated(uint256 gasLimitDepositRelay, uint256 gasLimitWithdrawConfirm);
|
||||
|
||||
event SignedForDeposit(address indexed signer, bytes32 message);
|
||||
event SignedForWithdraw(address indexed signer, bytes32 message);
|
||||
event DailyLimit(uint256 newLimit);
|
||||
|
||||
function initialize(
|
||||
address _validatorContract,
|
||||
address _erc677token,
|
||||
uint256 _foreignDailyLimit
|
||||
) public {
|
||||
require(!isInitialized());
|
||||
require(_validatorContract != address(0));
|
||||
require(_foreignDailyLimit > 0);
|
||||
addressStorage[keccak256("validatorContract")] = _validatorContract;
|
||||
setErc677token(_erc677token);
|
||||
setForeignDailyLimit(_foreignDailyLimit);
|
||||
uintStorage[keccak256("deployedAtBlock")] = block.number;
|
||||
setInitialize(true);
|
||||
}
|
||||
|
||||
function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns(bool) {
|
||||
require(address(erc677token()) != address(0x0));
|
||||
require(msg.sender == address(erc677token()));
|
||||
require(withinLimit(_value));
|
||||
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(_value));
|
||||
erc677token().burn(_value);
|
||||
Withdraw(_from, _value, homeGasPrice());
|
||||
return true;
|
||||
}
|
||||
|
||||
function totalSpentPerDay(uint256 _day) public view returns(uint256) {
|
||||
return uintStorage[keccak256("totalSpentPerDay", _day)];
|
||||
}
|
||||
|
||||
function deployedAtBlock() public view returns(uint256) {
|
||||
return uintStorage[keccak256("deployedAtBlock")];
|
||||
}
|
||||
|
||||
function gasLimitDepositRelay() public view returns(uint256) {
|
||||
return uintStorage[keccak256("gasLimitDepositRelay")];
|
||||
}
|
||||
|
||||
function gasLimitWithdrawConfirm() public view returns(uint256) {
|
||||
return uintStorage[keccak256("gasLimitWithdrawConfirm")];
|
||||
}
|
||||
|
||||
function foreignDailyLimit() public view returns(uint256) {
|
||||
return uintStorage[keccak256("foreignDailyLimit")];
|
||||
}
|
||||
|
||||
function erc677token() public view returns(IBurnableMintableERC677Token) {
|
||||
return IBurnableMintableERC677Token(addressStorage[keccak256("erc677token")]);
|
||||
}
|
||||
|
||||
function setGasLimits(uint256 _gasLimitDepositRelay, uint256 _gasLimitWithdrawConfirm) public onlyOwner {
|
||||
uintStorage[keccak256("gasLimitDepositRelay")] = _gasLimitDepositRelay;
|
||||
uintStorage[keccak256("gasLimitWithdrawConfirm")] = _gasLimitWithdrawConfirm;
|
||||
GasConsumptionLimitsUpdated(gasLimitDepositRelay(), gasLimitWithdrawConfirm());
|
||||
}
|
||||
|
||||
function deposit(address recipient, uint value, bytes32 transactionHash) public onlyValidator {
|
||||
require(address(erc677token()) != address(0x0));
|
||||
|
||||
// Protection from misbehaing authority
|
||||
bytes32 hashMsg = keccak256(recipient, value, transactionHash);
|
||||
bytes32 hashSender = keccak256(msg.sender, hashMsg);
|
||||
|
||||
// Duplicated deposits
|
||||
require(!depositsSigned(hashSender));
|
||||
setDepositsSigned(hashSender, true);
|
||||
|
||||
uint256 signed = numDepositsSigned(hashMsg).add(1);
|
||||
setNumDepositsSigned(hashMsg, signed);
|
||||
|
||||
SignedForDeposit(msg.sender, transactionHash);
|
||||
|
||||
if (signed == validatorContract().requiredSignatures()) {
|
||||
// If the bridge contract does not own enough tokens to transfer
|
||||
// it will couse funds lock on the home side of the bridge
|
||||
erc677token().mint(recipient, value);
|
||||
Deposit(recipient, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Should be used as sync tool
|
||||
///
|
||||
/// Message is a message that should be relayed to main chain once authorities sign it.
|
||||
///
|
||||
/// for withdraw message contains:
|
||||
/// withdrawal recipient (bytes20)
|
||||
/// withdrawal value (uint)
|
||||
/// foreign transaction hash (bytes32) // to avoid transaction duplication
|
||||
function submitSignature(bytes signature, bytes message) public onlyValidator {
|
||||
// ensure that `signature` is really `message` signed by `msg.sender`
|
||||
require(msg.sender == MessageSigning.recoverAddressFromSignedMessage(signature, message));
|
||||
|
||||
require(message.length == 116);
|
||||
bytes32 hash = keccak256(message);
|
||||
bytes32 hashSender = keccak256(msg.sender, hash);
|
||||
|
||||
uint signed = numMessagesSigned(hashSender) + 1;
|
||||
|
||||
if (signed > 1) {
|
||||
// Duplicated signatures
|
||||
require(!messagesSigned(hashSender));
|
||||
} else {
|
||||
// check if it will really reduce gas usage in case of the second transaction
|
||||
// with the same hash
|
||||
setMessages(hash, message);
|
||||
}
|
||||
setMessagesSigned(hashSender, true);
|
||||
|
||||
bytes32 signIdx = keccak256(hash, (signed-1));
|
||||
setSignatures(signIdx, signature);
|
||||
|
||||
setNumMessagesSigned(hashSender, signed);
|
||||
|
||||
SignedForWithdraw(msg.sender, hash);
|
||||
if (signed == validatorContract().requiredSignatures()) {
|
||||
CollectedSignatures(msg.sender, hash);
|
||||
}
|
||||
}
|
||||
|
||||
function signature(bytes32 _hash, uint256 _index) public view returns (bytes) {
|
||||
bytes32 signIdx = keccak256(_hash, _index);
|
||||
return signatures(signIdx);
|
||||
}
|
||||
|
||||
/// Get message
|
||||
function message(bytes32 _hash) public view returns (bytes) {
|
||||
return messages(_hash);
|
||||
}
|
||||
|
||||
function getCurrentDay() public view returns(uint256) {
|
||||
return now / 1 days;
|
||||
}
|
||||
|
||||
function setForeignDailyLimit(uint256 _foreignDailyLimit) public onlyOwner {
|
||||
require(_foreignDailyLimit > 0);
|
||||
uintStorage[keccak256("foreignDailyLimit")] = _foreignDailyLimit;
|
||||
DailyLimit(_foreignDailyLimit);
|
||||
}
|
||||
|
||||
function withinLimit(uint256 _amount) public view returns(bool) {
|
||||
uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount);
|
||||
return foreignDailyLimit() >= nextLimit;
|
||||
}
|
||||
|
||||
function isInitialized() public view returns(bool) {
|
||||
return boolStorage[keccak256("isInitialized")];
|
||||
}
|
||||
|
||||
function homeGasPrice() internal view returns(uint256) {
|
||||
return 1000000000 wei;
|
||||
}
|
||||
|
||||
function messages(bytes32 _hash) private view returns(bytes) {
|
||||
return bytesStorage[keccak256("messages", _hash)];
|
||||
}
|
||||
|
||||
function setMessages(bytes32 _hash, bytes _message) private {
|
||||
bytesStorage[keccak256("messages", _hash)] = _message;
|
||||
}
|
||||
|
||||
function signatures(bytes32 _hash) private view returns(bytes) {
|
||||
return bytesStorage[keccak256("signatures", _hash)];
|
||||
}
|
||||
|
||||
function setSignatures(bytes32 _hash, bytes _signature) private {
|
||||
bytesStorage[keccak256("signatures", _hash)] = _signature;
|
||||
}
|
||||
|
||||
function messagesSigned(bytes32 _message) private view returns(bool) {
|
||||
return boolStorage[keccak256("messagesSigned", _message)];
|
||||
}
|
||||
|
||||
function depositsSigned(bytes32 _deposit) private view returns(bool) {
|
||||
return boolStorage[keccak256("depositsSigned", _deposit)];
|
||||
}
|
||||
|
||||
function numMessagesSigned(bytes32 _message) private view returns(uint256) {
|
||||
return uintStorage[keccak256("numMessagesSigned", _message)];
|
||||
}
|
||||
|
||||
function numDepositsSigned(bytes32 _deposit) private view returns(uint256) {
|
||||
return uintStorage[keccak256("numDepositsSigned", _deposit)];
|
||||
}
|
||||
|
||||
function setMessagesSigned(bytes32 _hash, bool _status) private {
|
||||
boolStorage[keccak256("messagesSigned", _hash)] = _status;
|
||||
}
|
||||
|
||||
function setDepositsSigned(bytes32 _deposit, bool _status) private {
|
||||
boolStorage[keccak256("depositsSigned", _deposit)] = _status;
|
||||
}
|
||||
|
||||
function setNumMessagesSigned(bytes32 _message, uint256 _number) private {
|
||||
uintStorage[keccak256("numMessagesSigned", _message)] = _number;
|
||||
}
|
||||
|
||||
function setNumDepositsSigned(bytes32 _deposit, uint256 _number) private {
|
||||
uintStorage[keccak256("numDepositsSigned", _deposit)] = _number;
|
||||
}
|
||||
|
||||
function setTotalSpentPerDay(uint256 _day, uint256 _value) private {
|
||||
uintStorage[keccak256("totalSpentPerDay", _day)] = _value;
|
||||
}
|
||||
|
||||
function setErc677token(address _token) private {
|
||||
require(_token != address(0));
|
||||
addressStorage[keccak256("erc677token")] = _token;
|
||||
}
|
||||
|
||||
function setInitialize(bool _status) private {
|
||||
boolStorage[keccak256("isInitialized")] = _status;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
pragma solidity ^0.4.19;
|
||||
import "../libraries/SafeMath.sol";
|
||||
import "../libraries/Helpers.sol";
|
||||
import "../libraries/Message.sol";
|
||||
// import "./IBridgeValidators.sol";
|
||||
// import "./Validatable.sol";
|
||||
// import "./BridgeDeploymentAddressStorage.sol";
|
||||
import "./U_Validatable.sol";
|
||||
import "../upgradeability/OwnedUpgradeabilityStorage.sol";
|
||||
|
||||
|
||||
contract HomeBridge is OwnedUpgradeabilityStorage, Validatable {
|
||||
using SafeMath for uint256;
|
||||
event GasConsumptionLimitsUpdated(uint256 gas);
|
||||
event Deposit (address recipient, uint256 value);
|
||||
event Withdraw (address recipient, uint256 value);
|
||||
event DailyLimit(uint256 newLimit);
|
||||
|
||||
function initialize (
|
||||
address _validatorContract,
|
||||
uint256 _homeDailyLimit
|
||||
) public {
|
||||
require(!isInitialized());
|
||||
require(_validatorContract != address(0));
|
||||
require(_homeDailyLimit > 0);
|
||||
addressStorage[keccak256("validatorContract")] = _validatorContract;
|
||||
uintStorage[keccak256("deployedAtBlock")] = block.number;
|
||||
setHomeDailyLimit(_homeDailyLimit);
|
||||
setInitialize(true);
|
||||
}
|
||||
|
||||
function () public payable {
|
||||
require(msg.value > 0);
|
||||
require(withinLimit(msg.value));
|
||||
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(msg.value));
|
||||
Deposit(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
function gasLimitWithdrawRelay() public view returns(uint256) {
|
||||
return uintStorage[keccak256("gasLimitWithdrawRelay")];
|
||||
}
|
||||
|
||||
function deployedAtBlock() public view returns(uint256) {
|
||||
return uintStorage[keccak256("deployedAtBlock")];
|
||||
}
|
||||
|
||||
function homeDailyLimit() public view returns(uint256) {
|
||||
return uintStorage[keccak256("homeDailyLimit")];
|
||||
}
|
||||
|
||||
function totalSpentPerDay(uint256 _day) public view returns(uint256) {
|
||||
return uintStorage[keccak256("totalSpentPerDay", _day)];
|
||||
}
|
||||
|
||||
function withdraws(bytes32 _withdraw) public view returns(bool) {
|
||||
return boolStorage[keccak256("withdraws", _withdraw)];
|
||||
}
|
||||
|
||||
function setGasLimitWithdrawRelay(uint256 _gas) public onlyOwner {
|
||||
uintStorage[keccak256("gasLimitWithdrawRelay")] = _gas;
|
||||
GasConsumptionLimitsUpdated(_gas);
|
||||
}
|
||||
|
||||
function withdraw(uint8[] vs, bytes32[] rs, bytes32[] ss, bytes message) public {
|
||||
require(message.length == 116);
|
||||
require(Helpers.hasEnoughValidSignatures(message, vs, rs, ss, validatorContract()));
|
||||
|
||||
address recipient = Message.getRecipient(message);
|
||||
uint256 value = Message.getValue(message);
|
||||
bytes32 hash = Message.getTransactionHash(message);
|
||||
require(!withdraws(hash));
|
||||
// Order of operations below is critical to avoid TheDAO-like re-entry bug
|
||||
setWithdraws(hash, true);
|
||||
|
||||
// pay out recipient
|
||||
recipient.transfer(value);
|
||||
|
||||
Withdraw(recipient, value);
|
||||
}
|
||||
|
||||
function setHomeDailyLimit(uint256 _homeDailyLimit) public onlyOwner {
|
||||
uintStorage[keccak256("homeDailyLimit")] = _homeDailyLimit;
|
||||
DailyLimit(_homeDailyLimit);
|
||||
}
|
||||
|
||||
function getCurrentDay() public view returns(uint256) {
|
||||
return now / 1 days;
|
||||
}
|
||||
|
||||
function withinLimit(uint256 _amount) public view returns(bool) {
|
||||
uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount);
|
||||
return homeDailyLimit() >= nextLimit;
|
||||
}
|
||||
|
||||
function isInitialized() public view returns(bool) {
|
||||
return boolStorage[keccak256("isInitialized")];
|
||||
}
|
||||
|
||||
function setTotalSpentPerDay(uint256 _day, uint256 _value) private {
|
||||
uintStorage[keccak256("totalSpentPerDay", _day)] = _value;
|
||||
}
|
||||
|
||||
function setWithdraws(bytes32 _withdraw, bool _status) private {
|
||||
boolStorage[keccak256("withdraws", _withdraw)] = _status;
|
||||
}
|
||||
|
||||
function setInitialize(bool _status) private {
|
||||
boolStorage[keccak256("isInitialized")] = _status;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
pragma solidity ^0.4.19;
|
||||
import "../IBridgeValidators.sol";
|
||||
import "../upgradeability/OwnedUpgradeabilityStorage.sol";
|
||||
|
||||
|
||||
contract Validatable is OwnedUpgradeabilityStorage {
|
||||
|
||||
function validatorContract() public view returns(IBridgeValidators) {
|
||||
return IBridgeValidators(addressStorage[keccak256("validatorContract")]);
|
||||
}
|
||||
|
||||
modifier onlyValidator() {
|
||||
require(validatorContract().isValidator(msg.sender));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(validatorContract().owner() == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,107 +1,265 @@
|
|||
pragma solidity ^0.4.19;
|
||||
pragma solidity 0.4.19;
|
||||
|
||||
// File: contracts/IBridgeValidators.sol
|
||||
|
||||
interface IBridgeValidators {
|
||||
function isValidator(address _validator) public view returns(bool);
|
||||
function requiredSignatures() public view returns(uint8);
|
||||
function currentOwner() public view returns(address);
|
||||
function requiredSignatures() public view returns(uint256);
|
||||
function owner() public view returns(address);
|
||||
}
|
||||
|
||||
// File: zeppelin-solidity/contracts/ownership/Ownable.sol
|
||||
// File: contracts/libraries/SafeMath.sol
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint256 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 c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Substracts 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) {
|
||||
uint256 c = a + b;
|
||||
assert(c >= a);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/upgradeability/EternalStorage.sol
|
||||
|
||||
/**
|
||||
* @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/upgradeability/UpgradeabilityOwnerStorage.sol
|
||||
|
||||
/**
|
||||
* @title UpgradeabilityOwnerStorage
|
||||
* @dev This contract keeps track of the upgradeability owner
|
||||
*/
|
||||
contract UpgradeabilityOwnerStorage {
|
||||
// Owner of the contract
|
||||
address private _upgradeabilityOwner;
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the owner
|
||||
* @return the address of the owner
|
||||
*/
|
||||
function upgradeabilityOwner() public view returns (address) {
|
||||
return _upgradeabilityOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the address of the owner
|
||||
*/
|
||||
function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
|
||||
_upgradeabilityOwner = newUpgradeabilityOwner;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/upgradeability/UpgradeabilityStorage.sol
|
||||
|
||||
/**
|
||||
* @title UpgradeabilityStorage
|
||||
* @dev This contract holds all the necessary state variables to support the upgrade functionality
|
||||
*/
|
||||
contract UpgradeabilityStorage {
|
||||
// Version name of the current implementation
|
||||
string internal _version;
|
||||
|
||||
// Address of the current implementation
|
||||
address internal _implementation;
|
||||
|
||||
/**
|
||||
* @dev Tells the version name of the current implementation
|
||||
* @return string representing the name of the current version
|
||||
*/
|
||||
function version() public view returns (string) {
|
||||
return _version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the current implementation
|
||||
* @return address of the current implementation
|
||||
*/
|
||||
function implementation() public view returns (address) {
|
||||
return _implementation;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/upgradeability/OwnedUpgradeabilityStorage.sol
|
||||
|
||||
/**
|
||||
* @title OwnedUpgradeabilityStorage
|
||||
* @dev This is the storage necessary to perform upgradeable contracts.
|
||||
* This means, required state variables for upgradeability purpose and eternal storage per se.
|
||||
*/
|
||||
contract OwnedUpgradeabilityStorage is UpgradeabilityOwnerStorage, UpgradeabilityStorage, EternalStorage {}
|
||||
|
||||
// File: contracts/upgradeable_contracts/Ownable.sol
|
||||
|
||||
// Roman Storm Multi Sender
|
||||
// To Use this Dapp: https://poanetwork.github.io/multisender
|
||||
pragma solidity 0.4.19;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @title Ownable
|
||||
* @dev The Ownable contract has an owner address, and provides basic authorization control
|
||||
* functions, this simplifies the implementation of "user permissions".
|
||||
* @dev This contract has an owner address providing basic authorization control
|
||||
*/
|
||||
contract Ownable {
|
||||
address public owner;
|
||||
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());
|
||||
_;
|
||||
}
|
||||
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
||||
/**
|
||||
* @dev Tells the address of the owner
|
||||
* @return the address of the owner
|
||||
*/
|
||||
function owner() public view returns (address) {
|
||||
return addressStorage[keccak256("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) public onlyOwner {
|
||||
require(newOwner != address(0));
|
||||
setOwner(newOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
|
||||
* account.
|
||||
*/
|
||||
function Ownable() public {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Throws if called by any account other than the owner.
|
||||
*/
|
||||
modifier onlyOwner() {
|
||||
require(msg.sender == 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) public onlyOwner {
|
||||
require(newOwner != address(0));
|
||||
OwnershipTransferred(owner, newOwner);
|
||||
owner = newOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets a new owner address
|
||||
*/
|
||||
function setOwner(address newOwner) internal {
|
||||
OwnershipTransferred(owner(), newOwner);
|
||||
addressStorage[keccak256("owner")] = newOwner;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/BridgeValidators.sol
|
||||
// File: contracts/upgradeable_contracts/U_BridgeValidators.sol
|
||||
|
||||
contract BridgeValidators is Ownable, IBridgeValidators {
|
||||
|
||||
// Event created on validator gets added
|
||||
contract BridgeValidators is IBridgeValidators, Ownable, OwnedUpgradeabilityStorage {
|
||||
using SafeMath for uint256;
|
||||
event ValidatorAdded (address validator);
|
||||
event ValidatorRemoved (address validator);
|
||||
uint8 requiredValidators = 0;
|
||||
uint256 public validatorCount = 0;
|
||||
|
||||
mapping (address => bool) public validators;
|
||||
|
||||
function BridgeValidators(uint8 _requiredValidators, address[] _initialValidators) public Ownable() {
|
||||
require(_requiredValidators != 0);
|
||||
require(_initialValidators.length >= _requiredValidators);
|
||||
validatorCount = _initialValidators.length;
|
||||
function initialize(uint256 _requiredSignatures, address[] _initialValidators, address _owner) public {
|
||||
require(!isInitialized());
|
||||
setOwner(_owner);
|
||||
require(_requiredSignatures != 0);
|
||||
require(_initialValidators.length >= _requiredSignatures);
|
||||
for (uint i = 0; i < _initialValidators.length; i++) {
|
||||
require(!isValidator(_initialValidators[i]) && _initialValidators[i] != address(0));
|
||||
addValidator(_initialValidators[i]);
|
||||
}
|
||||
setRequiredValidators(_requiredValidators);
|
||||
setRequiredSignatures(_requiredSignatures);
|
||||
setInitialize(true);
|
||||
}
|
||||
|
||||
function addValidator(address _validator) public onlyOwner {
|
||||
assert(validators[_validator] != true);
|
||||
validatorCount++;
|
||||
validators[_validator] = true;
|
||||
function addValidator(address _validator) public onlyOwner {
|
||||
assert(validators(_validator) != true);
|
||||
setValidatorCount(validatorCount().add(1));
|
||||
setValidator(_validator, true);
|
||||
ValidatorAdded(_validator);
|
||||
}
|
||||
|
||||
function removeValidator(address _validator) public onlyOwner {
|
||||
require(validatorCount > requiredValidators);
|
||||
validators[_validator] = false;
|
||||
validatorCount--;
|
||||
require(validatorCount() > requiredSignatures());
|
||||
setValidator(_validator, false);
|
||||
setValidatorCount(validatorCount().sub(1));
|
||||
ValidatorRemoved(_validator);
|
||||
}
|
||||
|
||||
function setRequiredValidators(uint8 _requiredValidators) public onlyOwner {
|
||||
require(validatorCount >= _requiredValidators);
|
||||
requiredValidators = _requiredValidators;
|
||||
function setRequiredSignatures(uint256 _requiredSignatures) public onlyOwner {
|
||||
require(validatorCount() >= _requiredSignatures);
|
||||
uintStorage[keccak256("requiredSignatures")] = _requiredSignatures;
|
||||
}
|
||||
|
||||
function requiredSignatures() public view returns(uint256) {
|
||||
return uintStorage[keccak256("requiredSignatures")];
|
||||
}
|
||||
|
||||
function validatorCount() public view returns(uint256) {
|
||||
return uintStorage[keccak256("validatorCount")];
|
||||
}
|
||||
|
||||
function validators(address _validator) public view returns(bool) {
|
||||
return boolStorage[keccak256("validators", _validator)];
|
||||
}
|
||||
|
||||
function isValidator(address _validator) public view returns(bool) {
|
||||
return validators[_validator] == true;
|
||||
return validators(_validator) == true;
|
||||
}
|
||||
|
||||
function requiredSignatures() public view returns(uint8) {
|
||||
return requiredValidators;
|
||||
function isInitialized() public view returns(bool) {
|
||||
return boolStorage[keccak256("isInitialized")];
|
||||
}
|
||||
|
||||
function currentOwner() public view returns(address) {
|
||||
return owner;
|
||||
function setValidatorCount(uint256 _validatorCount) private {
|
||||
uintStorage[keccak256("validatorCount")] = _validatorCount;
|
||||
}
|
||||
|
||||
function setValidator(address _validator, bool _status) private {
|
||||
boolStorage[keccak256("validators", _validator)] = _status;
|
||||
}
|
||||
|
||||
function setInitialize(bool _status) private {
|
||||
boolStorage[keccak256("isInitialized")] = _status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,11 @@
|
|||
pragma solidity 0.4.19;
|
||||
|
||||
// File: contracts/BridgeDeploymentAddressStorage.sol
|
||||
|
||||
contract BridgeDeploymentAddressStorage {
|
||||
uint256 public deployedAtBlock;
|
||||
|
||||
function BridgeDeploymentAddressStorage() public {
|
||||
deployedAtBlock = block.number;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/ERC677Receiver.sol
|
||||
|
||||
contract ERC677Receiver {
|
||||
function onTokenTransfer(address _from, uint _value, bytes _data) external returns(bool);
|
||||
}
|
||||
|
||||
// File: contracts/IBridgeValidators.sol
|
||||
|
||||
interface IBridgeValidators {
|
||||
function isValidator(address _validator) public view returns(bool);
|
||||
function requiredSignatures() public view returns(uint8);
|
||||
function currentOwner() public view returns(address);
|
||||
}
|
||||
|
||||
// File: zeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
|
||||
|
||||
/**
|
||||
|
@ -67,25 +49,12 @@ contract IBurnableMintableERC677Token is ERC677 {
|
|||
function burn(uint256 _value) public;
|
||||
}
|
||||
|
||||
// File: contracts/Validatable.sol
|
||||
// File: contracts/IBridgeValidators.sol
|
||||
|
||||
contract Validatable {
|
||||
IBridgeValidators public validatorContract;
|
||||
|
||||
modifier onlyValidator() {
|
||||
require(validatorContract.isValidator(msg.sender));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(validatorContract.currentOwner() == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
||||
function Validatable(address _validatorContract) public {
|
||||
require(_validatorContract != address(0));
|
||||
validatorContract = IBridgeValidators(_validatorContract);
|
||||
}
|
||||
interface IBridgeValidators {
|
||||
function isValidator(address _validator) public view returns(bool);
|
||||
function requiredSignatures() public view returns(uint256);
|
||||
function owner() public view returns(address);
|
||||
}
|
||||
|
||||
// File: contracts/libraries/Helpers.sol
|
||||
|
@ -126,7 +95,7 @@ library Helpers {
|
|||
bytes32[] _rs,
|
||||
bytes32[] _ss,
|
||||
IBridgeValidators _validatorContract) internal view returns (bool) {
|
||||
uint8 requiredSignatures = _validatorContract.requiredSignatures();
|
||||
uint256 requiredSignatures = _validatorContract.requiredSignatures();
|
||||
require(_vs.length >= requiredSignatures);
|
||||
bytes32 hash = MessageSigning.hashMessage(_message);
|
||||
address[] memory encounteredAddresses = new address[](requiredSignatures);
|
||||
|
@ -262,24 +231,119 @@ library SafeMath {
|
|||
}
|
||||
}
|
||||
|
||||
// File: contracts/ForeignBridge.sol
|
||||
// File: contracts/upgradeability/EternalStorage.sol
|
||||
|
||||
contract ForeignBridge is ERC677Receiver, Validatable, BridgeDeploymentAddressStorage {
|
||||
/**
|
||||
* @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/upgradeability/UpgradeabilityOwnerStorage.sol
|
||||
|
||||
/**
|
||||
* @title UpgradeabilityOwnerStorage
|
||||
* @dev This contract keeps track of the upgradeability owner
|
||||
*/
|
||||
contract UpgradeabilityOwnerStorage {
|
||||
// Owner of the contract
|
||||
address private _upgradeabilityOwner;
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the owner
|
||||
* @return the address of the owner
|
||||
*/
|
||||
function upgradeabilityOwner() public view returns (address) {
|
||||
return _upgradeabilityOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the address of the owner
|
||||
*/
|
||||
function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
|
||||
_upgradeabilityOwner = newUpgradeabilityOwner;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/upgradeability/UpgradeabilityStorage.sol
|
||||
|
||||
/**
|
||||
* @title UpgradeabilityStorage
|
||||
* @dev This contract holds all the necessary state variables to support the upgrade functionality
|
||||
*/
|
||||
contract UpgradeabilityStorage {
|
||||
// Version name of the current implementation
|
||||
string internal _version;
|
||||
|
||||
// Address of the current implementation
|
||||
address internal _implementation;
|
||||
|
||||
/**
|
||||
* @dev Tells the version name of the current implementation
|
||||
* @return string representing the name of the current version
|
||||
*/
|
||||
function version() public view returns (string) {
|
||||
return _version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the current implementation
|
||||
* @return address of the current implementation
|
||||
*/
|
||||
function implementation() public view returns (address) {
|
||||
return _implementation;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/upgradeability/OwnedUpgradeabilityStorage.sol
|
||||
|
||||
/**
|
||||
* @title OwnedUpgradeabilityStorage
|
||||
* @dev This is the storage necessary to perform upgradeable contracts.
|
||||
* This means, required state variables for upgradeability purpose and eternal storage per se.
|
||||
*/
|
||||
contract OwnedUpgradeabilityStorage is UpgradeabilityOwnerStorage, UpgradeabilityStorage, EternalStorage {}
|
||||
|
||||
// File: contracts/upgradeable_contracts/U_Validatable.sol
|
||||
|
||||
contract Validatable is OwnedUpgradeabilityStorage {
|
||||
|
||||
function validatorContract() public view returns(IBridgeValidators) {
|
||||
return IBridgeValidators(addressStorage[keccak256("validatorContract")]);
|
||||
}
|
||||
|
||||
modifier onlyValidator() {
|
||||
require(validatorContract().isValidator(msg.sender));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(validatorContract().owner() == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// File: contracts/upgradeable_contracts/U_ForeignBridge.sol
|
||||
|
||||
// import "./IBridgeValidators.sol";
|
||||
|
||||
// import "./BridgeDeploymentAddressStorage.sol";
|
||||
|
||||
|
||||
|
||||
|
||||
contract ForeignBridge is ERC677Receiver, Validatable {
|
||||
using SafeMath for uint256;
|
||||
uint256 public gasLimitDepositRelay;
|
||||
uint256 public gasLimitWithdrawConfirm;
|
||||
uint256 homeGasPrice = 1000000000 wei;
|
||||
uint256 public foreignDailyLimit;
|
||||
mapping (bytes32 => bytes) messages;
|
||||
mapping (bytes32 => bytes) signatures;
|
||||
mapping (bytes32 => bool) messages_signed;
|
||||
mapping (bytes32 => uint256) num_messages_signed;
|
||||
mapping (bytes32 => bool) deposits_signed;
|
||||
mapping (bytes32 => uint256) num_deposits_signed;
|
||||
mapping (uint256 => uint256) totalSpentPerDay;
|
||||
|
||||
IBurnableMintableERC677Token public erc677token;
|
||||
|
||||
/// triggered when relay of deposit from HomeBridge is complete
|
||||
event Deposit(address recipient, uint value);
|
||||
|
||||
|
@ -295,63 +359,85 @@ contract ForeignBridge is ERC677Receiver, Validatable, BridgeDeploymentAddressSt
|
|||
event SignedForWithdraw(address indexed signer, bytes32 message);
|
||||
event DailyLimit(uint256 newLimit);
|
||||
|
||||
function ForeignBridge(
|
||||
function initialize(
|
||||
address _validatorContract,
|
||||
address _erc677token,
|
||||
uint256 _foreignDailyLimit
|
||||
) public Validatable(_validatorContract) {
|
||||
) public {
|
||||
require(!isInitialized());
|
||||
require(_validatorContract != address(0));
|
||||
require(_foreignDailyLimit > 0);
|
||||
erc677token = IBurnableMintableERC677Token(_erc677token);
|
||||
foreignDailyLimit = _foreignDailyLimit;
|
||||
}
|
||||
|
||||
function setGasLimitDepositRelay(uint256 _gas) public onlyOwner {
|
||||
gasLimitDepositRelay = _gas;
|
||||
|
||||
GasConsumptionLimitsUpdated(gasLimitDepositRelay, gasLimitWithdrawConfirm);
|
||||
}
|
||||
|
||||
function setGasLimitWithdrawConfirm(uint256 gas) public onlyOwner {
|
||||
gasLimitWithdrawConfirm = gas;
|
||||
|
||||
GasConsumptionLimitsUpdated(gasLimitDepositRelay, gasLimitWithdrawConfirm);
|
||||
}
|
||||
|
||||
function deposit(address recipient, uint value, bytes32 transactionHash) public onlyValidator {
|
||||
require(erc677token != address(0x0));
|
||||
|
||||
// Protection from misbehaing authority
|
||||
bytes32 hash_msg = keccak256(recipient, value, transactionHash);
|
||||
bytes32 hash_sender = keccak256(msg.sender, hash_msg);
|
||||
|
||||
// Duplicated deposits
|
||||
require(!deposits_signed[hash_sender]);
|
||||
deposits_signed[hash_sender] = true;
|
||||
|
||||
uint256 signed = num_deposits_signed[hash_msg] + 1;
|
||||
num_deposits_signed[hash_msg] = signed;
|
||||
|
||||
SignedForDeposit(msg.sender, transactionHash);
|
||||
|
||||
if (signed == validatorContract.requiredSignatures()) {
|
||||
// If the bridge contract does not own enough tokens to transfer
|
||||
// it will couse funds lock on the home side of the bridge
|
||||
erc677token.mint(recipient, value);
|
||||
Deposit(recipient, value);
|
||||
}
|
||||
|
||||
addressStorage[keccak256("validatorContract")] = _validatorContract;
|
||||
setErc677token(_erc677token);
|
||||
setForeignDailyLimit(_foreignDailyLimit);
|
||||
uintStorage[keccak256("deployedAtBlock")] = block.number;
|
||||
setInitialize(true);
|
||||
}
|
||||
|
||||
function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns(bool) {
|
||||
require(erc677token != address(0x0));
|
||||
require(msg.sender == address(erc677token));
|
||||
require(address(erc677token()) != address(0x0));
|
||||
require(msg.sender == address(erc677token()));
|
||||
require(withinLimit(_value));
|
||||
totalSpentPerDay[getCurrentDay()] = totalSpentPerDay[getCurrentDay()].add(_value);
|
||||
erc677token.burn(_value);
|
||||
Withdraw(_from, _value, homeGasPrice);
|
||||
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(_value));
|
||||
erc677token().burn(_value);
|
||||
Withdraw(_from, _value, homeGasPrice());
|
||||
return true;
|
||||
}
|
||||
|
||||
function totalSpentPerDay(uint256 _day) public view returns(uint256) {
|
||||
return uintStorage[keccak256("totalSpentPerDay", _day)];
|
||||
}
|
||||
|
||||
function deployedAtBlock() public view returns(uint256) {
|
||||
return uintStorage[keccak256("deployedAtBlock")];
|
||||
}
|
||||
|
||||
function gasLimitDepositRelay() public view returns(uint256) {
|
||||
return uintStorage[keccak256("gasLimitDepositRelay")];
|
||||
}
|
||||
|
||||
function gasLimitWithdrawConfirm() public view returns(uint256) {
|
||||
return uintStorage[keccak256("gasLimitWithdrawConfirm")];
|
||||
}
|
||||
|
||||
function foreignDailyLimit() public view returns(uint256) {
|
||||
return uintStorage[keccak256("foreignDailyLimit")];
|
||||
}
|
||||
|
||||
function erc677token() public view returns(IBurnableMintableERC677Token) {
|
||||
return IBurnableMintableERC677Token(addressStorage[keccak256("erc677token")]);
|
||||
}
|
||||
|
||||
function setGasLimits(uint256 _gasLimitDepositRelay, uint256 _gasLimitWithdrawConfirm) public onlyOwner {
|
||||
uintStorage[keccak256("gasLimitDepositRelay")] = _gasLimitDepositRelay;
|
||||
uintStorage[keccak256("gasLimitWithdrawConfirm")] = _gasLimitWithdrawConfirm;
|
||||
GasConsumptionLimitsUpdated(gasLimitDepositRelay(), gasLimitWithdrawConfirm());
|
||||
}
|
||||
|
||||
function deposit(address recipient, uint value, bytes32 transactionHash) public onlyValidator {
|
||||
require(address(erc677token()) != address(0x0));
|
||||
|
||||
// Protection from misbehaing authority
|
||||
bytes32 hashMsg = keccak256(recipient, value, transactionHash);
|
||||
bytes32 hashSender = keccak256(msg.sender, hashMsg);
|
||||
|
||||
// Duplicated deposits
|
||||
require(!depositsSigned(hashSender));
|
||||
setDepositsSigned(hashSender, true);
|
||||
|
||||
uint256 signed = numDepositsSigned(hashMsg).add(1);
|
||||
setNumDepositsSigned(hashMsg, signed);
|
||||
|
||||
SignedForDeposit(msg.sender, transactionHash);
|
||||
|
||||
if (signed == validatorContract().requiredSignatures()) {
|
||||
// If the bridge contract does not own enough tokens to transfer
|
||||
// it will couse funds lock on the home side of the bridge
|
||||
erc677token().mint(recipient, value);
|
||||
Deposit(recipient, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Should be used as sync tool
|
||||
///
|
||||
/// Message is a message that should be relayed to main chain once authorities sign it.
|
||||
|
@ -366,56 +452,123 @@ contract ForeignBridge is ERC677Receiver, Validatable, BridgeDeploymentAddressSt
|
|||
|
||||
require(message.length == 116);
|
||||
bytes32 hash = keccak256(message);
|
||||
bytes32 hash_sender = keccak256(msg.sender, hash);
|
||||
bytes32 hashSender = keccak256(msg.sender, hash);
|
||||
|
||||
uint signed = num_messages_signed[hash_sender] + 1;
|
||||
uint signed = numMessagesSigned(hashSender) + 1;
|
||||
|
||||
if (signed > 1) {
|
||||
// Duplicated signatures
|
||||
require(!messages_signed[hash_sender]);
|
||||
}
|
||||
else {
|
||||
require(!messagesSigned(hashSender));
|
||||
} else {
|
||||
// check if it will really reduce gas usage in case of the second transaction
|
||||
// with the same hash
|
||||
messages[hash] = message;
|
||||
setMessages(hash, message);
|
||||
}
|
||||
messages_signed[hash_sender] = true;
|
||||
setMessagesSigned(hashSender, true);
|
||||
|
||||
bytes32 sign_idx = keccak256(hash, (signed-1));
|
||||
signatures[sign_idx] = signature;
|
||||
bytes32 signIdx = keccak256(hash, (signed-1));
|
||||
setSignatures(signIdx, signature);
|
||||
|
||||
num_messages_signed[hash_sender] = signed;
|
||||
setNumMessagesSigned(hashSender, signed);
|
||||
|
||||
// TODO: this may cause troubles if requiredSignatures len is changed
|
||||
SignedForWithdraw(msg.sender, hash);
|
||||
if (signed == validatorContract.requiredSignatures()) {
|
||||
if (signed == validatorContract().requiredSignatures()) {
|
||||
CollectedSignatures(msg.sender, hash);
|
||||
}
|
||||
}
|
||||
|
||||
function signature(bytes32 hash, uint index) public view returns (bytes) {
|
||||
bytes32 sign_idx = keccak256(hash, index);
|
||||
return signatures[sign_idx];
|
||||
function signature(bytes32 _hash, uint256 _index) public view returns (bytes) {
|
||||
bytes32 signIdx = keccak256(_hash, _index);
|
||||
return signatures(signIdx);
|
||||
}
|
||||
|
||||
/// Get message
|
||||
function message(bytes32 hash) public view returns (bytes) {
|
||||
return messages[hash];
|
||||
function message(bytes32 _hash) public view returns (bytes) {
|
||||
return messages(_hash);
|
||||
}
|
||||
|
||||
function getCurrentDay() public view returns(uint256) {
|
||||
return now / 1 days;
|
||||
}
|
||||
|
||||
function setDailyLimit(uint256 _foreignDailyLimit) public onlyOwner {
|
||||
function setForeignDailyLimit(uint256 _foreignDailyLimit) public onlyOwner {
|
||||
require(_foreignDailyLimit > 0);
|
||||
foreignDailyLimit = _foreignDailyLimit;
|
||||
DailyLimit(foreignDailyLimit);
|
||||
uintStorage[keccak256("foreignDailyLimit")] = _foreignDailyLimit;
|
||||
DailyLimit(_foreignDailyLimit);
|
||||
}
|
||||
|
||||
function withinLimit(uint256 _amount) public view returns(bool) {
|
||||
uint256 nextLimit = totalSpentPerDay[getCurrentDay()].add(_amount);
|
||||
return foreignDailyLimit >= nextLimit;
|
||||
uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount);
|
||||
return foreignDailyLimit() >= nextLimit;
|
||||
}
|
||||
|
||||
function isInitialized() public view returns(bool) {
|
||||
return boolStorage[keccak256("isInitialized")];
|
||||
}
|
||||
|
||||
function homeGasPrice() internal view returns(uint256) {
|
||||
return 1000000000 wei;
|
||||
}
|
||||
|
||||
function messages(bytes32 _hash) private view returns(bytes) {
|
||||
return bytesStorage[keccak256("messages", _hash)];
|
||||
}
|
||||
|
||||
function setMessages(bytes32 _hash, bytes _message) private {
|
||||
bytesStorage[keccak256("messages", _hash)] = _message;
|
||||
}
|
||||
|
||||
function signatures(bytes32 _hash) private view returns(bytes) {
|
||||
return bytesStorage[keccak256("signatures", _hash)];
|
||||
}
|
||||
|
||||
function setSignatures(bytes32 _hash, bytes _signature) private {
|
||||
bytesStorage[keccak256("signatures", _hash)] = _signature;
|
||||
}
|
||||
|
||||
function messagesSigned(bytes32 _message) private view returns(bool) {
|
||||
return boolStorage[keccak256("messagesSigned", _message)];
|
||||
}
|
||||
|
||||
function depositsSigned(bytes32 _deposit) private view returns(bool) {
|
||||
return boolStorage[keccak256("depositsSigned", _deposit)];
|
||||
}
|
||||
|
||||
function numMessagesSigned(bytes32 _message) private view returns(uint256) {
|
||||
return uintStorage[keccak256("numMessagesSigned", _message)];
|
||||
}
|
||||
|
||||
function numDepositsSigned(bytes32 _deposit) private view returns(uint256) {
|
||||
return uintStorage[keccak256("numDepositsSigned", _deposit)];
|
||||
}
|
||||
|
||||
function setMessagesSigned(bytes32 _hash, bool _status) private {
|
||||
boolStorage[keccak256("messagesSigned", _hash)] = _status;
|
||||
}
|
||||
|
||||
function setDepositsSigned(bytes32 _deposit, bool _status) private {
|
||||
boolStorage[keccak256("depositsSigned", _deposit)] = _status;
|
||||
}
|
||||
|
||||
function setNumMessagesSigned(bytes32 _message, uint256 _number) private {
|
||||
uintStorage[keccak256("numMessagesSigned", _message)] = _number;
|
||||
}
|
||||
|
||||
function setNumDepositsSigned(bytes32 _deposit, uint256 _number) private {
|
||||
uintStorage[keccak256("numDepositsSigned", _deposit)] = _number;
|
||||
}
|
||||
|
||||
function setTotalSpentPerDay(uint256 _day, uint256 _value) private {
|
||||
uintStorage[keccak256("totalSpentPerDay", _day)] = _value;
|
||||
}
|
||||
|
||||
function setErc677token(address _token) private {
|
||||
require(_token != address(0));
|
||||
addressStorage[keccak256("erc677token")] = _token;
|
||||
}
|
||||
|
||||
function setInitialize(bool _status) private {
|
||||
boolStorage[keccak256("isInitialized")] = _status;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,42 +1,11 @@
|
|||
pragma solidity 0.4.19;
|
||||
|
||||
// File: contracts/BridgeDeploymentAddressStorage.sol
|
||||
|
||||
contract BridgeDeploymentAddressStorage {
|
||||
uint256 public deployedAtBlock;
|
||||
|
||||
function BridgeDeploymentAddressStorage() public {
|
||||
deployedAtBlock = block.number;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/IBridgeValidators.sol
|
||||
|
||||
interface IBridgeValidators {
|
||||
function isValidator(address _validator) public view returns(bool);
|
||||
function requiredSignatures() public view returns(uint8);
|
||||
function currentOwner() public view returns(address);
|
||||
}
|
||||
|
||||
// File: contracts/Validatable.sol
|
||||
|
||||
contract Validatable {
|
||||
IBridgeValidators public validatorContract;
|
||||
|
||||
modifier onlyValidator() {
|
||||
require(validatorContract.isValidator(msg.sender));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(validatorContract.currentOwner() == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
||||
function Validatable(address _validatorContract) public {
|
||||
require(_validatorContract != address(0));
|
||||
validatorContract = IBridgeValidators(_validatorContract);
|
||||
}
|
||||
function requiredSignatures() public view returns(uint256);
|
||||
function owner() public view returns(address);
|
||||
}
|
||||
|
||||
// File: contracts/libraries/Helpers.sol
|
||||
|
@ -77,7 +46,7 @@ library Helpers {
|
|||
bytes32[] _rs,
|
||||
bytes32[] _ss,
|
||||
IBridgeValidators _validatorContract) internal view returns (bool) {
|
||||
uint8 requiredSignatures = _validatorContract.requiredSignatures();
|
||||
uint256 requiredSignatures = _validatorContract.requiredSignatures();
|
||||
require(_vs.length >= requiredSignatures);
|
||||
bytes32 hash = MessageSigning.hashMessage(_message);
|
||||
address[] memory encounteredAddresses = new address[](requiredSignatures);
|
||||
|
@ -213,52 +182,179 @@ library SafeMath {
|
|||
}
|
||||
}
|
||||
|
||||
// File: contracts/HomeBridge.sol
|
||||
// File: contracts/upgradeability/EternalStorage.sol
|
||||
|
||||
contract HomeBridge is Validatable, BridgeDeploymentAddressStorage {
|
||||
/**
|
||||
* @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/upgradeability/UpgradeabilityOwnerStorage.sol
|
||||
|
||||
/**
|
||||
* @title UpgradeabilityOwnerStorage
|
||||
* @dev This contract keeps track of the upgradeability owner
|
||||
*/
|
||||
contract UpgradeabilityOwnerStorage {
|
||||
// Owner of the contract
|
||||
address private _upgradeabilityOwner;
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the owner
|
||||
* @return the address of the owner
|
||||
*/
|
||||
function upgradeabilityOwner() public view returns (address) {
|
||||
return _upgradeabilityOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the address of the owner
|
||||
*/
|
||||
function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
|
||||
_upgradeabilityOwner = newUpgradeabilityOwner;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/upgradeability/UpgradeabilityStorage.sol
|
||||
|
||||
/**
|
||||
* @title UpgradeabilityStorage
|
||||
* @dev This contract holds all the necessary state variables to support the upgrade functionality
|
||||
*/
|
||||
contract UpgradeabilityStorage {
|
||||
// Version name of the current implementation
|
||||
string internal _version;
|
||||
|
||||
// Address of the current implementation
|
||||
address internal _implementation;
|
||||
|
||||
/**
|
||||
* @dev Tells the version name of the current implementation
|
||||
* @return string representing the name of the current version
|
||||
*/
|
||||
function version() public view returns (string) {
|
||||
return _version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells the address of the current implementation
|
||||
* @return address of the current implementation
|
||||
*/
|
||||
function implementation() public view returns (address) {
|
||||
return _implementation;
|
||||
}
|
||||
}
|
||||
|
||||
// File: contracts/upgradeability/OwnedUpgradeabilityStorage.sol
|
||||
|
||||
/**
|
||||
* @title OwnedUpgradeabilityStorage
|
||||
* @dev This is the storage necessary to perform upgradeable contracts.
|
||||
* This means, required state variables for upgradeability purpose and eternal storage per se.
|
||||
*/
|
||||
contract OwnedUpgradeabilityStorage is UpgradeabilityOwnerStorage, UpgradeabilityStorage, EternalStorage {}
|
||||
|
||||
// File: contracts/upgradeable_contracts/U_Validatable.sol
|
||||
|
||||
contract Validatable is OwnedUpgradeabilityStorage {
|
||||
|
||||
function validatorContract() public view returns(IBridgeValidators) {
|
||||
return IBridgeValidators(addressStorage[keccak256("validatorContract")]);
|
||||
}
|
||||
|
||||
modifier onlyValidator() {
|
||||
require(validatorContract().isValidator(msg.sender));
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(validatorContract().owner() == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// File: contracts/upgradeable_contracts/U_HomeBridge.sol
|
||||
|
||||
// import "./IBridgeValidators.sol";
|
||||
// import "./Validatable.sol";
|
||||
// import "./BridgeDeploymentAddressStorage.sol";
|
||||
|
||||
|
||||
|
||||
|
||||
contract HomeBridge is OwnedUpgradeabilityStorage, Validatable {
|
||||
using SafeMath for uint256;
|
||||
uint256 public gasLimitWithdrawRelay;
|
||||
uint256 public homeDailyLimit;
|
||||
mapping (uint256 => uint256) totalSpentPerDay;
|
||||
mapping (bytes32 => bool) withdraws;
|
||||
|
||||
event GasConsumptionLimitsUpdated(uint256 gas);
|
||||
event Deposit (address recipient, uint256 value);
|
||||
event Withdraw (address recipient, uint256 value);
|
||||
event DailyLimit(uint256 newLimit);
|
||||
|
||||
function HomeBridge (
|
||||
function initialize (
|
||||
address _validatorContract,
|
||||
uint256 _homeDailyLimit
|
||||
) public Validatable(_validatorContract) {
|
||||
) public {
|
||||
require(!isInitialized());
|
||||
require(_validatorContract != address(0));
|
||||
require(_homeDailyLimit > 0);
|
||||
homeDailyLimit = _homeDailyLimit;
|
||||
DailyLimit(homeDailyLimit);
|
||||
addressStorage[keccak256("validatorContract")] = _validatorContract;
|
||||
uintStorage[keccak256("deployedAtBlock")] = block.number;
|
||||
setHomeDailyLimit(_homeDailyLimit);
|
||||
setInitialize(true);
|
||||
}
|
||||
|
||||
/// Should be used to deposit money.
|
||||
function () public payable {
|
||||
require(msg.value > 0);
|
||||
require(withinLimit(msg.value));
|
||||
totalSpentPerDay[getCurrentDay()] = totalSpentPerDay[getCurrentDay()].add(msg.value);
|
||||
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(msg.value));
|
||||
Deposit(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
function gasLimitWithdrawRelay() public view returns(uint256) {
|
||||
return uintStorage[keccak256("gasLimitWithdrawRelay")];
|
||||
}
|
||||
|
||||
function deployedAtBlock() public view returns(uint256) {
|
||||
return uintStorage[keccak256("deployedAtBlock")];
|
||||
}
|
||||
|
||||
function homeDailyLimit() public view returns(uint256) {
|
||||
return uintStorage[keccak256("homeDailyLimit")];
|
||||
}
|
||||
|
||||
function totalSpentPerDay(uint256 _day) public view returns(uint256) {
|
||||
return uintStorage[keccak256("totalSpentPerDay", _day)];
|
||||
}
|
||||
|
||||
function withdraws(bytes32 _withdraw) public view returns(bool) {
|
||||
return boolStorage[keccak256("withdraws", _withdraw)];
|
||||
}
|
||||
|
||||
function setGasLimitWithdrawRelay(uint256 _gas) public onlyOwner {
|
||||
gasLimitWithdrawRelay = _gas;
|
||||
GasConsumptionLimitsUpdated(gasLimitWithdrawRelay);
|
||||
uintStorage[keccak256("gasLimitWithdrawRelay")] = _gas;
|
||||
GasConsumptionLimitsUpdated(_gas);
|
||||
}
|
||||
|
||||
function withdraw(uint8[] vs, bytes32[] rs, bytes32[] ss, bytes message) public {
|
||||
require(message.length == 116);
|
||||
require(Helpers.hasEnoughValidSignatures(message, vs, rs, ss, validatorContract));
|
||||
require(Helpers.hasEnoughValidSignatures(message, vs, rs, ss, validatorContract()));
|
||||
|
||||
address recipient = Message.getRecipient(message);
|
||||
uint256 value = Message.getValue(message);
|
||||
bytes32 hash = Message.getTransactionHash(message);
|
||||
require(!withdraws[hash]);
|
||||
require(!withdraws(hash));
|
||||
// Order of operations below is critical to avoid TheDAO-like re-entry bug
|
||||
withdraws[hash] = true;
|
||||
setWithdraws(hash, true);
|
||||
|
||||
// pay out recipient
|
||||
recipient.transfer(value);
|
||||
|
@ -266,10 +362,9 @@ contract HomeBridge is Validatable, BridgeDeploymentAddressStorage {
|
|||
Withdraw(recipient, value);
|
||||
}
|
||||
|
||||
function setDailyLimit(uint256 _homeDailyLimit) public onlyOwner {
|
||||
require(_homeDailyLimit > 0);
|
||||
homeDailyLimit = _homeDailyLimit;
|
||||
DailyLimit(homeDailyLimit);
|
||||
function setHomeDailyLimit(uint256 _homeDailyLimit) public onlyOwner {
|
||||
uintStorage[keccak256("homeDailyLimit")] = _homeDailyLimit;
|
||||
DailyLimit(_homeDailyLimit);
|
||||
}
|
||||
|
||||
function getCurrentDay() public view returns(uint256) {
|
||||
|
@ -277,7 +372,23 @@ contract HomeBridge is Validatable, BridgeDeploymentAddressStorage {
|
|||
}
|
||||
|
||||
function withinLimit(uint256 _amount) public view returns(bool) {
|
||||
uint256 nextLimit = totalSpentPerDay[getCurrentDay()].add(_amount);
|
||||
return homeDailyLimit >= nextLimit;
|
||||
uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount);
|
||||
return homeDailyLimit() >= nextLimit;
|
||||
}
|
||||
|
||||
function isInitialized() public view returns(bool) {
|
||||
return boolStorage[keccak256("isInitialized")];
|
||||
}
|
||||
|
||||
function setTotalSpentPerDay(uint256 _day, uint256 _value) private {
|
||||
uintStorage[keccak256("totalSpentPerDay", _day)] = _value;
|
||||
}
|
||||
|
||||
function setWithdraws(bytes32 _withdraw, bool _status) private {
|
||||
boolStorage[keccak256("withdraws", _withdraw)] = _status;
|
||||
}
|
||||
|
||||
function setInitialize(bool _status) private {
|
||||
boolStorage[keccak256("isInitialized")] = _status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
rm -rf flats/*
|
||||
./node_modules/.bin/truffle-flattener contracts/ForeignBridge.sol > flats/ForeignBridge_flat.sol
|
||||
./node_modules/.bin/truffle-flattener contracts/BridgeValidators.sol > flats/BridgeValidators_flat.sol
|
||||
./node_modules/.bin/truffle-flattener contracts/HomeBridge.sol > flats/HomeBridge_flat.sol
|
||||
./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/U_ForeignBridge.sol > flats/ForeignBridge_flat.sol
|
||||
./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/U_BridgeValidators.sol > flats/BridgeValidators_flat.sol
|
||||
./node_modules/.bin/truffle-flattener contracts/upgradeable_contracts/U_HomeBridge.sol > flats/HomeBridge_flat.sol
|
||||
./node_modules/.bin/truffle-flattener contracts/POA20.sol > flats/POA20_flat.sol
|
||||
|
|
|
@ -4,22 +4,24 @@ const HomeBridge = artifacts.require("./HomeBridge.sol");
|
|||
const ForeignBridge = artifacts.require("./ForeignBridge.sol");
|
||||
|
||||
module.exports = async function(deployer, network, accounts) {
|
||||
let validators = ["0xb8988b690910913c97a090c3a6f80fad8b3a4683"]
|
||||
const homeDailyLimit = '1000000000000000000' // 1 ether
|
||||
const foreignDailyLimit = '1000000000000000000' // 1 ether
|
||||
console.log('deploying token')
|
||||
await deployer.deploy(POA20, "POA ERC20 on Foundation", "POA20", 18)
|
||||
const erc677token = await POA20.deployed()
|
||||
console.log('deploying validators')
|
||||
await deployer.deploy(BridgeValidators, '1', validators);
|
||||
const validatorContract = await BridgeValidators.deployed();
|
||||
console.log('deploying home')
|
||||
await deployer.deploy(HomeBridge, validatorContract.address, homeDailyLimit);
|
||||
console.log('deploying ForeignBridge')
|
||||
await deployer.deploy(ForeignBridge, validatorContract.address, erc677token.address, foreignDailyLimit);
|
||||
const foreignBridge = await ForeignBridge.deployed();
|
||||
if(process.env.DEPLOY_NORMAL === true){
|
||||
let validators = ["0xb8988b690910913c97a090c3a6f80fad8b3a4683"]
|
||||
const homeDailyLimit = '1000000000000000000' // 1 ether
|
||||
const foreignDailyLimit = '1000000000000000000' // 1 ether
|
||||
console.log('deploying token')
|
||||
await deployer.deploy(POA20, "POA ERC20 on Foundation", "POA20", 18)
|
||||
const erc677token = await POA20.deployed()
|
||||
console.log('deploying validators')
|
||||
await deployer.deploy(BridgeValidators, '1', validators);
|
||||
const validatorContract = await BridgeValidators.deployed();
|
||||
console.log('deploying home')
|
||||
await deployer.deploy(HomeBridge, validatorContract.address, homeDailyLimit);
|
||||
console.log('deploying ForeignBridge')
|
||||
await deployer.deploy(ForeignBridge, validatorContract.address, erc677token.address, foreignDailyLimit);
|
||||
const foreignBridge = await ForeignBridge.deployed();
|
||||
|
||||
await erc677token.transferOwnership(foreignBridge.address)
|
||||
console.log('all is done')
|
||||
await erc677token.transferOwnership(foreignBridge.address)
|
||||
console.log('all is done')
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
const POA20 = artifacts.require("./POA20.sol");
|
||||
const BridgeValidators = artifacts.require("./BridgeValidators.sol");
|
||||
const HomeBridge = artifacts.require("./HomeBridge.sol");
|
||||
const ForeignBridge = artifacts.require("./ForeignBridge.sol");
|
||||
const EternalStorageProxy = artifacts.require('EternalStorageProxy')
|
||||
|
||||
module.exports = async function(deployer, network, accounts) {
|
||||
const VALIDATORS = process.env.VALIDATORS ? process.env.VALIDATORS.split(" ") : ["0xb8988b690910913c97a090c3a6f80fad8b3a4683"];
|
||||
const REQUIRED_NUMBER_OF_VALIDATORS = process.env.REQUIRED_VALIDATORS || VALIDATORS.length
|
||||
const PROXY_OWNER = process.env.PROXY_OWNER || accounts[0];
|
||||
const homeDailyLimit = process.env.HOME_LIMIT || '1000000000000000000' // 1 ether
|
||||
const foreignDailyLimit = process.env.FOREIGN_LIMIT || '1000000000000000000' // 1 ether
|
||||
|
||||
console.log('storage for home validators')
|
||||
await deployer.deploy(EternalStorageProxy, {from: PROXY_OWNER});
|
||||
const storageBridgeValidators = await EternalStorageProxy.deployed()
|
||||
|
||||
console.log('deploying token')
|
||||
await deployer.deploy(POA20, "POA ERC20 on Foundation", "POA20", 18)
|
||||
const erc677token = await POA20.deployed()
|
||||
|
||||
console.log('deploying validators')
|
||||
await deployer.deploy(BridgeValidators);
|
||||
const validatorContract = await BridgeValidators.deployed();
|
||||
|
||||
console.log('hooking up eternal storage to BridgeValidators')
|
||||
//truffle sucks, it uses web3 0.20, hence I need to work around in order to generate data param
|
||||
var bridgeValidatorsWeb3 = web3.eth.contract(BridgeValidators.abi);
|
||||
var bridgeValidatorsWeb3Instance = bridgeValidatorsWeb3.at(validatorContract.address);
|
||||
var initializeDataValidators = bridgeValidatorsWeb3Instance.initialize.getData(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, PROXY_OWNER);
|
||||
await storageBridgeValidators.upgradeTo('0', validatorContract.address, {from: PROXY_OWNER});
|
||||
await web3.eth.sendTransaction({
|
||||
from: PROXY_OWNER,
|
||||
to: storageBridgeValidators.address,
|
||||
data: initializeDataValidators,
|
||||
value: 0,
|
||||
gas: 4700000
|
||||
})
|
||||
|
||||
console.log('deploying home storage on home network')
|
||||
await deployer.deploy(EternalStorageProxy, {from: PROXY_OWNER});
|
||||
const homeBridgeUpgradeable = await EternalStorageProxy.deployed()
|
||||
await deployer.deploy(HomeBridge);
|
||||
const homeBridgeImplementation = await HomeBridge.deployed();
|
||||
var homeBridgeWeb3 = web3.eth.contract(HomeBridge.abi);
|
||||
var homeBridgeWeb3Instance = homeBridgeWeb3.at(homeBridgeImplementation.address);
|
||||
var initializeDataHome = homeBridgeWeb3Instance.initialize.getData(storageBridgeValidators.address, homeDailyLimit);
|
||||
await homeBridgeUpgradeable.upgradeTo('0', homeBridgeImplementation.address, {from: PROXY_OWNER});
|
||||
await web3.eth.sendTransaction({
|
||||
from: PROXY_OWNER,
|
||||
to: homeBridgeUpgradeable.address,
|
||||
data: initializeDataHome,
|
||||
value: 0,
|
||||
gas: 4700000
|
||||
})
|
||||
|
||||
console.log('deploying ForeignBridge')
|
||||
await deployer.deploy(EternalStorageProxy, {from: PROXY_OWNER});
|
||||
const foreignBridgeUpgradeable = await EternalStorageProxy.deployed()
|
||||
await deployer.deploy(ForeignBridge);
|
||||
const foreignBridgeImplementation = await ForeignBridge.deployed();
|
||||
var foreignBridgeWeb3 = web3.eth.contract(ForeignBridge.abi);
|
||||
var foreignBridgeWeb3Instance = foreignBridgeWeb3.at(foreignBridgeImplementation.address);
|
||||
var initializeDataForeign = foreignBridgeWeb3Instance.initialize.getData(storageBridgeValidators.address, erc677token.address, foreignDailyLimit);
|
||||
await foreignBridgeUpgradeable.upgradeTo('0', foreignBridgeImplementation.address, {from: PROXY_OWNER});
|
||||
|
||||
await web3.eth.sendTransaction({
|
||||
from: PROXY_OWNER,
|
||||
to: foreignBridgeUpgradeable.address,
|
||||
data: initializeDataForeign,
|
||||
value: 0,
|
||||
gas: 4700000
|
||||
})
|
||||
// await deployer.deploy(ForeignBridge, validatorContract.address, erc677token.address, foreignDailyLimit);
|
||||
// const foreignBridge = await ForeignBridge.deployed();
|
||||
|
||||
await erc677token.transferOwnership(foreignBridgeUpgradeable.address)
|
||||
console.log('all is done', `
|
||||
validators: ${VALIDATORS}
|
||||
Owner: ${PROXY_OWNER}
|
||||
Foreign Bridge: ${foreignBridgeUpgradeable.address}
|
||||
Home Bridge: ${homeBridgeUpgradeable.address}
|
||||
POA20: ${erc677token.address}`)
|
||||
|
||||
};
|
Loading…
Reference in New Issue