Transaction Hash:
Block:
16149636 at Dec-09-2022 08:49:47 PM +UTC
Transaction Fee:
0.006689226106636128 ETH
$15.07
Gas Used:
153,324 Gas / 43.628043272 Gwei
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x690B9A9E...Db4FaC990
Miner
| (builder0x69) | 2.020335418656169896 Eth | 2.020425461480375364 Eth | 0.000090042824205468 | |
0x717DCb74...26c83191c |
0.147603557999324389 Eth
Nonce: 16
|
0.140914331892688261 Eth
Nonce: 17
| 0.006689226106636128 |
Execution Trace
AdminUpgradeabilityProxy.f5537ede( )
Mediator.transferToken( _recipient=0x717DCb74b04E1481229E961fA94dEFa26c83191c, _tokenAddress=0x96c645D3D3706f793Ef52C19bBACe441900eD47D, _value=501 )
MPSToken.transferFrom( _from=0x717DCb74b04E1481229E961fA94dEFa26c83191c, _to=0xA343Ab9EF834fbC5fb2391db555edeeb5691c871, _value=501 ) => ( True )
-
FreezeRule.isTransferValid( _from=0x717DCb74b04E1481229E961fA94dEFa26c83191c, _to=0xA343Ab9EF834fbC5fb2391db555edeeb5691c871, 501 ) => ( True )
-
LockRule.isTransferValid( _from=0x717DCb74b04E1481229E961fA94dEFa26c83191c, _to=0xA343Ab9EF834fbC5fb2391db555edeeb5691c871, 501 ) => ( True )
-
FreezeRule.isAddressValid( _address=0xA343Ab9EF834fbC5fb2391db555edeeb5691c871 ) => ( True )
-
LockRule.isAddressValid( 0xA343Ab9EF834fbC5fb2391db555edeeb5691c871 ) => ( True )
-
EternalStorageProxy.dc8601b3( )
-
ForeignAMB.requireToPassMessage( _contract=0x3037ba5e63cE968c1278452b7AE13b793FD4eea9, _data=0x75694727000000000000000000000000717DCB74B04E1481229E961FA94DEFA26C83191C000000000000000000000000FA57AA7BEED63D03AAF85FFD1753F5F6242588FB00000000000000000000000000000000000000000000000000000000000001F5000500004AC82B41BD819DD871590B510316F2385CB196FB000000000001D283, _gas=2000000 )
-
transferToken[Mediator (ln:39)]
passMessage[Mediator (ln:40)]
encodeWithSelector[Mediator (ln:49)]
transferFrom[Mediator (ln:57)]
_msgSender[Mediator (ln:57)]
requireToPassMessage[Mediator (ln:58)]
bridgeContract[Mediator (ln:58)]
mediatorContractOnOtherSide[Mediator (ln:59)]
requestGasLimit[Mediator (ln:61)]
setMessageRecipient[Mediator (ln:63)]
setMessageTokenAddress[Mediator (ln:64)]
setMessageValue[Mediator (ln:65)]
setNonce[Mediator (ln:66)]
File 1 of 7: AdminUpgradeabilityProxy
File 2 of 7: Mediator
File 3 of 7: MPSToken
File 4 of 7: FreezeRule
File 5 of 7: LockRule
File 6 of 7: EternalStorageProxy
File 7 of 7: ForeignAMB
// File: zos-lib/contracts/upgradeability/Proxy.sol pragma solidity ^0.5.0; /** * @title Proxy * @dev Implements delegation of calls to other contracts, with proper * forwarding of return values and bubbling of failures. * It defines a fallback function that delegates all calls to the address * returned by the abstract _implementation() internal function. */ contract Proxy { /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ function () payable external { _fallback(); } /** * @return The Address of the implementation. */ function _implementation() internal view returns (address); /** * @dev Delegates execution to an implementation contract. * This is a low level function that doesn't return to its internal call site. * It will return to the external caller whatever the implementation returns. * @param implementation Address to delegate. */ function _delegate(address implementation) internal { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } /** * @dev Function that is run as the first thing in the fallback function. * Can be redefined in derived contracts to add functionality. * Redefinitions must call super._willFallback(). */ function _willFallback() internal { } /** * @dev fallback implementation. * Extracted to enable manual triggering. */ function _fallback() internal { _willFallback(); _delegate(_implementation()); } } // File: zos-lib/contracts/utils/Address.sol pragma solidity ^0.5.0; /** * Utility library of inline functions on addresses * * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/utils/Address.sol * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the * build/artifacts folder) as well as the vanilla Address implementation from an openzeppelin version. */ library ZOSLibAddress { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param account address of the account to check * @return whether the target address is a contract */ function isContract(address account) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } // File: zos-lib/contracts/upgradeability/BaseUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseUpgradeabilityProxy * @dev This contract implements a proxy that allows to change the * implementation address to which it will delegate. * Such a change is called an implementation upgrade. */ contract BaseUpgradeabilityProxy is Proxy { /** * @dev Emitted when the implementation is upgraded. * @param implementation Address of the new implementation. */ event Upgraded(address indexed implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is * validated in the constructor. */ bytes32 internal constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3; /** * @dev Returns the current implementation. * @return Address of the current implementation */ function _implementation() internal view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * @param newImplementation Address of the new implementation. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation address of the proxy. * @param newImplementation Address of the new implementation. */ function _setImplementation(address newImplementation) internal { require(ZOSLibAddress.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, newImplementation) } } } // File: zos-lib/contracts/upgradeability/UpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title UpgradeabilityProxy * @dev Extends BaseUpgradeabilityProxy with a constructor for initializing * implementation and init data. */ contract UpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Contract constructor. * @param _logic Address of the initial implementation. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, bytes memory _data) public payable { assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation")); _setImplementation(_logic); if(_data.length > 0) { (bool success,) = _logic.delegatecall(_data); require(success); } } } // File: zos-lib/contracts/upgradeability/BaseAdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseAdminUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with an authorization * mechanism for administrative tasks. * All external functions in this contract must be guarded by the * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity * feature proposal that would enable this to be done automatically. */ contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Emitted when the administration has been transferred. * @param previousAdmin Address of the previous admin. * @param newAdmin Address of the new admin. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is * validated in the constructor. */ bytes32 internal constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b; /** * @dev Modifier to check whether the `msg.sender` is the admin. * If it is, it will run the function. Otherwise, it will delegate the call * to the implementation. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * @return The address of the proxy admin. */ function admin() external ifAdmin returns (address) { return _admin(); } /** * @return The address of the implementation. */ function implementation() external ifAdmin returns (address) { return _implementation(); } /** * @dev Changes the admin of the proxy. * Only the current admin can call this function. * @param newAdmin Address to transfer proxy administration to. */ function changeAdmin(address newAdmin) external ifAdmin { require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address"); emit AdminChanged(_admin(), newAdmin); _setAdmin(newAdmin); } /** * @dev Upgrade the backing implementation of the proxy. * Only the admin can call this function. * @param newImplementation Address of the new implementation. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the backing implementation of the proxy and call a function * on the new implementation. * This is useful to initialize the proxied contract. * @param newImplementation Address of the new implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin { _upgradeTo(newImplementation); (bool success,) = newImplementation.delegatecall(data); require(success); } /** * @return The admin slot. */ function _admin() internal view returns (address adm) { bytes32 slot = ADMIN_SLOT; assembly { adm := sload(slot) } } /** * @dev Sets the address of the proxy admin. * @param newAdmin Address of the new proxy admin. */ function _setAdmin(address newAdmin) internal { bytes32 slot = ADMIN_SLOT; assembly { sstore(slot, newAdmin) } } /** * @dev Only fall back when the sender is not the admin. */ function _willFallback() internal { require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); super._willFallback(); } } // File: zos-lib/contracts/upgradeability/AdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title AdminUpgradeabilityProxy * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for * initializing the implementation, admin, and init data. */ contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy { /** * Contract constructor. * @param _logic address of the initial implementation. * @param _admin Address of the proxy administrator. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable { assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin")); _setAdmin(_admin); } }
File 2 of 7: Mediator
/* Copyright (c) 2019 Mt Pelerin Group Ltd This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation with the addition of the following permission added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY MT PELERIN GROUP LTD. MT PELERIN GROUP LTD DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, 02110-1301 USA, or download the license from the following URL: https://www.gnu.org/licenses/agpl-3.0.fr.html The interactive user interfaces in modified source and object code versions of this program must display Appropriate Legal Notices, as required under Section 5 of the GNU Affero General Public License. You can be released from the requirements of the license by purchasing a commercial license. Buying such a license is mandatory as soon as you develop commercial activities involving Mt Pelerin Group Ltd software without disclosing the source code of your own applications. These activities include: offering paid services based/using this product to customers, using this product in any application, distributing this product with a closed source product. For more information, please contact Mt Pelerin Group Ltd at this address: [email protected] */ pragma solidity 0.6.2; import "./abstract/BasicMediator.sol"; import "../interfaces/IERC20ToERC20Mediator.sol"; import "../interfaces/IERC20Detailed.sol"; contract Mediator is BasicMediator { uint256 public constant VERSION = 1; mapping(address => address) internal tokenMapping; function transferToken(address _recipient, address _tokenAddress, uint256 _value) external { passMessage(_recipient, _tokenAddress, _value); } function passMessage( address _recipient, address _tokenAddress, uint256 _value ) internal override { require(tokenMapping[_tokenAddress] != address(0), 'AM01'); bytes4 methodSelector = IERC20ToERC20Mediator(0).handleBridgedTokens.selector; bytes memory data = abi.encodeWithSelector( methodSelector, _recipient, tokenMapping[_tokenAddress], _value, nonce ); IERC20Detailed token = IERC20Detailed(_tokenAddress); token.transferFrom(_msgSender(), address(this), _value); bytes32 msgId = bridgeContract().requireToPassMessage( mediatorContractOnOtherSide(), data, requestGasLimit() ); setMessageRecipient(msgId, _recipient); setMessageTokenAddress(msgId, _tokenAddress); setMessageValue(msgId, _value); setNonce(msgId); } function handleBridgedTokens( address _recipient, address _tokenAddress, uint256 _value, bytes32 /* nonce */ ) external { require(_msgSender() == address(bridgeContract()), 'AM05'); require(bridgeContract().messageSender() == mediatorContractOnOtherSide(), 'AM06'); unlockToken(_recipient, _tokenAddress, _value); } function unlockToken(address _recipient, address _tokenAddress, uint256 _value) internal { IERC20Detailed token = IERC20Detailed(_tokenAddress); token.transfer(_recipient, _value); } function claimTokens(address _tokenAddress, address _to) public onlyOwner validAddress(_to) { IERC20Detailed token = IERC20Detailed(_tokenAddress); uint256 balance = token.balanceOf(address(this)); unlockToken(_to, _tokenAddress, balance); } function fixFailedMessage(bytes32 _messageId) external override { require(_msgSender() == address(bridgeContract()), 'AM05'); require(bridgeContract().messageSender() == mediatorContractOnOtherSide(), 'AM06'); require(!messageFixed(_messageId), 'AM07'); address recipient = messageRecipient(_messageId); address tokenAddress = messageTokenAddress(_messageId); uint256 value = messageValue(_messageId); setMessageFixed(_messageId); unlockToken(recipient, tokenAddress, value); emit FailedMessageFixed(_messageId, recipient, tokenAddress, value); } function setTokenMapping( address _localTokenAddress, address _remoteTokenAddress ) public onlyOperator validAddress(_remoteTokenAddress) validAddress(_localTokenAddress) { tokenMapping[_localTokenAddress] = _remoteTokenAddress; } function getTokenMapping(address _localTokenAddress) public view returns (address) { return tokenMapping[_localTokenAddress]; } /* Reserved slots for future use: https://docs.openzeppelin.com/sdk/2.5/writing-contracts.html#modifying-your-contracts */ uint256[50] private ______gap; } pragma solidity ^0.6.2; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } } pragma solidity ^0.6.0; import "../GSN/Context.sol"; import "../Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract OwnableUpgradeSafe is Initializable, ContextUpgradeSafe { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[49] private __gap; } pragma solidity >=0.4.24 <0.7.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } pragma solidity ^0.6.0; import "../Initializable.sol"; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract ContextUpgradeSafe is Initializable { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; } /* Copyright (c) 2019 Mt Pelerin Group Ltd This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation with the addition of the following permission added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY MT PELERIN GROUP LTD. MT PELERIN GROUP LTD DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, 02110-1301 USA, or download the license from the following URL: https://www.gnu.org/licenses/agpl-3.0.fr.html The interactive user interfaces in modified source and object code versions of this program must display Appropriate Legal Notices, as required under Section 5 of the GNU Affero General Public License. You can be released from the requirements of the license by purchasing a commercial license. Buying such a license is mandatory as soon as you develop commercial activities involving Mt Pelerin Group Ltd software without disclosing the source code of your own applications. These activities include: offering paid services based/using this product to customers, using this product in any application, distributing this product with a closed source product. For more information, please contact Mt Pelerin Group Ltd at this address: [email protected] */ pragma solidity 0.6.2; import "./AMBMediator.sol"; abstract contract BasicMediator is AMBMediator { event FailedMessageFixed(bytes32 indexed messageId, address recipient, address tokenAddress, uint256 value); bytes32 public nonce; mapping(bytes32 => address) internal _messageRecipient; mapping(bytes32 => address) internal _messageTokenAddress; mapping(bytes32 => uint256) internal _messageValue; mapping(bytes32 => bool) internal _messageFixed; function initialize( address _bridgeContract, address _mediatorContract, uint256 _requestGasLimit, address _owner ) external returns (bool) { _setBridgeContract(_bridgeContract); _setMediatorContractOnOtherSide(_mediatorContract); _setRequestGasLimit(_requestGasLimit); Operator.initialize(_owner); setNonce(keccak256(abi.encodePacked(address(this)))); } function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) { return (1, 0, 0); } function getBridgeMode() external pure returns (bytes4 _data) { return bytes4(keccak256(abi.encodePacked("erc20-to-erc20-lock-unlock-amb"))); } function setNonce(bytes32 _msgId) internal { nonce = _msgId; } function setMessageRecipient(bytes32 _msgId, address _recipient) internal { _messageRecipient[_msgId] = _recipient; } function messageRecipient(bytes32 _msgId) internal view returns (address) { return _messageRecipient[_msgId]; } function setMessageTokenAddress(bytes32 _msgId, address _tokenAddress) internal { _messageTokenAddress[_msgId] = _tokenAddress; } function messageTokenAddress(bytes32 _msgId) internal view returns (address) { return _messageTokenAddress[_msgId]; } function setMessageValue(bytes32 _msgId, uint256 _value) internal { _messageValue[_msgId] = _value; } function messageValue(bytes32 _msgId) internal view returns (uint256) { return _messageValue[_msgId]; } function setMessageFixed(bytes32 _msgId) internal { _messageFixed[_msgId] = true; } function messageFixed(bytes32 _msgId) public view returns (bool) { return _messageFixed[_msgId]; } function requestFailedMessageFix(bytes32 _txHash) external { require(!bridgeContract().messageCallStatus(_txHash), 'AM04'); require(bridgeContract().failedMessageReceiver(_txHash) == address(this), 'AM05'); require(bridgeContract().failedMessageSender(_txHash) == mediatorContractOnOtherSide(), 'AM06'); bytes32 msgId = bridgeContract().failedMessageDataHash(_txHash); bytes4 methodSelector = this.fixFailedMessage.selector; bytes memory data = abi.encodeWithSelector(methodSelector, msgId); bridgeContract().requireToPassMessage(mediatorContractOnOtherSide(), data, requestGasLimit()); } function fixFailedMessage(bytes32 _msgId) external virtual; function passMessage(address _recipient, address _tokenAddress, uint256 _value) internal virtual; /* Reserved slots for future use: https://docs.openzeppelin.com/sdk/2.5/writing-contracts.html#modifying-your-contracts */ uint256[50] private ______gap; } /* Copyright (c) 2019 Mt Pelerin Group Ltd This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation with the addition of the following permission added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY MT PELERIN GROUP LTD. MT PELERIN GROUP LTD DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, 02110-1301 USA, or download the license from the following URL: https://www.gnu.org/licenses/agpl-3.0.fr.html The interactive user interfaces in modified source and object code versions of this program must display Appropriate Legal Notices, as required under Section 5 of the GNU Affero General Public License. You can be released from the requirements of the license by purchasing a commercial license. Buying such a license is mandatory as soon as you develop commercial activities involving Mt Pelerin Group Ltd software without disclosing the source code of your own applications. These activities include: offering paid services based/using this product to customers, using this product in any application, distributing this product with a closed source product. For more information, please contact Mt Pelerin Group Ltd at this address: [email protected] */ pragma solidity 0.6.2; import "../../interfaces/IAMB.sol"; import "../../access/Operator.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/utils/Address.sol"; contract AMBMediator is Initializable, Operator { address internal _bridgeContract; address internal _mediatorContractOnOtherSide; uint256 internal _requestGasLimit; modifier validAddress(address _to) { require(_to != address(0), 'AM01'); /* solcov ignore next */ _; } function setBridgeContract(address newBridgeContract) external onlyOwner { _setBridgeContract(newBridgeContract); } function _setBridgeContract(address newBridgeContract) internal { require(Address.isContract(newBridgeContract), 'AM02'); _bridgeContract = newBridgeContract; } function bridgeContract() public view returns (IAMB) { return IAMB(_bridgeContract); } function setMediatorContractOnOtherSide(address newMediatorContract) external onlyOwner { _setMediatorContractOnOtherSide(newMediatorContract); } function _setMediatorContractOnOtherSide(address newMediatorContract) internal { _mediatorContractOnOtherSide = newMediatorContract; } function mediatorContractOnOtherSide() public view returns (address) { return _mediatorContractOnOtherSide; } function setRequestGasLimit(uint256 newRequestGasLimit) external onlyOwner { _setRequestGasLimit(newRequestGasLimit); } function _setRequestGasLimit(uint256 newRequestGasLimit) internal { require(newRequestGasLimit <= bridgeContract().maxGasPerTx(), 'AM03'); _requestGasLimit = newRequestGasLimit; } function requestGasLimit() public view returns (uint256) { return _requestGasLimit; } /* Reserved slots for future use: https://docs.openzeppelin.com/sdk/2.5/writing-contracts.html#modifying-your-contracts */ uint256[50] private ______gap; } /* Copyright (c) 2019 Mt Pelerin Group Ltd This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation with the addition of the following permission added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY MT PELERIN GROUP LTD. MT PELERIN GROUP LTD DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, 02110-1301 USA, or download the license from the following URL: https://www.gnu.org/licenses/agpl-3.0.fr.html The interactive user interfaces in modified source and object code versions of this program must display Appropriate Legal Notices, as required under Section 5 of the GNU Affero General Public License. You can be released from the requirements of the license by purchasing a commercial license. Buying such a license is mandatory as soon as you develop commercial activities involving Mt Pelerin Group Ltd software without disclosing the source code of your own applications. These activities include: offering paid services based/using this product to customers, using this product in any application, distributing this product with a closed source product. For more information, please contact Mt Pelerin Group Ltd at this address: [email protected] */ pragma solidity 0.6.2; interface IERC20ToERC20Mediator { function handleBridgedTokens( address _recipient, address _tokenAddress, uint256 _value, bytes32 nonce ) external; } /* Copyright (c) 2019 Mt Pelerin Group Ltd This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation with the addition of the following permission added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY MT PELERIN GROUP LTD. MT PELERIN GROUP LTD DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, 02110-1301 USA, or download the license from the following URL: https://www.gnu.org/licenses/agpl-3.0.fr.html The interactive user interfaces in modified source and object code versions of this program must display Appropriate Legal Notices, as required under Section 5 of the GNU Affero General Public License. You can be released from the requirements of the license by purchasing a commercial license. Buying such a license is mandatory as soon as you develop commercial activities involving Mt Pelerin Group Ltd software without disclosing the source code of your own applications. These activities include: offering paid services based/using this product to customers, using this product in any application, distributing this product with a closed source product. For more information, please contact Mt Pelerin Group Ltd at this address: [email protected] */ pragma solidity 0.6.2; /** * @title IERC20Detailed * @dev IERC20Detailed interface **/ interface IERC20Detailed { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function transfer(address to, uint256 value) external returns (bool); function approve(address spender, uint256 value) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); function totalSupply() external view returns (uint256); function balanceOf(address who) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } pragma solidity 0.6.2; interface IAMB { function messageSender() external view returns (address); function maxGasPerTx() external view returns (uint256); function transactionHash() external view returns (bytes32); function messageId() external view returns (bytes32); function messageSourceChainId() external view returns (bytes32); function messageCallStatus(bytes32 _messageId) external view returns (bool); function failedMessageDataHash(bytes32 _messageId) external view returns (bytes32); function failedMessageReceiver(bytes32 _messageId) external view returns (address); function failedMessageSender(bytes32 _messageId) external view returns (address); function requireToPassMessage(address _contract, bytes calldata _data, uint256 _gas) external returns (bytes32); function requireToConfirmMessage(address _contract, bytes calldata _data, uint256 _gas) external returns (bytes32); function sourceChainId() external view returns (uint256); function destinationChainId() external view returns (uint256); } /* Copyright (c) 2016-2019 zOS Global Limited Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity 0.6.2; /** * @title Roles * @dev Library for managing addresses assigned to a Role. */ library Roles { struct Role { mapping (address => bool) bearer; } /** * @dev Give an account access to this role. */ function add(Role storage role, address account) internal { require(!has(role, account), "Roles: account already has role"); role.bearer[account] = true; } /** * @dev Remove an account's access to this role. */ function remove(Role storage role, address account) internal { require(has(role, account), "Roles: account does not have role"); role.bearer[account] = false; } /** * @dev Check if an account has this role. * @return bool */ function has(Role storage role, address account) internal view returns (bool) { require(account != address(0), "Roles: account is the zero address"); return role.bearer[account]; } }/* Copyright (c) 2019 Mt Pelerin Group Ltd This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation with the addition of the following permission added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY MT PELERIN GROUP LTD. MT PELERIN GROUP LTD DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, 02110-1301 USA, or download the license from the following URL: https://www.gnu.org/licenses/agpl-3.0.fr.html The interactive user interfaces in modified source and object code versions of this program must display Appropriate Legal Notices, as required under Section 5 of the GNU Affero General Public License. You can be released from the requirements of the license by purchasing a commercial license. Buying such a license is mandatory as soon as you develop commercial activities involving Mt Pelerin Group Ltd software without disclosing the source code of your own applications. These activities include: offering paid services based/using this product to customers, using this product in any application, distributing this product with a closed source product. For more information, please contact Mt Pelerin Group Ltd at this address: [email protected] */ pragma solidity 0.6.2; import "@openzeppelin/contracts-ethereum-package/contracts/access/Ownable.sol"; import "./Roles.sol"; /** * @title Operator * @dev The Operator contract contains list of addresses authorized to specific administration operations on contracts * * Error messages * OP01: Message sender must be an operator */ contract Operator is OwnableUpgradeSafe { using Roles for Roles.Role; Roles.Role private operators; event OperatorAdded(address indexed operator); event OperatorRemoved(address indexed operator); /** * @dev Initializer (replaces constructor when contract is upgradable) * @param owner the final owner of the contract */ function initialize(address owner) public virtual initializer { __Ownable_init(); transferOwnership(owner); } /** * @dev Throws OP01 if called by any account other than the operator */ modifier onlyOperator { require(owner() == _msgSender() || operators.has(_msgSender()), "OP01"); _; } /** * @dev Checks if the address in param _operator is granted the operator right * @param _operator the address to check for operator right * @return true if the address is granted the operator right, false otherwise */ function isOperator(address _operator) public view returns (bool) { return operators.has(_operator); } /** * @dev Grants the operator right to _operator * @param _operator the address to grant */ function addOperator(address _operator) public onlyOwner { operators.add(_operator); emit OperatorAdded(_operator); } /** * @dev Removes the operator right from the _operator address * @param _operator the address of the operator to remove */ function removeOperator(address _operator) public onlyOwner { operators.remove(_operator); emit OperatorRemoved(_operator); } }
File 3 of 7: MPSToken
/** * MPSToken.sol * MPS Token (Mt Pelerin Share) * More info about MPS : https://github.com/MtPelerin/MtPelerin-share-MPS * The unflattened code is available through this github tag: * https://github.com/MtPelerin/MtPelerin-protocol/tree/etherscan-verify-batch-1 * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice All matters regarding the intellectual property of this code * @notice or software are subject to Swiss Law without reference to its * @notice conflicts of law rules. * @notice License for each contract is available in the respective file * @notice or in the LICENSE.md file. * @notice https://github.com/MtPelerin/ * @notice Code by OpenZeppelin is copyrighted and licensed on their repository: * @notice https://github.com/OpenZeppelin/openzeppelin-solidity */ pragma solidity ^0.4.24; // File: contracts/zeppelin/token/ERC20/ERC20Basic.sol /** * @title ERC20Basic * @dev Simpler version of ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address who) public view returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } // File: contracts/zeppelin/math/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 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/zeppelin/token/ERC20/BasicToken.sol /** * @title Basic token * @dev Basic version of StandardToken, with no allowances. */ contract BasicToken is ERC20Basic { using SafeMath for uint256; mapping(address => uint256) balances; uint256 totalSupply_; /** * @dev total number of tokens in existence */ function totalSupply() public view returns (uint256) { return totalSupply_; } /** * @dev transfer token for a specified address * @param _to The address to transfer to. * @param _value The amount to be transferred. */ function transfer(address _to, uint256 _value) public returns (bool) { require(_to != address(0)); require(_value <= balances[msg.sender]); balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); emit Transfer(msg.sender, _to, _value); return true; } /** * @dev Gets the balance of the specified address. * @param _owner The address to query the the balance of. * @return An uint256 representing the amount owned by the passed address. */ function balanceOf(address _owner) public view returns (uint256) { return balances[_owner]; } } // File: contracts/interface/ISeizable.sol /** * @title ISeizable * @dev ISeizable interface * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ contract ISeizable { function seize(address _account, uint256 _value) public; event Seize(address account, uint256 amount); } // File: contracts/zeppelin/ownership/Ownable.sol /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address public owner; event OwnershipRenounced(address indexed previousOwner); event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor() 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 relinquish control of the contract. */ function renounceOwnership() public onlyOwner { emit OwnershipRenounced(owner); owner = address(0); } /** * @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 { _transferOwnership(_newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param _newOwner The address to transfer ownership to. */ function _transferOwnership(address _newOwner) internal { require(_newOwner != address(0)); emit OwnershipTransferred(owner, _newOwner); owner = _newOwner; } } // File: contracts/Authority.sol /** * @title Authority * @dev The Authority contract has an authority address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". * Authority means to represent a legal entity that is entitled to specific rights * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * * Error messages * AU01: Message sender must be an authority */ contract Authority is Ownable { address authority; /** * @dev Throws if called by any account other than the authority. */ modifier onlyAuthority { require(msg.sender == authority, "AU01"); _; } /** * @dev return the address associated to the authority */ function authorityAddress() public view returns (address) { return authority; } /** * @dev rdefines an authority * @param _name the authority name * @param _address the authority address. */ function defineAuthority(string _name, address _address) public onlyOwner { emit AuthorityDefined(_name, _address); authority = _address; } event AuthorityDefined( string name, address _address ); } // File: contracts/token/component/SeizableToken.sol /** * @title SeizableToken * @dev BasicToken contract which allows owner to seize accounts * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * * Error messages * ST01: Owner cannot seize itself */ contract SeizableToken is BasicToken, Authority, ISeizable { using SafeMath for uint256; // Although very unlikely, the value below may overflow. // This contract and its children should expect it to happened and consider // this value as only the first 256 bits of the complete value. uint256 public allTimeSeized = 0; // overflow may happend /** * @dev called by the owner to seize value from the account */ function seize(address _account, uint256 _value) public onlyAuthority { require(_account != owner, "ST01"); balances[_account] = balances[_account].sub(_value); balances[authority] = balances[authority].add(_value); allTimeSeized += _value; emit Seize(_account, _value); } } // File: contracts/zeppelin/token/ERC20/ERC20.sol /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { function allowance(address owner, address spender) public view returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: contracts/zeppelin/token/ERC20/StandardToken.sol /** * @title Standard ERC20 token * * @dev Implementation of the basic standard token. * @dev https://github.com/ethereum/EIPs/issues/20 * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol */ contract StandardToken is ERC20, BasicToken { mapping (address => mapping (address => uint256)) internal allowed; /** * @dev Transfer tokens from one address to another * @param _from address The address which you want to send tokens from * @param _to address The address which you want to transfer to * @param _value uint256 the amount of tokens to be transferred */ function transferFrom( address _from, address _to, uint256 _value ) public returns (bool) { require(_to != address(0)); require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); emit Transfer(_from, _to, _value); return true; } /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. * * Beware that changing an allowance with this method brings the risk that someone may use both the old * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * @param _spender The address which will spend the funds. * @param _value The amount of tokens to be spent. */ function approve(address _spender, uint256 _value) public returns (bool) { allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } /** * @dev Function to check the amount of tokens that an owner allowed to a spender. * @param _owner address The address which owns the funds. * @param _spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ function allowance( address _owner, address _spender ) public view returns (uint256) { return allowed[_owner][_spender]; } /** * @dev Increase the amount of tokens that an owner allowed to a spender. * * approve should be called when allowed[_spender] == 0. To increment * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * @param _spender The address which will spend the funds. * @param _addedValue The amount of tokens to increase the allowance by. */ function increaseApproval( address _spender, uint _addedValue ) public returns (bool) { allowed[msg.sender][_spender] = ( allowed[msg.sender][_spender].add(_addedValue)); emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. * * approve should be called when allowed[_spender] == 0. To decrement * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * @param _spender The address which will spend the funds. * @param _subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseApproval( address _spender, uint _subtractedValue ) public returns (bool) { uint oldValue = allowed[msg.sender][_spender]; if (_subtractedValue > oldValue) { allowed[msg.sender][_spender] = 0; } else { allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); } emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } } // File: contracts/interface/IProvableOwnership.sol /** * @title IProvableOwnership * @dev IProvableOwnership interface which describe proof of ownership. * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ contract IProvableOwnership { function proofLength(address _holder) public view returns (uint256); function proofAmount(address _holder, uint256 _proofId) public view returns (uint256); function proofDateFrom(address _holder, uint256 _proofId) public view returns (uint256); function proofDateTo(address _holder, uint256 _proofId) public view returns (uint256); function createProof(address _holder) public; function checkProof(address _holder, uint256 _proofId, uint256 _at) public view returns (uint256); function transferWithProofs( address _to, uint256 _value, bool _proofFrom, bool _proofTo ) public returns (bool); function transferFromWithProofs( address _from, address _to, uint256 _value, bool _proofFrom, bool _proofTo ) public returns (bool); event ProofOfOwnership(address indexed holder, uint256 proofId); } // File: contracts/interface/IAuditableToken.sol /** * @title IAuditableToken * @dev IAuditableToken interface describing the audited data * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ contract IAuditableToken { function lastTransactionAt(address _address) public view returns (uint256); function lastReceivedAt(address _address) public view returns (uint256); function lastSentAt(address _address) public view returns (uint256); function transactionCount(address _address) public view returns (uint256); function receivedCount(address _address) public view returns (uint256); function sentCount(address _address) public view returns (uint256); function totalReceivedAmount(address _address) public view returns (uint256); function totalSentAmount(address _address) public view returns (uint256); } // File: contracts/token/component/AuditableToken.sol /** * @title AuditableToken * @dev AuditableToken contract * AuditableToken provides transaction data which can be used * in other smart contracts * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ contract AuditableToken is IAuditableToken, StandardToken { // Although very unlikely, the following values below may overflow: // receivedCount, sentCount, totalReceivedAmount, totalSentAmount // This contract and its children should expect it to happen and consider // these values as only the first 256 bits of the complete value. struct Audit { uint256 createdAt; uint256 lastReceivedAt; uint256 lastSentAt; uint256 receivedCount; // potential overflow uint256 sentCount; // poential overflow uint256 totalReceivedAmount; // potential overflow uint256 totalSentAmount; // potential overflow } mapping(address => Audit) internal audits; /** * @dev Time of the creation of the audit struct */ function auditCreatedAt(address _address) public view returns (uint256) { return audits[_address].createdAt; } /** * @dev Time of the last transaction */ function lastTransactionAt(address _address) public view returns (uint256) { return ( audits[_address].lastReceivedAt > audits[_address].lastSentAt ) ? audits[_address].lastReceivedAt : audits[_address].lastSentAt; } /** * @dev Time of the last received transaction */ function lastReceivedAt(address _address) public view returns (uint256) { return audits[_address].lastReceivedAt; } /** * @dev Time of the last sent transaction */ function lastSentAt(address _address) public view returns (uint256) { return audits[_address].lastSentAt; } /** * @dev Count of transactions */ function transactionCount(address _address) public view returns (uint256) { return audits[_address].receivedCount + audits[_address].sentCount; } /** * @dev Count of received transactions */ function receivedCount(address _address) public view returns (uint256) { return audits[_address].receivedCount; } /** * @dev Count of sent transactions */ function sentCount(address _address) public view returns (uint256) { return audits[_address].sentCount; } /** * @dev All time received */ function totalReceivedAmount(address _address) public view returns (uint256) { return audits[_address].totalReceivedAmount; } /** * @dev All time sent */ function totalSentAmount(address _address) public view returns (uint256) { return audits[_address].totalSentAmount; } /** * @dev Overriden transfer function */ function transfer(address _to, uint256 _value) public returns (bool) { if (!super.transfer(_to, _value)) { return false; } updateAudit(msg.sender, _to, _value); return true; } /** * @dev Overriden transferFrom function */ function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { if (!super.transferFrom(_from, _to, _value)) { return false; } updateAudit(_from, _to, _value); return true; } /** * @dev currentTime() */ function currentTime() internal view returns (uint256) { // solium-disable-next-line security/no-block-members return now; } /** * @dev Update audit data */ function updateAudit(address _sender, address _receiver, uint256 _value) private returns (uint256) { Audit storage senderAudit = audits[_sender]; senderAudit.lastSentAt = currentTime(); senderAudit.sentCount++; senderAudit.totalSentAmount += _value; if (senderAudit.createdAt == 0) { senderAudit.createdAt = currentTime(); } Audit storage receiverAudit = audits[_receiver]; receiverAudit.lastReceivedAt = currentTime(); receiverAudit.receivedCount++; receiverAudit.totalReceivedAmount += _value; if (receiverAudit.createdAt == 0) { receiverAudit.createdAt = currentTime(); } } } // File: contracts/token/component/ProvableOwnershipToken.sol /** * @title ProvableOwnershipToken * @dev ProvableOwnershipToken is a StandardToken * with ability to record a proof of ownership * * When desired a proof of ownership can be generated. * The proof is stored within the contract. * A proofId is then returned. * The proof can later be used to retrieve the amount needed. * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ contract ProvableOwnershipToken is IProvableOwnership, AuditableToken, Ownable { struct Proof { uint256 amount; uint256 dateFrom; uint256 dateTo; } mapping(address => mapping(uint256 => Proof)) internal proofs; mapping(address => uint256) internal proofLengths; /** * @dev number of proof stored in the contract */ function proofLength(address _holder) public view returns (uint256) { return proofLengths[_holder]; } /** * @dev amount contains for the proofId reccord */ function proofAmount(address _holder, uint256 _proofId) public view returns (uint256) { return proofs[_holder][_proofId].amount; } /** * @dev date from which the proof is valid */ function proofDateFrom(address _holder, uint256 _proofId) public view returns (uint256) { return proofs[_holder][_proofId].dateFrom; } /** * @dev date until the proof is valid */ function proofDateTo(address _holder, uint256 _proofId) public view returns (uint256) { return proofs[_holder][_proofId].dateTo; } /** * @dev called to challenge a proof at a point in the past * Return the amount tokens owned by the proof owner at that time */ function checkProof(address _holder, uint256 _proofId, uint256 _at) public view returns (uint256) { if (_proofId < proofLengths[_holder]) { Proof storage proof = proofs[_holder][_proofId]; if (proof.dateFrom <= _at && _at <= proof.dateTo) { return proof.amount; } } return 0; } /** * @dev called to create a proof of token ownership */ function createProof(address _holder) public { createProofInternal( _holder, balanceOf(_holder), lastTransactionAt(_holder) ); } /** * @dev transfer function with also create a proof of ownership to any of the participants * @param _proofSender if true a proof will be created for the sender * @param _proofReceiver if true a proof will be created for the receiver */ function transferWithProofs( address _to, uint256 _value, bool _proofSender, bool _proofReceiver ) public returns (bool) { uint256 balanceBeforeFrom = balanceOf(msg.sender); uint256 beforeFrom = lastTransactionAt(msg.sender); uint256 balanceBeforeTo = balanceOf(_to); uint256 beforeTo = lastTransactionAt(_to); if (!super.transfer(_to, _value)) { return false; } transferPostProcessing( msg.sender, balanceBeforeFrom, beforeFrom, _proofSender ); transferPostProcessing( _to, balanceBeforeTo, beforeTo, _proofReceiver ); return true; } /** * @dev transfer function with also create a proof of ownership to any of the participants * @param _proofSender if true a proof will be created for the sender * @param _proofReceiver if true a proof will be created for the receiver */ function transferFromWithProofs( address _from, address _to, uint256 _value, bool _proofSender, bool _proofReceiver) public returns (bool) { uint256 balanceBeforeFrom = balanceOf(_from); uint256 beforeFrom = lastTransactionAt(_from); uint256 balanceBeforeTo = balanceOf(_to); uint256 beforeTo = lastTransactionAt(_to); if (!super.transferFrom(_from, _to, _value)) { return false; } transferPostProcessing( _from, balanceBeforeFrom, beforeFrom, _proofSender ); transferPostProcessing( _to, balanceBeforeTo, beforeTo, _proofReceiver ); return true; } /** * @dev can be used to force create a proof (with a fake amount potentially !) * Only usable by child contract internaly */ function createProofInternal( address _holder, uint256 _amount, uint256 _from) internal { uint proofId = proofLengths[_holder]; // solium-disable-next-line security/no-block-members proofs[_holder][proofId] = Proof(_amount, _from, currentTime()); proofLengths[_holder] = proofId+1; emit ProofOfOwnership(_holder, proofId); } /** * @dev private function updating contract state after a transfer operation */ function transferPostProcessing( address _holder, uint256 _balanceBefore, uint256 _before, bool _proof) private { if (_proof) { createProofInternal(_holder, _balanceBefore, _before); } } event ProofOfOwnership(address indexed holder, uint256 proofId); } // File: contracts/interface/IClaimable.sol /** * @title IClaimable * @dev IClaimable interface * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ interface IClaimable { function hasClaimsSince(address _address, uint256 at) external view returns (bool); } // File: contracts/interface/IWithClaims.sol /** * @title IWithClaims * @dev IWithClaims interface * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ contract IWithClaims { function claimableLength() public view returns (uint256); function claimable(uint256 _claimableId) public view returns (IClaimable); function hasClaims(address _holder) public view returns (bool); function defineClaimables(IClaimable[] _claimables) public; event ClaimablesDefined(uint256 count); } // File: contracts/token/component/TokenWithClaims.sol /** * @title TokenWithClaims * @dev TokenWithClaims contract * TokenWithClaims is a token that will create a * proofOfOwnership during transfers if a claim can be made. * Holder may ask for the claim later using the proofOfOwnership * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * * Error messages * E01: Claimable address must be defined * E02: Claimables parameter must not be empty * E03: Claimable does not exist **/ contract TokenWithClaims is IWithClaims, ProvableOwnershipToken { IClaimable[] claimables; /** * @dev Constructor */ constructor(IClaimable[] _claimables) public { claimables = _claimables; } /** * @dev Returns the number of claimables */ function claimableLength() public view returns (uint256) { return claimables.length; } /** * @dev Returns the Claimable associated to the specified claimableId */ function claimable(uint256 _claimableId) public view returns (IClaimable) { return claimables[_claimableId]; } /** * @dev Returns true if there are any claims associated to this token * to be made at this time for the _holder */ function hasClaims(address _holder) public view returns (bool) { uint256 lastTransaction = lastTransactionAt(_holder); for (uint256 i = 0; i < claimables.length; i++) { if (claimables[i].hasClaimsSince(_holder, lastTransaction)) { return true; } } return false; } /** * @dev Override the transfer function with transferWithProofs * A proof of ownership will be made if any claims can be made by the participants */ function transfer(address _to, uint256 _value) public returns (bool) { bool proofFrom = hasClaims(msg.sender); bool proofTo = hasClaims(_to); return super.transferWithProofs( _to, _value, proofFrom, proofTo ); } /** * @dev Override the transfer function with transferWithProofs * A proof of ownership will be made if any claims can be made by the participants */ function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { bool proofFrom = hasClaims(_from); bool proofTo = hasClaims(_to); return super.transferFromWithProofs( _from, _to, _value, proofFrom, proofTo ); } /** * @dev transfer with proofs */ function transferWithProofs( address _to, uint256 _value, bool _proofFrom, bool _proofTo ) public returns (bool) { bool proofFrom = _proofFrom || hasClaims(msg.sender); bool proofTo = _proofTo || hasClaims(_to); return super.transferWithProofs( _to, _value, proofFrom, proofTo ); } /** * @dev transfer from with proofs */ function transferFromWithProofs( address _from, address _to, uint256 _value, bool _proofFrom, bool _proofTo ) public returns (bool) { bool proofFrom = _proofFrom || hasClaims(_from); bool proofTo = _proofTo || hasClaims(_to); return super.transferFromWithProofs( _from, _to, _value, proofFrom, proofTo ); } /** * @dev define claimables contract to this token */ function defineClaimables(IClaimable[] _claimables) public onlyOwner { claimables = _claimables; emit ClaimablesDefined(claimables.length); } } // File: contracts/interface/IRule.sol /** * @title IRule * @dev IRule interface * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ interface IRule { function isAddressValid(address _address) external view returns (bool); function isTransferValid(address _from, address _to, uint256 _amount) external view returns (bool); } // File: contracts/interface/IWithRules.sol /** * @title IWithRules * @dev IWithRules interface * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ contract IWithRules { function ruleLength() public view returns (uint256); function rule(uint256 _ruleId) public view returns (IRule); function validateAddress(address _address) public view returns (bool); function validateTransfer(address _from, address _to, uint256 _amount) public view returns (bool); function defineRules(IRule[] _rules) public; event RulesDefined(uint256 count); } // File: contracts/rule/WithRules.sol /** * @title WithRules * @dev WithRules contract allows inheriting contract to use a set of validation rules * @dev contract owner may add or remove rules * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * * Error messages * WR01: The rules rejected this address * WR02: The rules rejected the transfer **/ contract WithRules is IWithRules, Ownable { IRule[] internal rules; /** * @dev Constructor */ constructor(IRule[] _rules) public { rules = _rules; } /** * @dev Returns the number of rules */ function ruleLength() public view returns (uint256) { return rules.length; } /** * @dev Returns the Rule associated to the specified ruleId */ function rule(uint256 _ruleId) public view returns (IRule) { return rules[_ruleId]; } /** * @dev Check if the rules are valid for an address */ function validateAddress(address _address) public view returns (bool) { for (uint256 i = 0; i < rules.length; i++) { if (!rules[i].isAddressValid(_address)) { return false; } } return true; } /** * @dev Check if the rules are valid */ function validateTransfer(address _from, address _to, uint256 _amount) public view returns (bool) { for (uint256 i = 0; i < rules.length; i++) { if (!rules[i].isTransferValid(_from, _to, _amount)) { return false; } } return true; } /** * @dev Modifier to make functions callable * only when participants follow rules */ modifier whenAddressRulesAreValid(address _address) { require(validateAddress(_address), "WR01"); _; } /** * @dev Modifier to make transfer functions callable * only when participants follow rules */ modifier whenTransferRulesAreValid( address _from, address _to, uint256 _amount) { require(validateTransfer(_from, _to, _amount), "WR02"); _; } /** * @dev Define rules to the token */ function defineRules(IRule[] _rules) public onlyOwner { rules = _rules; emit RulesDefined(rules.length); } } // File: contracts/token/component/TokenWithRules.sol /** * @title TokenWithRules * @dev TokenWithRules contract * TokenWithRules is a token that will apply * rules restricting transferability * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * **/ contract TokenWithRules is StandardToken, WithRules { /** * @dev Constructor */ constructor(IRule[] _rules) public WithRules(_rules) { } /** * @dev Overriden transfer function */ function transfer(address _to, uint256 _value) public whenTransferRulesAreValid(msg.sender, _to, _value) returns (bool) { return super.transfer(_to, _value); } /** * @dev Overriden transferFrom function */ function transferFrom(address _from, address _to, uint256 _value) public whenTransferRulesAreValid(_from, _to, _value) whenAddressRulesAreValid(msg.sender) returns (bool) { return super.transferFrom(_from, _to, _value); } } // File: contracts/token/BridgeToken.sol /** * @title BridgeToken * @dev BridgeToken contract * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. */ contract BridgeToken is TokenWithRules, TokenWithClaims, SeizableToken { string public name; string public symbol; /** * @dev constructor */ constructor(string _name, string _symbol) TokenWithRules(new IRule[](0)) TokenWithClaims(new IClaimable[](0)) public { name = _name; symbol = _symbol; } } // File: contracts/interface/IMintable.sol /** * @title Mintable interface * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. */ contract IMintable { function mintingFinished() public view returns (bool); function mint(address _to, uint256 _amount) public returns (bool); function finishMinting() public returns (bool); event Mint(address indexed to, uint256 amount); event MintFinished(); } // File: contracts/token/component/MintableToken.sol /** * @title MintableToken * @dev MintableToken contract * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * * Error messages * MT01: Minting is already finished. */ contract MintableToken is StandardToken, Ownable, IMintable { bool public mintingFinished = false; function mintingFinished() public view returns (bool) { return mintingFinished; } modifier canMint() { require(!mintingFinished, "MT01"); _; } /** * @dev Function to mint tokens * @param _to The address that will receive the minted tokens. * @param _amount The amount of tokens to mint. * @return A boolean that indicates if the operation was successful. */ function mint( address _to, uint256 _amount ) public canMint onlyOwner returns (bool) { totalSupply_ = totalSupply_.add(_amount); balances[_to] = balances[_to].add(_amount); emit Mint(_to, _amount); emit Transfer(address(0), _to, _amount); return true; } /** * @dev Function to stop minting new tokens. * @return True if the operation was successful. */ function finishMinting() public canMint onlyOwner returns (bool) { mintingFinished = true; emit MintFinished(); return true; } event Mint(address indexed to, uint256 amount); event MintFinished(); } // File: contracts/token/MintableBridgeToken.sol /** * @title MintableBridgeToken * @dev MintableBridgeToken contract * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. */ contract MintableBridgeToken is BridgeToken, MintableToken { string public name; string public symbol; /** * @dev constructor */ constructor(string _name, string _symbol) BridgeToken(_name, _symbol) public { name = _name; symbol = _symbol; } } // File: contracts/token/ShareBridgeToken.sol /** * @title ShareBridgeToken * @dev ShareBridgeToken contract * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. */ contract ShareBridgeToken is MintableBridgeToken { // Shares are non divisible assets uint256 public decimals = 0; /** * @dev constructor */ constructor(string _name, string _symbol) public MintableBridgeToken(_name, _symbol) { } } // File: contracts/mps/MPSToken.sol /** * @title MPSToken * @dev MPSToken contract * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. */ contract MPSToken is ShareBridgeToken { /** * @dev constructor */ constructor() public ShareBridgeToken("MtPelerin Shares", "MPS") { } }
File 4 of 7: FreezeRule
/** * FreezeRule.sol * Rule to restrict individual addresses from sending or receiving MPS tokens. * More info about MPS : https://github.com/MtPelerin/MtPelerin-share-MPS * The unflattened code is available through this github tag: * https://github.com/MtPelerin/MtPelerin-protocol/tree/etherscan-verify-batch-1 * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice All matters regarding the intellectual property of this code * @notice or software are subject to Swiss Law without reference to its * @notice conflicts of law rules. * @notice License for each contract is available in the respective file * @notice or in the LICENSE.md file. * @notice https://github.com/MtPelerin/ * @notice Code by OpenZeppelin is copyrighted and licensed on their repository: * @notice https://github.com/OpenZeppelin/openzeppelin-solidity */ pragma solidity ^0.4.24; // File: contracts/zeppelin/ownership/Ownable.sol /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address public owner; event OwnershipRenounced(address indexed previousOwner); event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor() 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 relinquish control of the contract. */ function renounceOwnership() public onlyOwner { emit OwnershipRenounced(owner); owner = address(0); } /** * @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 { _transferOwnership(_newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param _newOwner The address to transfer ownership to. */ function _transferOwnership(address _newOwner) internal { require(_newOwner != address(0)); emit OwnershipTransferred(owner, _newOwner); owner = _newOwner; } } // File: contracts/Authority.sol /** * @title Authority * @dev The Authority contract has an authority address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". * Authority means to represent a legal entity that is entitled to specific rights * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * * Error messages * AU01: Message sender must be an authority */ contract Authority is Ownable { address authority; /** * @dev Throws if called by any account other than the authority. */ modifier onlyAuthority { require(msg.sender == authority, "AU01"); _; } /** * @dev return the address associated to the authority */ function authorityAddress() public view returns (address) { return authority; } /** * @dev rdefines an authority * @param _name the authority name * @param _address the authority address. */ function defineAuthority(string _name, address _address) public onlyOwner { emit AuthorityDefined(_name, _address); authority = _address; } event AuthorityDefined( string name, address _address ); } // File: contracts/interface/IRule.sol /** * @title IRule * @dev IRule interface * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ interface IRule { function isAddressValid(address _address) external view returns (bool); function isTransferValid(address _from, address _to, uint256 _amount) external view returns (bool); } // File: contracts/rule/FreezeRule.sol /** * @title FreezeRule * @dev FreezeRule contract * This rule allow a legal authority to enforce a freeze of assets. * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * * Error messages * E01: The address is frozen */ contract FreezeRule is IRule, Authority { mapping(address => uint256) freezer; uint256 allFreezedUntil; /** * @dev is rule frozen */ function isFrozen() public view returns (bool) { // solium-disable-next-line security/no-block-members return allFreezedUntil > now ; } /** * @dev is address frozen */ function isAddressFrozen(address _address) public view returns (bool) { // solium-disable-next-line security/no-block-members return freezer[_address] > now; } /** * @dev allow authority to freeze the address * @param _until allows to auto unlock if the frozen time is known initially. * otherwise infinity can be used */ function freezeAddress(address _address, uint256 _until) public onlyAuthority returns (bool) { freezer[_address] = _until; emit Freeze(_address, _until); } /** * @dev allow authority to freeze several addresses * @param _until allows to auto unlock if the frozen time is known initially. * otherwise infinity can be used */ function freezeManyAddresses(address[] _addresses, uint256 _until) public onlyAuthority returns (bool) { for (uint256 i = 0; i < _addresses.length; i++) { freezer[_addresses[i]] = _until; emit Freeze(_addresses[i], _until); } } /** * @dev freeze all until */ function freezeAll(uint256 _until) public onlyAuthority returns (bool) { allFreezedUntil = _until; emit FreezeAll(_until); } /** * @dev validates an address */ function isAddressValid(address _address) public view returns (bool) { return !isFrozen() && !isAddressFrozen(_address); } /** * @dev validates a transfer */ function isTransferValid(address _from, address _to, uint256 /* _amount */) public view returns (bool) { return !isFrozen() && (!isAddressFrozen(_from) && !isAddressFrozen(_to)); } event FreezeAll(uint256 until); event Freeze(address _address, uint256 until); }
File 5 of 7: LockRule
/** * LockRule.sol * Rule to lock all tokens on a schedule and define a whitelist of exceptions. * More info about MPS : https://github.com/MtPelerin/MtPelerin-share-MPS * The unflattened code is available through this github tag: * https://github.com/MtPelerin/MtPelerin-protocol/tree/etherscan-verify-batch-2 * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice All matters regarding the intellectual property of this code * @notice or software are subject to Swiss Law without reference to its * @notice conflicts of law rules. * @notice License for each contract is available in the respective file * @notice or in the LICENSE.md file. * @notice https://github.com/MtPelerin/ * @notice Code by OpenZeppelin is copyrighted and licensed on their repository: * @notice https://github.com/OpenZeppelin/openzeppelin-solidity */ pragma solidity ^0.4.24; // File: contracts/zeppelin/ownership/Ownable.sol /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address public owner; event OwnershipRenounced(address indexed previousOwner); event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor() 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 relinquish control of the contract. */ function renounceOwnership() public onlyOwner { emit OwnershipRenounced(owner); owner = address(0); } /** * @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 { _transferOwnership(_newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param _newOwner The address to transfer ownership to. */ function _transferOwnership(address _newOwner) internal { require(_newOwner != address(0)); emit OwnershipTransferred(owner, _newOwner); owner = _newOwner; } } // File: contracts/Authority.sol /** * @title Authority * @dev The Authority contract has an authority address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". * Authority means to represent a legal entity that is entitled to specific rights * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * * Error messages * AU01: Message sender must be an authority */ contract Authority is Ownable { address authority; /** * @dev Throws if called by any account other than the authority. */ modifier onlyAuthority { require(msg.sender == authority, "AU01"); _; } /** * @dev Returns the address associated to the authority */ function authorityAddress() public view returns (address) { return authority; } /** Define an address as authority, with an arbitrary name included in the event * @dev returns the authority of the * @param _name the authority name * @param _address the authority address. */ function defineAuthority(string _name, address _address) public onlyOwner { emit AuthorityDefined(_name, _address); authority = _address; } event AuthorityDefined( string name, address _address ); } // File: contracts/interface/IRule.sol /** * @title IRule * @dev IRule interface * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. **/ interface IRule { function isAddressValid(address _address) external view returns (bool); function isTransferValid(address _from, address _to, uint256 _amount) external view returns (bool); } // File: contracts/rule/LockRule.sol /** * @title LockRule * @dev LockRule contract * This rule allow to lock assets for a period of time * for event such as investment vesting * * @author Cyril Lapinte - <[email protected]> * * @notice Copyright © 2016 - 2018 Mt Pelerin Group SA - All Rights Reserved * @notice Please refer to the top of this file for the license. * * Error messages * LOR01: definePass() call have failed * LOR02: startAt must be before or equal to endAt */ contract LockRule is IRule, Authority { enum Direction { NONE, RECEIVE, SEND, BOTH } struct ScheduledLock { Direction restriction; uint256 startAt; uint256 endAt; bool scheduleInverted; } mapping(address => Direction) individualPasses; ScheduledLock lock = ScheduledLock( Direction.NONE, 0, 0, false ); /** * @dev hasSendDirection */ function hasSendDirection(Direction _direction) public pure returns (bool) { return _direction == Direction.SEND || _direction == Direction.BOTH; } /** * @dev hasReceiveDirection */ function hasReceiveDirection(Direction _direction) public pure returns (bool) { return _direction == Direction.RECEIVE || _direction == Direction.BOTH; } /** * @dev restriction */ function restriction() public view returns (Direction) { return lock.restriction; } /** * @dev scheduledStartAt */ function scheduledStartAt() public view returns (uint256) { return lock.startAt; } /** * @dev scheduledEndAt */ function scheduledEndAt() public view returns (uint256) { return lock.endAt; } /** * @dev lock inverted */ function isScheduleInverted() public view returns (bool) { return lock.scheduleInverted; } /** * @dev isLocked */ function isLocked() public view returns (bool) { // solium-disable-next-line security/no-block-members return (lock.startAt <= now && lock.endAt > now) ? !lock.scheduleInverted : lock.scheduleInverted; } /** * @dev individualPass */ function individualPass(address _address) public view returns (Direction) { return individualPasses[_address]; } /** * @dev can the address send */ function canSend(address _address) public view returns (bool) { if (isLocked() && hasSendDirection(lock.restriction)) { return hasSendDirection(individualPasses[_address]); } return true; } /** * @dev can the address receive */ function canReceive(address _address) public view returns (bool) { if (isLocked() && hasReceiveDirection(lock.restriction)) { return hasReceiveDirection(individualPasses[_address]); } return true; } /** * @dev allow authority to provide a pass to an address */ function definePass(address _address, uint256 _lock) public onlyAuthority returns (bool) { individualPasses[_address] = Direction(_lock); emit PassDefinition(_address, Direction(_lock)); return true; } /** * @dev allow authority to provide addresses with lock passes */ function defineManyPasses(address[] _addresses, uint256 _lock) public onlyAuthority returns (bool) { for (uint256 i = 0; i < _addresses.length; i++) { require(definePass(_addresses[i], _lock), "LOR01"); } return true; } /** * @dev schedule lock */ function scheduleLock( Direction _restriction, uint256 _startAt, uint256 _endAt, bool _scheduleInverted) public onlyAuthority returns (bool) { require(_startAt <= _endAt, "LOR02"); lock = ScheduledLock( _restriction, _startAt, _endAt, _scheduleInverted ); emit LockDefinition( lock.restriction, lock.startAt, lock.endAt, lock.scheduleInverted); } /** * @dev validates an address */ function isAddressValid(address /*_address*/) public view returns (bool) { return true; } /** * @dev validates a transfer of ownership */ function isTransferValid(address _from, address _to, uint256 /* _amount */) public view returns (bool) { return (canSend(_from) && canReceive(_to)); } event LockDefinition( Direction restriction, uint256 startAt, uint256 endAt, bool scheduleInverted ); event PassDefinition(address _address, Direction pass); }
File 6 of 7: EternalStorageProxy
// 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: openzeppelin-solidity/contracts/AddressUtils.sol pragma solidity ^0.4.24; /** * Utility library of inline functions on addresses */ library AddressUtils { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param _addr address to check * @return whether the target address is a contract */ function isContract(address _addr) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solium-disable-next-line security/no-inline-assembly assembly { size := extcodesize(_addr) } return size > 0; } } // File: contracts/upgradeability/Proxy.sol pragma solidity 0.4.24; /** * @title Proxy * @dev Gives the possibility to delegate any call to a foreign implementation. */ contract Proxy { /** * @dev Tells the address of the implementation where every call will be delegated. * @return address of the implementation to which it will be delegated */ /* solcov ignore next */ function implementation() public view returns (address); /** * @dev Fallback function allowing to perform a delegatecall to the given implementation. * This function will return whatever the implementation call returns */ function() public payable { // solhint-disable-previous-line no-complex-fallback address _impl = implementation(); require(_impl != address(0)); assembly { /* 0x40 is the "free memory slot", meaning a pointer to next slot of empty memory. mload(0x40) loads the data in the free memory slot, so `ptr` is a pointer to the next slot of empty memory. It's needed because we're going to write the return data of delegatecall to the free memory slot. */ let ptr := mload(0x40) /* `calldatacopy` is copy calldatasize bytes from calldata First argument is the destination to which data is copied(ptr) Second argument specifies the start position of the copied data. Since calldata is sort of its own unique location in memory, 0 doesn't refer to 0 in memory or 0 in storage - it just refers to the zeroth byte of calldata. That's always going to be the zeroth byte of the function selector. Third argument, calldatasize, specifies how much data will be copied. calldata is naturally calldatasize bytes long (same thing as msg.data.length) */ calldatacopy(ptr, 0, calldatasize) /* delegatecall params explained: gas: the amount of gas to provide for the call. `gas` is an Opcode that gives us the amount of gas still available to execution _impl: address of the contract to delegate to ptr: to pass copied data calldatasize: loads the size of `bytes memory data`, same as msg.data.length 0, 0: These are for the `out` and `outsize` params. Because the output could be dynamic, these are set to 0, 0 so the output data will not be written to memory. The output data will be read using `returndatasize` and `returdatacopy` instead. result: This will be 0 if the call fails and 1 if it succeeds */ let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0) /* */ /* ptr current points to the value stored at 0x40, because we assigned it like ptr := mload(0x40). Because we use 0x40 as a free memory pointer, we want to make sure that the next time we want to allocate memory, we aren't overwriting anything important. So, by adding ptr and returndatasize, we get a memory location beyond the end of the data we will be copying to ptr. We place this in at 0x40, and any reads from 0x40 will now read from free memory */ mstore(0x40, add(ptr, returndatasize)) /* `returndatacopy` is an Opcode that copies the last return data to a slot. `ptr` is the slot it will copy to, 0 means copy from the beginning of the return data, and size is the amount of data to copy. `returndatasize` is an Opcode that gives us the size of the last return data. In this case, that is the size of the data returned from delegatecall */ returndatacopy(ptr, 0, returndatasize) /* if `result` is 0, revert. if `result` is 1, return `size` amount of data from `ptr`. This is the data that was copied to `ptr` from the delegatecall return data */ switch result case 0 { revert(ptr, returndatasize) } default { return(ptr, returndatasize) } } } } // File: contracts/upgradeability/UpgradeabilityStorage.sol pragma solidity 0.4.24; /** * @title UpgradeabilityStorage * @dev This contract holds all the necessary state variables to support the upgrade functionality */ contract UpgradeabilityStorage { // Version name of the current implementation uint256 internal _version; // Address of the current implementation address internal _implementation; /** * @dev Tells the version name of the current implementation * @return uint256 representing the name of the current version */ function version() external view returns (uint256) { 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/UpgradeabilityProxy.sol pragma solidity 0.4.24; /** * @title UpgradeabilityProxy * @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded */ contract UpgradeabilityProxy is Proxy, UpgradeabilityStorage { /** * @dev This event will be emitted every time the implementation gets upgraded * @param version representing the version name of the upgraded implementation * @param implementation representing the address of the upgraded implementation */ event Upgraded(uint256 version, address indexed implementation); /** * @dev Upgrades the implementation address * @param version representing the version name of the new implementation to be set * @param implementation representing the address of the new implementation to be set */ function _upgradeTo(uint256 version, address implementation) internal { require(_implementation != implementation); // This additional check verifies that provided implementation is at least a contract require(AddressUtils.isContract(implementation)); // This additional check guarantees that new version will be at least greater than the privios one, // so it is impossible to reuse old versions, or use the last version twice require(version > _version); _version = version; _implementation = implementation; emit Upgraded(version, implementation); } } // File: contracts/upgradeability/UpgradeabilityOwnerStorage.sol pragma solidity 0.4.24; /** * @title UpgradeabilityOwnerStorage * @dev This contract keeps track of the upgradeability owner */ contract UpgradeabilityOwnerStorage { // Owner of the contract address internal _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/OwnedUpgradeabilityProxy.sol pragma solidity 0.4.24; /** * @title OwnedUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with basic authorization control functionalities */ contract OwnedUpgradeabilityProxy is UpgradeabilityOwnerStorage, UpgradeabilityProxy { /** * @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 ProxyOwnershipTransferred(address previousOwner, address newOwner); /** * @dev the constructor sets the original owner of the contract to the sender account. */ constructor() public { setUpgradeabilityOwner(msg.sender); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyUpgradeabilityOwner() { require(msg.sender == upgradeabilityOwner()); /* solcov ignore next */ _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferProxyOwnership(address newOwner) external onlyUpgradeabilityOwner { require(newOwner != address(0)); emit ProxyOwnershipTransferred(upgradeabilityOwner(), newOwner); setUpgradeabilityOwner(newOwner); } /** * @dev Allows the upgradeability owner to upgrade the current version of the proxy. * @param version representing the version name of the new implementation to be set. * @param implementation representing the address of the new implementation to be set. */ function upgradeTo(uint256 version, address implementation) public onlyUpgradeabilityOwner { _upgradeTo(version, implementation); } /** * @dev Allows the upgradeability owner to upgrade the current version of the proxy and call the new implementation * to initialize whatever is needed through a low level call. * @param version representing the version name of the new implementation to be set. * @param implementation representing the address of the new implementation to be set. * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function * signature of the implementation to be called with the needed payload */ function upgradeToAndCall(uint256 version, address implementation, bytes data) external payable onlyUpgradeabilityOwner { upgradeTo(version, implementation); // solhint-disable-next-line avoid-call-value require(address(this).call.value(msg.value)(data)); } } // File: contracts/upgradeability/EternalStorageProxy.sol pragma solidity 0.4.24; /** * @title EternalStorageProxy * @dev This proxy holds the storage of the token contract and delegates every call to the current implementation set. * Besides, it allows to upgrade the token's behaviour towards further implementations, and provides basic * authorization control functionalities */ // solhint-disable-next-line no-empty-blocks contract EternalStorageProxy is EternalStorage, OwnedUpgradeabilityProxy {}
File 7 of 7: ForeignAMB
// File: contracts/interfaces/IBridgeValidators.sol pragma solidity 0.4.24; interface IBridgeValidators { function isValidator(address _validator) external view returns (bool); function requiredSignatures() external view returns (uint256); function owner() external view returns (address); } // File: contracts/libraries/Message.sol pragma solidity 0.4.24; library Message { function addressArrayContains(address[] array, address value) internal pure returns (bool) { for (uint256 i = 0; i < array.length; i++) { if (array[i] == value) { return true; } } return false; } // layout of message :: bytes: // offset 0: 32 bytes :: uint256 - message length // offset 32: 20 bytes :: address - recipient address // offset 52: 32 bytes :: uint256 - value // offset 84: 32 bytes :: bytes32 - transaction hash // offset 116: 20 bytes :: address - contract address to prevent double spending // mload always reads 32 bytes. // so we can and have to start reading recipient at offset 20 instead of 32. // if we were to read at 32 the address would contain part of value and be corrupted. // when reading from offset 20 mload will read 12 bytes (most of them zeros) followed // by the 20 recipient address bytes and correctly convert it into an address. // this saves some storage/gas over the alternative solution // which is padding address to 32 bytes and reading recipient at offset 32. // for more details see discussion in: // https://github.com/paritytech/parity-bridge/issues/61 function parseMessage(bytes message) internal pure returns (address recipient, uint256 amount, bytes32 txHash, address contractAddress) { require(isMessageValid(message)); assembly { recipient := mload(add(message, 20)) amount := mload(add(message, 52)) txHash := mload(add(message, 84)) contractAddress := mload(add(message, 104)) } } function isMessageValid(bytes _msg) internal pure returns (bool) { return _msg.length == requiredMessageLength(); } function requiredMessageLength() internal pure returns (uint256) { return 104; } function recoverAddressFromSignedMessage(bytes signature, bytes message, bool isAMBMessage) internal pure returns (address) { require(signature.length == 65); bytes32 r; bytes32 s; bytes1 v; assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := mload(add(signature, 0x60)) } require(uint8(v) == 27 || uint8(v) == 28); require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0); return ecrecover(hashMessage(message, isAMBMessage), uint8(v), r, s); } function hashMessage(bytes message, bool isAMBMessage) internal pure returns (bytes32) { bytes memory prefix = "\x19Ethereum Signed Message:\n"; if (isAMBMessage) { return keccak256(abi.encodePacked(prefix, uintToString(message.length), message)); } else { string memory msgLength = "104"; return keccak256(abi.encodePacked(prefix, msgLength, message)); } } /** * @dev Validates provided signatures, only first requiredSignatures() number * of signatures are going to be validated, these signatures should be from different validators. * @param _message bytes message used to generate signatures * @param _signatures bytes blob with signatures to be validated. * First byte X is a number of signatures in a blob, * next X bytes are v components of signatures, * next 32 * X bytes are r components of signatures, * next 32 * X bytes are s components of signatures. * @param _validatorContract contract, which conforms to the IBridgeValidators interface, * where info about current validators and required signatures is stored. * @param isAMBMessage true if _message is an AMB message with arbitrary length. */ function hasEnoughValidSignatures( bytes _message, bytes _signatures, IBridgeValidators _validatorContract, bool isAMBMessage ) internal view { require(isAMBMessage || isMessageValid(_message)); uint256 requiredSignatures = _validatorContract.requiredSignatures(); uint256 amount; assembly { amount := and(mload(add(_signatures, 1)), 0xff) } require(amount >= requiredSignatures); bytes32 hash = hashMessage(_message, isAMBMessage); address[] memory encounteredAddresses = new address[](requiredSignatures); for (uint256 i = 0; i < requiredSignatures; i++) { uint8 v; bytes32 r; bytes32 s; uint256 posr = 33 + amount + 32 * i; uint256 poss = posr + 32 * amount; assembly { v := mload(add(_signatures, add(2, i))) r := mload(add(_signatures, posr)) s := mload(add(_signatures, poss)) } address recoveredAddress = ecrecover(hash, v, r, s); require(_validatorContract.isValidator(recoveredAddress)); require(!addressArrayContains(encounteredAddresses, recoveredAddress)); encounteredAddresses[i] = recoveredAddress; } } function uintToString(uint256 i) internal pure returns (string) { if (i == 0) return "0"; uint256 j = i; uint256 length; while (j != 0) { length++; j /= 10; } bytes memory bstr = new bytes(length); uint256 k = length - 1; while (i != 0) { bstr[k--] = bytes1(48 + (i % 10)); i /= 10; } return string(bstr); } } // File: contracts/libraries/ArbitraryMessage.sol pragma solidity 0.4.24; library ArbitraryMessage { /** * @dev Unpacks data fields from AMB message * layout of message :: bytes: * offset 0 : 32 bytes :: uint256 - message length * offset 32 : 32 bytes :: bytes32 - messageId * offset 64 : 20 bytes :: address - sender address * offset 84 : 20 bytes :: address - executor contract * offset 104 : 4 bytes :: uint32 - gasLimit * offset 108 : 1 bytes :: uint8 - source chain id length (X) * offset 109 : 1 bytes :: uint8 - destination chain id length (Y) * offset 110 : 1 bytes :: uint8 - dataType * offset 111 : X bytes :: bytes - source chain id * offset 111 + X : Y bytes :: bytes - destination chain id * NOTE: when message structure is changed, make sure that MESSAGE_PACKING_VERSION from VersionableAMB is updated as well * NOTE: assembly code uses calldatacopy, make sure that message is passed as the first argument in the calldata * @param _data encoded message */ function unpackData(bytes _data) internal pure returns ( bytes32 messageId, address sender, address executor, uint32 gasLimit, uint8 dataType, uint256[2] chainIds, bytes memory data ) { // 32 (message id) + 20 (sender) + 20 (executor) + 4 (gasLimit) + 1 (source chain id length) + 1 (destination chain id length) + 1 (dataType) uint256 srcdataptr = 32 + 20 + 20 + 4 + 1 + 1 + 1; uint256 datasize; assembly { messageId := mload(add(_data, 32)) // 32 bytes sender := and(mload(add(_data, 52)), 0xffffffffffffffffffffffffffffffffffffffff) // 20 bytes // executor (20 bytes) + gasLimit (4 bytes) + srcChainIdLength (1 byte) + dstChainIdLength (1 bytes) + dataType (1 byte) + remainder (5 bytes) let blob := mload(add(_data, 84)) // after bit shift left 12 bytes are zeros automatically executor := shr(96, blob) gasLimit := and(shr(64, blob), 0xffffffff) dataType := byte(26, blob) // load source chain id length let chainIdLength := byte(24, blob) // at this moment srcdataptr points to sourceChainId // mask for sourceChainId // e.g. length X -> (1 << (X * 8)) - 1 let mask := sub(shl(shl(3, chainIdLength), 1), 1) // increase payload offset by length of source chain id srcdataptr := add(srcdataptr, chainIdLength) // write sourceChainId mstore(chainIds, and(mload(add(_data, srcdataptr)), mask)) // at this moment srcdataptr points to destinationChainId // load destination chain id length chainIdLength := byte(25, blob) // mask for destinationChainId // e.g. length X -> (1 << (X * 8)) - 1 mask := sub(shl(shl(3, chainIdLength), 1), 1) // increase payload offset by length of destination chain id srcdataptr := add(srcdataptr, chainIdLength) // write destinationChainId mstore(add(chainIds, 32), and(mload(add(_data, srcdataptr)), mask)) // at this moment srcdataptr points to payload // datasize = message length - payload offset datasize := sub(mload(_data), srcdataptr) } data = new bytes(datasize); assembly { // 36 = 4 (selector) + 32 (bytes length header) srcdataptr := add(srcdataptr, 36) // calldataload(4) - offset of first bytes argument in the calldata calldatacopy(add(data, 32), add(calldataload(4), srcdataptr), datasize) } } } // File: contracts/interfaces/IUpgradeabilityOwnerStorage.sol pragma solidity 0.4.24; interface IUpgradeabilityOwnerStorage { function upgradeabilityOwner() external view returns (address); } // File: contracts/upgradeable_contracts/Upgradeable.sol pragma solidity 0.4.24; contract Upgradeable { // Avoid using onlyUpgradeabilityOwner name to prevent issues with implementation from proxy contract modifier onlyIfUpgradeabilityOwner() { require(msg.sender == IUpgradeabilityOwnerStorage(this).upgradeabilityOwner()); /* solcov ignore next */ _; } } // 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/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: openzeppelin-solidity/contracts/AddressUtils.sol pragma solidity ^0.4.24; /** * Utility library of inline functions on addresses */ library AddressUtils { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param _addr address to check * @return whether the target address is a contract */ function isContract(address _addr) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solium-disable-next-line security/no-inline-assembly assembly { size := extcodesize(_addr) } return size > 0; } } // File: contracts/upgradeable_contracts/ValidatorStorage.sol pragma solidity 0.4.24; contract ValidatorStorage { bytes32 internal constant VALIDATOR_CONTRACT = 0x5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe; // keccak256(abi.encodePacked("validatorContract")) } // File: contracts/upgradeable_contracts/Validatable.sol pragma solidity 0.4.24; contract Validatable is EternalStorage, ValidatorStorage { function validatorContract() public view returns (IBridgeValidators) { return IBridgeValidators(addressStorage[VALIDATOR_CONTRACT]); } modifier onlyValidator() { require(validatorContract().isValidator(msg.sender)); /* solcov ignore next */ _; } function requiredSignatures() public view returns (uint256) { return validatorContract().requiredSignatures(); } } // 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 { bytes4 internal constant UPGRADEABILITY_OWNER = 0x6fde8202; // upgradeabilityOwner() /** * @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 */ _; } /** * @dev Throws if called by any account other than contract itself or owner. */ modifier onlyRelevantSender() { // proxy owner if used through proxy, address(0) otherwise require( !address(this).call(abi.encodeWithSelector(UPGRADEABILITY_OWNER)) || // covers usage without calling through storage proxy msg.sender == IUpgradeabilityOwnerStorage(this).upgradeabilityOwner() || // covers usage through regular proxy calls msg.sender == address(this) // covers calls through upgradeAndCall proxy method ); /* 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 { _setOwner(newOwner); } /** * @dev Sets a new owner address */ function _setOwner(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(owner(), newOwner); addressStorage[OWNER] = newOwner; } } // File: contracts/upgradeable_contracts/Sacrifice.sol pragma solidity 0.4.24; contract Sacrifice { constructor(address _recipient) public payable { selfdestruct(_recipient); } } // File: contracts/libraries/Address.sol pragma solidity 0.4.24; /** * @title Address * @dev Helper methods for Address type. */ library Address { /** * @dev Try to send native tokens to the address. If it fails, it will force the transfer by creating a selfdestruct contract * @param _receiver address that will receive the native tokens * @param _value the amount of native tokens to send */ function safeSendValue(address _receiver, uint256 _value) internal { if (!_receiver.send(_value)) { (new Sacrifice).value(_value)(_receiver); } } } // 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: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol pragma solidity ^0.4.24; /** * @title ERC20Basic * @dev Simpler version of ERC20 interface * See https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol pragma solidity ^0.4.24; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { function allowance(address _owner, address _spender) public view returns (uint256); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: contracts/interfaces/ERC677.sol pragma solidity 0.4.24; contract ERC677 is ERC20 { event Transfer(address indexed from, address indexed to, uint256 value, bytes data); function transferAndCall(address, uint256, bytes) external returns (bool); function increaseAllowance(address spender, uint256 addedValue) public returns (bool); function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool); } contract LegacyERC20 { function transfer(address _spender, uint256 _value) public; // returns (bool); function transferFrom(address _owner, address _spender, uint256 _value) public; // returns (bool); } // File: contracts/libraries/SafeERC20.sol pragma solidity 0.4.24; /** * @title SafeERC20 * @dev Helper methods for safe token transfers. * Functions perform additional checks to be sure that token transfer really happened. */ library SafeERC20 { using SafeMath for uint256; /** * @dev Same as ERC20.transfer(address,uint256) but with extra consistency checks. * @param _token address of the token contract * @param _to address of the receiver * @param _value amount of tokens to send */ function safeTransfer(address _token, address _to, uint256 _value) internal { LegacyERC20(_token).transfer(_to, _value); assembly { if returndatasize { returndatacopy(0, 0, 32) if iszero(mload(0)) { revert(0, 0) } } } } /** * @dev Same as ERC20.transferFrom(address,address,uint256) but with extra consistency checks. * @param _token address of the token contract * @param _from address of the sender * @param _value amount of tokens to send */ function safeTransferFrom(address _token, address _from, uint256 _value) internal { LegacyERC20(_token).transferFrom(_from, address(this), _value); assembly { if returndatasize { returndatacopy(0, 0, 32) if iszero(mload(0)) { revert(0, 0) } } } } } // File: contracts/upgradeable_contracts/Claimable.sol pragma solidity 0.4.24; /** * @title Claimable * @dev Implementation of the claiming utils that can be useful for withdrawing accidentally sent tokens that are not used in bridge operations. */ contract Claimable { using SafeERC20 for address; /** * Throws if a given address is equal to address(0) */ modifier validAddress(address _to) { require(_to != address(0)); /* solcov ignore next */ _; } /** * @dev Withdraws the erc20 tokens or native coins from this contract. * Caller should additionally check that the claimed token is not a part of bridge operations (i.e. that token != erc20token()). * @param _token address of the claimed token or address(0) for native coins. * @param _to address of the tokens/coins receiver. */ function claimValues(address _token, address _to) internal validAddress(_to) { if (_token == address(0)) { claimNativeCoins(_to); } else { claimErc20Tokens(_token, _to); } } /** * @dev Internal function for withdrawing all native coins from the contract. * @param _to address of the coins receiver. */ function claimNativeCoins(address _to) internal { uint256 value = address(this).balance; Address.safeSendValue(_to, value); } /** * @dev Internal function for withdrawing all tokens of ssome particular ERC20 contract from this contract. * @param _token address of the claimed ERC20 token. * @param _to address of the tokens receiver. */ function claimErc20Tokens(address _token, address _to) internal { ERC20Basic token = ERC20Basic(_token); uint256 balance = token.balanceOf(this); _token.safeTransfer(_to, balance); } } // File: contracts/upgradeable_contracts/VersionableBridge.sol pragma solidity 0.4.24; contract VersionableBridge { function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) { return (6, 1, 0); } /* solcov ignore next */ function getBridgeMode() external pure returns (bytes4); } // File: contracts/upgradeable_contracts/DecimalShiftBridge.sol pragma solidity 0.4.24; contract DecimalShiftBridge is EternalStorage { using SafeMath for uint256; bytes32 internal constant DECIMAL_SHIFT = 0x1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee5; // keccak256(abi.encodePacked("decimalShift")) /** * @dev Internal function for setting the decimal shift for bridge operations. * Decimal shift can be positive, negative, or equal to zero. * It has the following meaning: N tokens in the foreign chain are equivalent to N * pow(10, shift) tokens on the home side. * @param _shift new value of decimal shift. */ function _setDecimalShift(int256 _shift) internal { // since 1 wei * 10**77 > 2**255, it does not make any sense to use higher values require(_shift > -77 && _shift < 77); uintStorage[DECIMAL_SHIFT] = uint256(_shift); } /** * @dev Returns the value of foreign-to-home decimal shift. * @return decimal shift. */ function decimalShift() public view returns (int256) { return int256(uintStorage[DECIMAL_SHIFT]); } /** * @dev Converts the amount of home tokens into the equivalent amount of foreign tokens. * @param _value amount of home tokens. * @return equivalent amount of foreign tokens. */ function _unshiftValue(uint256 _value) internal view returns (uint256) { return _shiftUint(_value, -decimalShift()); } /** * @dev Converts the amount of foreign tokens into the equivalent amount of home tokens. * @param _value amount of foreign tokens. * @return equivalent amount of home tokens. */ function _shiftValue(uint256 _value) internal view returns (uint256) { return _shiftUint(_value, decimalShift()); } /** * @dev Calculates _value * pow(10, _shift). * @param _value amount of tokens. * @param _shift decimal shift to apply. * @return shifted value. */ function _shiftUint(uint256 _value, int256 _shift) private pure returns (uint256) { if (_shift == 0) { return _value; } if (_shift > 0) { return _value.mul(10**uint256(_shift)); } return _value.div(10**uint256(-_shift)); } } // File: contracts/upgradeable_contracts/BasicBridge.sol pragma solidity 0.4.24; contract BasicBridge is InitializableBridge, Validatable, Ownable, Upgradeable, Claimable, VersionableBridge, DecimalShiftBridge { event GasPriceChanged(uint256 gasPrice); event RequiredBlockConfirmationChanged(uint256 requiredBlockConfirmations); bytes32 internal constant GAS_PRICE = 0x55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b; // keccak256(abi.encodePacked("gasPrice")) bytes32 internal constant REQUIRED_BLOCK_CONFIRMATIONS = 0x916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071; // keccak256(abi.encodePacked("requiredBlockConfirmations")) /** * @dev Public setter for fallback gas price value. Only bridge owner can call this method. * @param _gasPrice new value for the gas price. */ function setGasPrice(uint256 _gasPrice) external onlyOwner { _setGasPrice(_gasPrice); } function gasPrice() external view returns (uint256) { return uintStorage[GAS_PRICE]; } function setRequiredBlockConfirmations(uint256 _blockConfirmations) external onlyOwner { _setRequiredBlockConfirmations(_blockConfirmations); } function _setRequiredBlockConfirmations(uint256 _blockConfirmations) internal { require(_blockConfirmations > 0); uintStorage[REQUIRED_BLOCK_CONFIRMATIONS] = _blockConfirmations; emit RequiredBlockConfirmationChanged(_blockConfirmations); } function requiredBlockConfirmations() external view returns (uint256) { return uintStorage[REQUIRED_BLOCK_CONFIRMATIONS]; } /** * @dev Internal function for updating fallback gas price value. * @param _gasPrice new value for the gas price, zero gas price is allowed. */ function _setGasPrice(uint256 _gasPrice) internal { uintStorage[GAS_PRICE] = _gasPrice; emit GasPriceChanged(_gasPrice); } } // File: contracts/upgradeable_contracts/arbitrary_message/VersionableAMB.sol pragma solidity 0.4.24; contract VersionableAMB is VersionableBridge { // message format version as a single 4-bytes number padded to 32-bytes // value, included into every outgoing relay request // // the message version should be updated every time when // - new field appears // - some field removed // - fields order is changed bytes32 internal constant MESSAGE_PACKING_VERSION = 0x00050000 << 224; /** * Returns currently used bridge version * @return (major, minor, patch) version triple */ function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) { return (6, 2, 0); } } // File: contracts/upgradeable_contracts/arbitrary_message/BasicAMB.sol pragma solidity 0.4.24; 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(); } } // File: contracts/libraries/Bytes.sol pragma solidity 0.4.24; /** * @title Bytes * @dev Helper methods to transform bytes to other solidity types. */ library Bytes { /** * @dev Converts bytes array to bytes32. * Truncates bytes array if its size is more than 32 bytes. * NOTE: This function does not perform any checks on the received parameter. * Make sure that the _bytes argument has a correct length, not less than 32 bytes. * A case when _bytes has length less than 32 will lead to the undefined behaviour, * since assembly will read data from memory that is not related to the _bytes argument. * @param _bytes to be converted to bytes32 type * @return bytes32 type of the firsts 32 bytes array in parameter. */ function bytesToBytes32(bytes _bytes) internal pure returns (bytes32 result) { assembly { result := mload(add(_bytes, 32)) } } /** * @dev Truncate bytes array if its size is more than 20 bytes. * NOTE: Similar to the bytesToBytes32 function, make sure that _bytes is not shorter than 20 bytes. * @param _bytes to be converted to address type * @return address included in the firsts 20 bytes of the bytes array in parameter. */ function bytesToAddress(bytes _bytes) internal pure returns (address addr) { assembly { addr := mload(add(_bytes, 20)) } } } // File: contracts/upgradeable_contracts/arbitrary_message/MessageProcessor.sol pragma solidity 0.4.24; contract MessageProcessor is EternalStorage { /** * @dev Returns a status of the message that came from the other side. * @param _messageId id of the message from the other side that triggered a call. * @return true if call executed successfully. */ function messageCallStatus(bytes32 _messageId) external view returns (bool) { return boolStorage[keccak256(abi.encodePacked("messageCallStatus", _messageId))]; } /** * @dev Sets a status of the message that came from the other side. * @param _messageId id of the message from the other side that triggered a call. * @param _status execution status, true if executed successfully. */ function setMessageCallStatus(bytes32 _messageId, bool _status) internal { boolStorage[keccak256(abi.encodePacked("messageCallStatus", _messageId))] = _status; } /** * @dev Returns a data hash of the failed message that came from the other side. * NOTE: dataHash was used previously to identify outgoing message before AMB message id was introduced. * It is kept for backwards compatibility with old mediators contracts. * @param _messageId id of the message from the other side that triggered a call. * @return keccak256 hash of message data. */ function failedMessageDataHash(bytes32 _messageId) external view returns (bytes32) { return bytes32(uintStorage[keccak256(abi.encodePacked("failedMessageDataHash", _messageId))]); } /** * @dev Sets a data hash of the failed message that came from the other side. * NOTE: dataHash was used previously to identify outgoing message before AMB message id was introduced. * It is kept for backwards compatibility with old mediators contracts. * @param _messageId id of the message from the other side that triggered a call. * @param data of the processed message. */ function setFailedMessageDataHash(bytes32 _messageId, bytes data) internal { uintStorage[keccak256(abi.encodePacked("failedMessageDataHash", _messageId))] = uint256(keccak256(data)); } /** * @dev Returns a receiver address of the failed message that came from the other side. * @param _messageId id of the message from the other side that triggered a call. * @return receiver address. */ function failedMessageReceiver(bytes32 _messageId) external view returns (address) { return addressStorage[keccak256(abi.encodePacked("failedMessageReceiver", _messageId))]; } /** * @dev Sets a sender address of the failed message that came from the other side. * @param _messageId id of the message from the other side that triggered a call. * @param _receiver address of the receiver. */ function setFailedMessageReceiver(bytes32 _messageId, address _receiver) internal { addressStorage[keccak256(abi.encodePacked("failedMessageReceiver", _messageId))] = _receiver; } /** * @dev Returns a sender address of the failed message that came from the other side. * @param _messageId id of the message from the other side that triggered a call. * @return sender address on the other side. */ function failedMessageSender(bytes32 _messageId) external view returns (address) { return addressStorage[keccak256(abi.encodePacked("failedMessageSender", _messageId))]; } /** * @dev Sets a sender address of the failed message that came from the other side. * @param _messageId id of the message from the other side that triggered a call. * @param _sender address of the sender on the other side. */ function setFailedMessageSender(bytes32 _messageId, address _sender) internal { addressStorage[keccak256(abi.encodePacked("failedMessageSender", _messageId))] = _sender; } /** * @dev Returns an address of the sender on the other side for the currently processed message. * Can be used by executors for getting other side caller address. * @return address of the sender on the other side. */ function messageSender() external view returns (address sender) { assembly { // Even though this is not the same as addressStorage[keccak256(abi.encodePacked("messageSender"))], // since solidity mapping introduces another level of addressing, such slot change is safe // for temporary variables which are cleared at the end of the call execution. sender := sload(0x7b58b2a669d8e0992eae9eaef641092c0f686fd31070e7236865557fa1571b5b) // keccak256(abi.encodePacked("messageSender")) } } /** * @dev Sets an address of the sender on the other side for the currently processed message. * @param _sender address of the sender on the other side. */ function setMessageSender(address _sender) internal { assembly { // Even though this is not the same as addressStorage[keccak256(abi.encodePacked("messageSender"))], // since solidity mapping introduces another level of addressing, such slot change is safe // for temporary variables which are cleared at the end of the call execution. sstore(0x7b58b2a669d8e0992eae9eaef641092c0f686fd31070e7236865557fa1571b5b, _sender) // keccak256(abi.encodePacked("messageSender")) } } /** * @dev Returns an id of the currently processed message. * @return id of the message that originated on the other side. */ function messageId() public view returns (bytes32 id) { assembly { // Even though this is not the same as uintStorage[keccak256(abi.encodePacked("messageId"))], // since solidity mapping introduces another level of addressing, such slot change is safe // for temporary variables which are cleared at the end of the call execution. id := sload(0xe34bb2103dc34f2c144cc216c132d6ffb55dac57575c22e089161bbe65083304) // keccak256(abi.encodePacked("messageId")) } } /** * @dev Returns an id of the currently processed message. * NOTE: transactionHash was used previously to identify incoming message before AMB message id was introduced. * It is kept for backwards compatibility with old mediators contracts, although it doesn't return txHash anymore. * @return id of the message that originated on the other side. */ function transactionHash() external view returns (bytes32) { return messageId(); } /** * @dev Sets a message id of the currently processed message. * @param _messageId id of the message that originated on the other side. */ function setMessageId(bytes32 _messageId) internal { assembly { // Even though this is not the same as uintStorage[keccak256(abi.encodePacked("messageId"))], // since solidity mapping introduces another level of addressing, such slot change is safe // for temporary variables which are cleared at the end of the call execution. sstore(0xe34bb2103dc34f2c144cc216c132d6ffb55dac57575c22e089161bbe65083304, _messageId) // keccak256(abi.encodePacked("messageId")) } } /** * @dev Returns an originating chain id of the currently processed message. * @return source chain id of the message that originated on the other side. */ function messageSourceChainId() external view returns (uint256 id) { assembly { // Even though this is not the same as uintStorage[keccak256(abi.encodePacked("messageSourceChainId"))], // since solidity mapping introduces another level of addressing, such slot change is safe // for temporary variables which are cleared at the end of the call execution. id := sload(0x7f0fcd9e49860f055dd0c1682d635d309ecb5e3011654c716d9eb59a7ddec7d2) // keccak256(abi.encodePacked("messageSourceChainId")) } } /** * @dev Sets an originating chain id of the currently processed message. * @param _sourceChainId source chain id of the message that originated on the other side. */ function setMessageSourceChainId(uint256 _sourceChainId) internal { assembly { // Even though this is not the same as uintStorage[keccak256(abi.encodePacked("messageSourceChainId"))], // since solidity mapping introduces another level of addressing, such slot change is safe // for temporary variables which are cleared at the end of the call execution. sstore(0x7f0fcd9e49860f055dd0c1682d635d309ecb5e3011654c716d9eb59a7ddec7d2, _sourceChainId) // keccak256(abi.encodePacked("messageSourceChainId")) } } /** * @dev Processes received message. Makes a call to the message executor, * sets dataHash, receive, sender variables for failed messages. * @param _sender sender address on the other side. * @param _executor address of an executor. * @param _messageId id of the processed message. * @param _gasLimit gas limit for a call to executor. * @param _sourceChainId source chain id is of the received message. * @param _data calldata for a call to executor. */ function processMessage( address _sender, address _executor, bytes32 _messageId, uint256 _gasLimit, uint8, /* dataType */ uint256 _sourceChainId, bytes memory _data ) internal { bool status = _passMessage(_sender, _executor, _data, _gasLimit, _messageId, _sourceChainId); setMessageCallStatus(_messageId, status); if (!status) { setFailedMessageDataHash(_messageId, _data); setFailedMessageReceiver(_messageId, _executor); setFailedMessageSender(_messageId, _sender); } emitEventOnMessageProcessed(_sender, _executor, _messageId, status); } /** * @dev Makes a call to the message executor. * @param _sender sender address on the other side. * @param _contract address of an executor contract. * @param _data calldata for a call to executor. * @param _gas gas limit for a call to executor. 2^32 - 1, if caller will pass all available gas for the execution. * @param _messageId id of the processed message. * @param _sourceChainId source chain id is of the received message. */ function _passMessage( address _sender, address _contract, bytes _data, uint256 _gas, bytes32 _messageId, uint256 _sourceChainId ) internal returns (bool) { setMessageSender(_sender); setMessageId(_messageId); setMessageSourceChainId(_sourceChainId); // After EIP-150, max gas cost allowed to be passed to the internal call is equal to the 63/64 of total gas left. // In reality, min(gasLimit, 63/64 * gasleft()) will be used as the call gas limit. // Imagine a situation, when message requires 10000000 gas to be executed successfully. // Also suppose, that at this point, gasleft() is equal to 10158000, so the callee will receive ~ 10158000 * 63 / 64 = 9999300 gas. // That amount of gas is not enough, so the call will fail. At the same time, // even if the callee failed the bridge contract still has ~ 158000 gas to // finish its execution and it will be enough. The internal call fails but // only because the oracle provides incorrect gas limit for the transaction // This check is needed here in order to force contract to pass exactly the requested amount of gas. // Avoiding it may lead to the unwanted message failure in some extreme cases. require(_gas == 0xffffffff || (gasleft() * 63) / 64 > _gas); bool status = _contract.call.gas(_gas)(_data); _validateExecutionStatus(status); setMessageSender(address(0)); setMessageId(bytes32(0)); setMessageSourceChainId(0); return status; } /** * @dev Validates message execution status. In simplest case, does nothing. * @param _status message execution status. */ function _validateExecutionStatus(bool _status) internal { (_status); } /* solcov ignore next */ function emitEventOnMessageProcessed(address sender, address executor, bytes32 messageId, bool status) internal; } // File: contracts/upgradeable_contracts/arbitrary_message/MessageDelivery.sol pragma solidity 0.4.24; contract MessageDelivery is BasicAMB, MessageProcessor { using SafeMath for uint256; uint256 internal constant SEND_TO_ORACLE_DRIVEN_LANE = 0x00; // after EIP2929, call to warmed contract address costs 100 instead of 2600 uint256 internal constant MIN_GAS_PER_CALL = 100; /** * @dev Requests message relay to the opposite network * @param _contract executor address on the other side * @param _data calldata passed to the executor on the other side * @param _gas gas limit used on the other network for executing a message */ function requireToPassMessage(address _contract, bytes memory _data, uint256 _gas) public returns (bytes32) { return _sendMessage(_contract, _data, _gas, SEND_TO_ORACLE_DRIVEN_LANE); } /** * @dev Initiates sending of an AMB message to the opposite network * @param _contract executor address on the other side * @param _data calldata passed to the executor on the other side * @param _gas gas limit used on the other network for executing a message * @param _dataType AMB message dataType to be included as a part of the header */ function _sendMessage(address _contract, bytes memory _data, uint256 _gas, uint256 _dataType) internal returns (bytes32) { // it is not allowed to pass messages while other messages are processed // if other is not explicitly configured require(messageId() == bytes32(0) || allowReentrantRequests()); require(_gas >= MIN_GAS_PER_CALL && _gas <= maxGasPerTx()); uint256 selector; assembly { selector := and(mload(add(_data, 4)), 0xffffffff) } // In order to prevent possible unauthorized ERC20 withdrawals, the following function signatures are prohibited: // * transfer(address,uint256) // * approve(address,uint256) // * transferFrom(address,address,uint256) // * approveAndCall(address,uint256,bytes) // * transferAndCall(address,uint256,bytes) // See https://medium.com/immunefi/xdai-stake-arbitrary-call-method-bug-postmortem-f80a90ac56e3 for more details require( selector != 0xa9059cbb && selector != 0x095ea7b3 && selector != 0x23b872dd && selector != 0x4000aea0 && selector != 0xcae9ca51 ); (bytes32 _messageId, bytes memory header) = _packHeader(_contract, _gas, _dataType); bytes memory eventData = abi.encodePacked(header, _data); emitEventOnMessageRequest(_messageId, eventData); return _messageId; } /** * @dev Packs message header into a single bytes blob * @param _contract executor address on the other side * @param _gas gas limit used on the other network for executing a message * @param _dataType AMB message dataType to be included as a part of the header */ function _packHeader(address _contract, uint256 _gas, uint256 _dataType) internal view returns (bytes32 _messageId, bytes memory header) { uint256 srcChainId = sourceChainId(); uint256 srcChainIdLength = _sourceChainIdLength(); uint256 dstChainId = destinationChainId(); uint256 dstChainIdLength = _destinationChainIdLength(); _messageId = _getNewMessageId(srcChainId); // 79 = 4 + 20 + 8 + 20 + 20 + 4 + 1 + 1 + 1 header = new bytes(79 + srcChainIdLength + dstChainIdLength); // In order to save the gas, the header is packed in the reverse order. // With such approach, it is possible to store right-aligned values without any additional bit shifts. assembly { let ptr := add(header, mload(header)) // points to the last word of header mstore(ptr, dstChainId) mstore(sub(ptr, dstChainIdLength), srcChainId) mstore(add(header, 79), _dataType) mstore(add(header, 78), dstChainIdLength) mstore(add(header, 77), srcChainIdLength) mstore(add(header, 76), _gas) mstore(add(header, 72), _contract) mstore(add(header, 52), caller) mstore(add(header, 32), _messageId) } } /** * @dev Generates a new messageId for the passed request/message. * Increments the nonce accordingly. * @param _srcChainId source chain id of the newly created message. Should be a chain id of the current network. * @return unique message id to use for the new request/message. */ function _getNewMessageId(uint256 _srcChainId) internal returns (bytes32) { uint64 nonce = _nonce(); _setNonce(nonce + 1); // Bridge id is recalculated every time again and again, since it is still cheaper than using SLOAD opcode (800 gas) bytes32 bridgeId = keccak256(abi.encodePacked(_srcChainId, address(this))) & 0x00000000ffffffffffffffffffffffffffffffffffffffff0000000000000000; return MESSAGE_PACKING_VERSION | bridgeId | bytes32(nonce); } /* solcov ignore next */ function emitEventOnMessageRequest(bytes32 messageId, bytes encodedData) internal; } // File: contracts/upgradeable_contracts/MessageRelay.sol pragma solidity 0.4.24; contract MessageRelay is EternalStorage { function relayedMessages(bytes32 _txHash) public view returns (bool) { return boolStorage[keccak256(abi.encodePacked("relayedMessages", _txHash))]; } function setRelayedMessages(bytes32 _txHash, bool _status) internal { boolStorage[keccak256(abi.encodePacked("relayedMessages", _txHash))] = _status; } } // File: contracts/upgradeable_contracts/arbitrary_message/BasicForeignAMB.sol pragma solidity 0.4.24; contract BasicForeignAMB is BasicAMB, MessageRelay, MessageDelivery { /** * @dev Validates provided signatures and relays a given message * @param _data bytes to be relayed * @param _signatures bytes blob with signatures to be validated */ function executeSignatures(bytes _data, bytes _signatures) public { _allowMessageExecution(_data, _signatures); bytes32 msgId; address sender; address executor; uint32 gasLimit; uint8 dataType; uint256[2] memory chainIds; bytes memory data; (msgId, sender, executor, gasLimit, dataType, chainIds, data) = ArbitraryMessage.unpackData(_data); _executeMessage(msgId, sender, executor, gasLimit, dataType, chainIds, data); } /** * @dev Validates provided signatures and relays a given message. * The message is not allowed to fail. The whole tx will be revered if message fails. * @param _data bytes to be relayed * @param _signatures bytes blob with signatures to be validated */ function safeExecuteSignatures(bytes _data, bytes _signatures) external { executeSignatures(_data, _signatures); } /** * @dev Validates provided signatures and relays a given message. Allows to override the gas limit of the passed message. * Usually it makes sense to provide a higher amount of gas for the execution. * The message is not allowed to fail. The whole tx will be revered if message fails. * @param _data bytes to be relayed * @param _signatures bytes blob with signatures to be validated */ function safeExecuteSignaturesWithGasLimit(bytes _data, bytes _signatures, uint32 _gas) public { _allowMessageExecution(_data, _signatures); bytes32 msgId; address sender; address executor; uint8 dataType; uint256[2] memory chainIds; bytes memory data; (msgId, sender, executor, , dataType, chainIds, data) = ArbitraryMessage.unpackData(_data); _executeMessage(msgId, sender, executor, _gas, dataType, chainIds, data); } /** * @dev Validates provided signatures and relays a given message. Passes all available gas for the execution. * The message is not allowed to fail. The whole tx will be revered if message fails. * @param _data bytes to be relayed * @param _signatures bytes blob with signatures to be validated */ function safeExecuteSignaturesWithAutoGasLimit(bytes _data, bytes _signatures) external { safeExecuteSignaturesWithGasLimit(_data, _signatures, 0xffffffff); } /** * @dev Internal function for validating pre-execution requirements. * @param _data bytes to be relayed. * @param _signatures bytes blob with signatures to be validated. */ function _allowMessageExecution(bytes _data, bytes _signatures) internal { // this checks prevents execution of other messages, while some other message is being processed // nested executeSignatures is considered to be unsafe, // since it allows to change/reset the AMB context variables (messageId, messageSender, messageSourceChainId) // while processing nested message require(messageId() == bytes32(0)); Message.hasEnoughValidSignatures(_data, _signatures, validatorContract(), true); } /** * @dev Internal function for executing decoded message. Performs additional validation on the message fields. * @param msgId id of the processed message. * @param sender sender address on the other side. * @param executor address of an executor. * @param gasLimit gas limit for a call to executor. * @param dataType AMB message dataType to be included as a part of the header. * @param chainIds pair of source and destination chain ids. * @param data calldata for a call to executor. */ function _executeMessage( bytes32 msgId, address sender, address executor, uint32 gasLimit, uint8 dataType, uint256[2] memory chainIds, bytes memory data ) internal { require(_isMessageVersionValid(msgId)); require(_isDestinationChainIdValid(chainIds[1])); require(!relayedMessages(msgId)); setRelayedMessages(msgId, true); processMessage(sender, executor, msgId, gasLimit, dataType, chainIds[0], data); } /** * @dev Validates message execution status. Reverts if message is was executed in safe mode and reverted. * @param _status message execution status. */ function _validateExecutionStatus(bool _status) internal { require(_status || msg.sig == this.executeSignatures.selector); } /** * @dev Internal function for updating fallback gas price value. * @param _gasPrice new value for the gas price, zero gas price is not allowed. */ function _setGasPrice(uint256 _gasPrice) internal { require(_gasPrice > 0); super._setGasPrice(_gasPrice); } } // File: contracts/upgradeable_contracts/arbitrary_message/ForeignAMB.sol pragma solidity 0.4.24; contract ForeignAMB is BasicForeignAMB { event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData); event RelayedMessage(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status); function emitEventOnMessageRequest(bytes32 messageId, bytes encodedData) internal { emit UserRequestForAffirmation(messageId, encodedData); } function emitEventOnMessageProcessed(address sender, address executor, bytes32 messageId, bool status) internal { emit RelayedMessage(sender, executor, messageId, status); } }