tokenbridge-contracts/contracts/upgradeable_contracts/arbitrary_message/BasicAMB.sol

195 lines
8.1 KiB
Solidity

pragma solidity 0.4.24;
import "../BasicBridge.sol";
import "./VersionableAMB.sol";
contract BasicAMB is BasicBridge, VersionableAMB {
bytes32 internal constant MAX_GAS_PER_TX = 0x2670ecc91ec356e32067fd27b36614132d727b84a1e03e08f412a4f2cf075974; // keccak256(abi.encodePacked("maxGasPerTx"))
bytes32 internal constant NONCE = 0x7ab1577440dd7bedf920cb6de2f9fc6bf7ba98c78c85a3fa1f8311aac95e1759; // keccak256(abi.encodePacked("nonce"))
bytes32 internal constant SOURCE_CHAIN_ID = 0x67d6f42a1ed69c62022f2d160ddc6f2f0acd37ad1db0c24f4702d7d3343a4add; // keccak256(abi.encodePacked("sourceChainId"))
bytes32 internal constant SOURCE_CHAIN_ID_LENGTH = 0xe504ae1fd6471eea80f18b8532a61a9bb91fba4f5b837f80a1cfb6752350af44; // keccak256(abi.encodePacked("sourceChainIdLength"))
bytes32 internal constant DESTINATION_CHAIN_ID = 0xbbd454018e72a3f6c02bbd785bacc49e46292744f3f6761276723823aa332320; // keccak256(abi.encodePacked("destinationChainId"))
bytes32 internal constant DESTINATION_CHAIN_ID_LENGTH = 0xfb792ae4ad11102b93f26a51b3749c2b3667f8b561566a4806d4989692811594; // keccak256(abi.encodePacked("destinationChainIdLength"))
bytes32 internal constant ALLOW_REENTRANT_REQUESTS = 0xffa3a5a0e192028fc343362a39c5688e5a60819a4dc5ab3ee70c25bc25b78dd6; // keccak256(abi.encodePacked("allowReentrantRequests"))
/**
* Initializes AMB contract
* @param _sourceChainId chain id of a network where this contract is deployed
* @param _destinationChainId chain id of a network where all outgoing messages are directed
* @param _validatorContract address of the validators contract
* @param _maxGasPerTx maximum amount of gas per one message execution
* @param _gasPrice default gas price used by oracles for sending transactions in this network
* @param _requiredBlockConfirmations number of block confirmations oracle will wait before processing passed messages
* @param _owner address of new bridge owner
*/
function initialize(
uint256 _sourceChainId,
uint256 _destinationChainId,
address _validatorContract,
uint256 _maxGasPerTx,
uint256 _gasPrice,
uint256 _requiredBlockConfirmations,
address _owner
) external onlyRelevantSender returns (bool) {
require(!isInitialized());
require(AddressUtils.isContract(_validatorContract));
_setChainIds(_sourceChainId, _destinationChainId);
addressStorage[VALIDATOR_CONTRACT] = _validatorContract;
uintStorage[DEPLOYED_AT_BLOCK] = block.number;
uintStorage[MAX_GAS_PER_TX] = _maxGasPerTx;
_setGasPrice(_gasPrice);
_setRequiredBlockConfirmations(_requiredBlockConfirmations);
_setOwner(_owner);
setInitialize();
return isInitialized();
}
function getBridgeMode() external pure returns (bytes4 _data) {
return 0x2544fbb9; // bytes4(keccak256(abi.encodePacked("arbitrary-message-bridge-core")))
}
function maxGasPerTx() public view returns (uint256) {
return uintStorage[MAX_GAS_PER_TX];
}
function setMaxGasPerTx(uint256 _maxGasPerTx) external onlyOwner {
uintStorage[MAX_GAS_PER_TX] = _maxGasPerTx;
}
/**
* Internal function for retrieving chain id for the source network
* @return chain id for the current network
*/
function sourceChainId() public view returns (uint256) {
return uintStorage[SOURCE_CHAIN_ID];
}
/**
* Internal function for retrieving chain id for the destination network
* @return chain id for the destination network
*/
function destinationChainId() public view returns (uint256) {
return uintStorage[DESTINATION_CHAIN_ID];
}
/**
* Updates chain ids of used networks
* @param _sourceChainId chain id for current network
* @param _destinationChainId chain id for opposite network
*/
function setChainIds(uint256 _sourceChainId, uint256 _destinationChainId) external onlyOwner {
_setChainIds(_sourceChainId, _destinationChainId);
}
/**
* Sets the flag to allow passing new AMB requests in the opposite direction,
* while other AMB message is being processed.
* Only owner can call this method.
* @param _enable true, if reentrant requests are allowed.
*/
function setAllowReentrantRequests(bool _enable) external onlyOwner {
boolStorage[ALLOW_REENTRANT_REQUESTS] = _enable;
}
/**
* Tells if passing reentrant requests is allowed.
* @return true, if reentrant requests are allowed.
*/
function allowReentrantRequests() public view returns (bool) {
return boolStorage[ALLOW_REENTRANT_REQUESTS];
}
/**
* @dev Withdraws the erc20 tokens or native coins from this contract.
* @param _token address of the claimed token or address(0) for native coins.
* @param _to address of the tokens/coins receiver.
*/
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
claimValues(_token, _to);
}
/**
* Internal function for retrieving current nonce value
* @return nonce value
*/
function _nonce() internal view returns (uint64) {
return uint64(uintStorage[NONCE]);
}
/**
* Internal function for updating nonce value
* @param _nonce new nonce value
*/
function _setNonce(uint64 _nonce) internal {
uintStorage[NONCE] = uint256(_nonce);
}
/**
* Internal function for updating chain ids of used networks
* @param _sourceChainId chain id for current network
* @param _destinationChainId chain id for opposite network
*/
function _setChainIds(uint256 _sourceChainId, uint256 _destinationChainId) internal {
require(_sourceChainId > 0 && _destinationChainId > 0);
require(_sourceChainId != _destinationChainId);
// Length fields are needed further when encoding the message.
// Chain ids are compressed, so that leading zero bytes are not preserved.
// In order to save some gas during calls to MessageDelivery.c,
// lengths of chain ids are precalculated and being saved in the storage.
uint256 sourceChainIdLength = 0;
uint256 destinationChainIdLength = 0;
uint256 mask = 0xff;
for (uint256 i = 1; sourceChainIdLength == 0 || destinationChainIdLength == 0; i++) {
if (sourceChainIdLength == 0 && _sourceChainId & mask == _sourceChainId) {
sourceChainIdLength = i;
}
if (destinationChainIdLength == 0 && _destinationChainId & mask == _destinationChainId) {
destinationChainIdLength = i;
}
mask = (mask << 8) | 0xff;
}
uintStorage[SOURCE_CHAIN_ID] = _sourceChainId;
uintStorage[SOURCE_CHAIN_ID_LENGTH] = sourceChainIdLength;
uintStorage[DESTINATION_CHAIN_ID] = _destinationChainId;
uintStorage[DESTINATION_CHAIN_ID_LENGTH] = destinationChainIdLength;
}
/**
* Internal function for retrieving chain id length for the source network
* @return chain id for the current network
*/
function _sourceChainIdLength() internal view returns (uint256) {
return uintStorage[SOURCE_CHAIN_ID_LENGTH];
}
/**
* Internal function for retrieving chain id length for the destination network
* @return chain id for the destination network
*/
function _destinationChainIdLength() internal view returns (uint256) {
return uintStorage[DESTINATION_CHAIN_ID_LENGTH];
}
/**
* Internal function for validating version of the received message
* @param _messageId id of the received message
*/
function _isMessageVersionValid(bytes32 _messageId) internal returns (bool) {
return
_messageId & 0xffffffff00000000000000000000000000000000000000000000000000000000 == MESSAGE_PACKING_VERSION;
}
/**
* Internal function for validating destination chain id of the received message
* @param _chainId destination chain id of the received message
*/
function _isDestinationChainIdValid(uint256 _chainId) internal returns (bool res) {
return _chainId == sourceChainId();
}
}