├── .gitignore ├── Readme.md ├── contracts ├── core │ ├── assets │ │ ├── LPToken_template │ │ │ └── LPToken.sol │ │ ├── btc │ │ │ └── BTCX.sol │ │ ├── erc20_template │ │ │ └── ERC20Template.sol │ │ ├── neo │ │ │ └── eNEO.sol │ │ ├── oep4_template │ │ │ └── OEP4Template.sol │ │ ├── ong │ │ │ └── ONGX.sol │ │ ├── ont │ │ │ └── xONT.sol │ │ └── usdt │ │ │ └── USDT.sol │ ├── cross_chain_manager │ │ ├── data │ │ │ └── EthCrossChainData.sol │ │ ├── interface │ │ │ ├── IEthCrossChainData.sol │ │ │ ├── IEthCrossChainManager.sol │ │ │ ├── IEthCrossChainManagerProxy.sol │ │ │ └── IUpgradableECCM.sol │ │ ├── libs │ │ │ └── EthCrossChainUtils.sol │ │ ├── logic │ │ │ ├── EthCrossChainManager.sol │ │ │ ├── EthCrossChainManagerForTest.sol │ │ │ ├── EthCrossChainManagerForUpgrade.sol │ │ │ └── EthCrossChainManagerNoWhiteList.sol │ │ └── upgrade │ │ │ ├── EthCrossChainManagerProxy.sol │ │ │ └── UpgradableECCM.sol │ ├── lock_proxy │ │ ├── LockProxy.sol │ │ ├── LockProxyPip1.sol │ │ ├── LockProxyPip4.sol │ │ ├── LockProxySingleAsset.sol │ │ ├── LockProxyWithLP.sol │ │ └── RippleLockProxy.sol │ └── wrapper │ │ ├── PolyWrapper_v1 │ │ ├── PolyWrapper_v1.sol │ │ ├── PolyWrapper_v2.sol │ │ └── interfaces │ │ ├── ILockProxy.sol │ │ └── IPolyWrapper.sol ├── libs │ ├── GSN │ │ └── Context.sol │ ├── common │ │ ├── ZeroCopySink.sol │ │ └── ZeroCopySource.sol │ ├── lifecycle │ │ └── Pausable.sol │ ├── math │ │ └── SafeMath.sol │ ├── ownership │ │ └── Ownable.sol │ ├── token │ │ └── ERC20 │ │ │ ├── ERC20.sol │ │ │ ├── ERC20Detailed.sol │ │ │ ├── ERC20Extended.sol │ │ │ ├── IERC20.sol │ │ │ └── SafeERC20.sol │ └── utils │ │ ├── Encoder.sol │ │ ├── ReentrancyGuard.sol │ │ └── Utils.sol └── mocks │ └── libs │ ├── common │ ├── ZeroCopySinkMock.sol │ └── ZeroCopySourceMock.sol │ ├── math │ └── SafeMathMock.sol │ └── utils │ └── UtilsMock.sol ├── document └── images │ └── eccm_design.png ├── go_abi ├── btcx_abi │ └── btcx_abi.go ├── eccd_abi │ └── eccd_abi.go ├── eccm_abi │ └── eccm_abi.go ├── eccmp_abi │ └── eccmp_abi.go ├── erc20_abi │ └── erc20_abi.go ├── lock_proxy_abi │ └── lock_proxy.go ├── oep4_abi │ └── oep4_abi.go ├── ongx_abi │ └── ongx_abi.go ├── ontx_abi │ └── ontx_abi.go └── usdt_abi │ └── usdt_abi.go ├── hardhat.config.js ├── hardhatTests └── EthCrossChainMangerTest.js ├── migrations └── 1_initial_migration.js ├── package-lock.json ├── scripts ├── deploy.js ├── deployBasic.js ├── deployBasicTestnet.js ├── deployLockProxy.js ├── deployLockProxyTestnet.js ├── deployPIP4.js ├── deployPIP4Testnet.js ├── deploy_testnet.js ├── resumeUpdate.js ├── setDefaultWhiteList.js ├── setSpecifiedWhiteList.js ├── suspendV1.js ├── update.js ├── update_testnet.js └── whiteListGen.js ├── test ├── ECCUtilsMock.sol ├── EthCrossChainManagerTest.js ├── SafeMathTest.js ├── UtilsTest.js ├── ZeroCopySinkTest.js ├── ZeroCopySourceTest.js └── helpers │ └── assertRevert.js └── truffle-config.js /.gitignore: -------------------------------------------------------------------------------- 1 | abigen 2 | info.txt 3 | tmp 4 | build 5 | .idea 6 | 7 | node_modules 8 | /.project 9 | /.settings/ 10 | 11 | 12 | /docs/_build/ 13 | lib/ 14 | 15 | # Logs 16 | *.log 17 | 18 | # Coverage 19 | /.nyc_output 20 | /coverage 21 | 22 | # IDE specific 23 | /.vscode 24 | 25 | .DS_Store 26 | /.DS_Store 27 | src/.DS_Store 28 | 29 | apidoc/ 30 | node_modules 31 | 32 | artifacts/ 33 | hardhat.config.js 34 | cache/ 35 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ## Current effective version 2 | 3 | Current version being used in testnet is `./contracts/core` 4 | 5 | ## Generate abi files instruction 6 | 7 | Download go-ethereum, choose the preferred version and build the executable abigen file. 8 | 9 | ``` 10 | ./abigen --sol ./contracts/core/cross_chain_manager/data/EthCrossChainData.sol --pkg eccd_abi > ./go_abi/eccd_abi/eccd_abi.go 11 | 12 | ./abigen --sol ./contracts/core/cross_chain_manager/logic/EthCrossChainManager.sol --pkg eccm_abi > ./go_abi/eccm_abi/eccm_abi.go 13 | 14 | ./abigen --sol ./contracts/core/cross_chain_manager/upgrade/EthCrossChainManagerProxy.sol --pkg eccmp_abi > ./go_abi/eccmp_abi/eccmp_abi.go 15 | 16 | ./abigen --sol ./contracts/core/lock_proxy/LockProxy.sol --pkg lock_proxy_abi > ./go_abi/lock_proxy_abi/lock_proxy.go 17 | 18 | ./abigen --sol ./contracts/core/assets/btc/BTCX.sol --pkg btcx_abi > ./go_abi/btcx_abi/btcx_abi.go 19 | 20 | ./abigen --sol ./contracts/core/assets/ont/xONT.sol --pkg ontx_abi > ./go_abi/ontx_abi/ontx_abi.go 21 | 22 | ./abigen --sol ./contracts/core/assets/ong/ONGX.sol --pkg ongx_abi > ./go_abi/ongx_abi/ongx_abi.go 23 | 24 | ./abigen --sol ./contracts/core/assets/oep4_template/OEP4Template.sol --pkg oep4_abi > ./go_abi/oep4_abi/oep4_abi.go 25 | 26 | ./abigen --sol ./contracts/core/assets/erc20_template/ERC20Template.sol --pkg erc20_abi > ./go_abi/erc20_abi/erc20_abi.go 27 | 28 | 29 | ``` 30 | 31 | ## Truffle test instruction 32 | 33 | #### install pkg 34 | ``` 35 | npm install --save-dev @openzeppelin/test-helpers 36 | 37 | ``` 38 | 39 | 40 | 41 | [truffle documentation](https://learnblockchain.cn/docs/truffle/getting-started/interacting-with-your-contracts.html) 42 | 43 | [web3.js api reference](https://web3.tryblockchain.org/Web3.js-api-refrence.html) 44 | 45 | #### compile 46 | ``` 47 | truffle compile 48 | ``` 49 | 50 | #### deploy 51 | ``` 52 | truffle migrate 53 | ``` 54 | 55 | #### test 56 | 57 | Before run a full round of test or `test/EthCrossChainManagerv3.0Test.js` file, make sure you commit the following code within ```verifyAndExecuteTx()``` method in both [EthCrossChainManager.sol](./contracts/core/CrossChainManager/logic/EthCrossChainManager.sol) and [new EthCrossChainManager.sol](./contracts/core/CrossChainManager/logic/EthCrossChainManager_new_template.sol). 58 | ``` 59 | //TODO: check this part to make sure we commit the next line when doing local net UT test 60 | require(_executeCrossChainTx(toContract, toMerkleValue.makeTxParam.method, toMerkleValue.makeTxParam.args, toMerkleValue.makeTxParam.fromContract, toMerkleValue.fromChainID), "Execute CrossChain Tx failed!"); 61 | ``` 62 | 63 | To run a full test under `test` folder, use 64 | ``` 65 | truffle test 66 | ``` 67 | To run a specific test js file under `test` folder, use 68 | ``` 69 | truffle test ./test/ZeroCopySinkTest.js 70 | ``` 71 | 72 | 73 | 74 | ## In truffle console / truffle development mode 75 | 76 | #### Get contract instance in truffle console: 77 | 1. let instance = await MetaCoin.deployed() 78 | 2. Or suppose contract address : 0x133739AB03b9be2b885cC11e3B9292FDFf45440E, 79 | we can use let instance = await Contract.at("0x133739AB03b9be2b885cC11e3B9292FDFf45440E") to obtain the instance. 80 | 81 | #### Call contract function (pre-invoke/ pre-execute) 82 | ``` 83 | instance.name() / await instance.name() 84 | 85 | (await instance.totalSupply()).toNumber() 86 | ``` 87 | Or we can also use 88 | ``` 89 | await instance..name.call() 90 | ``` 91 | 92 | #### send Transaction: (invoke / execute) 93 | let result = await instance.transfer(accounts[1], 100) 94 | 95 | the returned structure is the following: 96 | ``` 97 | result = { 98 | "tx": .., 99 | "receipt": .., 100 | "logs": [] 101 | } 102 | 103 | ``` 104 | 105 | await instance.approve(accounts[2], 100) 106 | 107 | (await instance.allowance(accounts[0], accounts[2])).toNumber() 108 | 109 | let result1 = await instance.transferFrom(accounts[0], accounts[2], 1, {from:accounts[2]}) 110 | ({from: ***} to indicate the msg.sender of this transaction) 111 | 112 | #### about ether 113 | 114 | Note: in truffle console, accounts by default means eth.web3.accounts 115 | 116 | query balance : web3.eth.getBalance(accounts[0]) 117 | 118 | send ether: web3.eth.sendTransaction({from: accounts[0], to: accounts[1], value: web3.utils.toWei('1', "ether")}) 119 | 120 | 121 | -------------------------------------------------------------------------------- /contracts/core/assets/LPToken_template/LPToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../../libs/GSN/Context.sol"; 4 | import "./../../../libs/token/ERC20/ERC20.sol"; 5 | import "./../../../libs/token/ERC20/ERC20Detailed.sol"; 6 | 7 | contract LPToken is Context, ERC20, ERC20Detailed { 8 | 9 | constructor(string memory name, string memory symbol, uint8 decimal, address initReceiver, uint initAmount) 10 | public ERC20Detailed(name, symbol, decimal) { 11 | _mint(initReceiver, initAmount); 12 | } 13 | } -------------------------------------------------------------------------------- /contracts/core/assets/btc/BTCX.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | import "./../../../libs/GSN/Context.sol"; 3 | import "./../../../libs/common/ZeroCopySource.sol"; 4 | import "./../../../libs/common/ZeroCopySink.sol"; 5 | import "./../../../libs/utils/Utils.sol"; 6 | import "./../../cross_chain_manager/interface/IEthCrossChainManager.sol"; 7 | import "./../../cross_chain_manager/interface/IEthCrossChainManagerProxy.sol"; 8 | import "./../../../libs/token/ERC20/ERC20Extended.sol"; 9 | contract BTCX is ERC20Extended { 10 | struct TxArgs { 11 | bytes toAddress; 12 | uint64 amount; 13 | } 14 | 15 | bytes public redeemScript; 16 | uint64 public minimumLimit; 17 | event UnlockEvent(address toAssetHash, address toAddress, uint64 amount); 18 | event LockEvent(address fromAssetHash, address fromAddress, uint64 toChainId, bytes toAssetHash, bytes toAddress, uint64 amount); 19 | 20 | constructor (bytes memory _redeemScript) public ERC20Detailed("BTC Token", "BTCX", 8) { 21 | operator = _msgSender(); 22 | redeemScript = _redeemScript; 23 | } 24 | function setMinimumLimit(uint64 minimumTransferLimit) onlyOperator public returns (bool) { 25 | minimumLimit = minimumTransferLimit; 26 | return true; 27 | } 28 | /* @notice This function is meant to be invoked by the ETH crosschain management contract, 29 | * then mint a certin amount of tokens to the designated address since a certain amount 30 | * was burnt from the source chain invoker. 31 | * @param argsBs The argument bytes recevied by the ethereum business contract, need to be deserialized. 32 | * based on the way of serialization in the source chain contract. 33 | * @param fromContractAddr The source chain contract address 34 | * @param fromChainId The source chain id 35 | */ 36 | function unlock(bytes memory argsBs, bytes memory fromContractAddr, uint64 fromChainId) onlyManagerContract public returns (bool) { 37 | TxArgs memory args = _deserializeTxArgs(argsBs); 38 | require(fromContractAddr.length != 0, "from asset contract address cannot be empty"); 39 | require(Utils.equalStorage(bondAssetHashes[fromChainId], fromContractAddr), "From contract address error!"); 40 | 41 | address toAddress = Utils.bytesToAddress(args.toAddress); 42 | require(mint(toAddress, uint256(args.amount)), "mint BTCX in unlock method failed!"); 43 | 44 | emit UnlockEvent(address(this), toAddress, args.amount); 45 | return true; 46 | } 47 | 48 | /* @notice This function is meant to be invoked by the user, 49 | * a certin amount teokens will be burnt from the invoker/msg.sender immediately. 50 | * Then the same amount of tokens will be mint at the target chain with chainId later. 51 | * @param toChainId The target chain id 52 | * 53 | * @param toUserAddr The address in bytes format to receive same amount of tokens in target chain 54 | * @param amount The amount of tokens to be crossed from ethereum to the chain with chainId 55 | */ 56 | function lock(uint64 toChainId, bytes memory toUserAddr, uint64 amount) public returns (bool) { 57 | TxArgs memory txArgs = TxArgs({ 58 | toAddress: toUserAddr, 59 | amount: amount 60 | }); 61 | 62 | bytes memory txData; 63 | // if toChainId is BTC chain, put redeemScript into Args 64 | if (toChainId == 1) { 65 | require(amount >= minimumLimit, "btcx amount should be greater than 2000"); 66 | txData = _serializeToBtcTxArgs(txArgs, redeemScript); 67 | } else { 68 | txData = _serializeTxArgs(txArgs); 69 | } 70 | 71 | 72 | require(burn(uint256(amount)), "Burn msg.sender BTCX tokens failed"); 73 | 74 | IEthCrossChainManagerProxy eccmp = IEthCrossChainManagerProxy(managerProxyContract); 75 | address eccmAddr = eccmp.getEthCrossChainManager(); 76 | IEthCrossChainManager eccm = IEthCrossChainManager(eccmAddr); 77 | 78 | require(eccm.crossChain(toChainId, bondAssetHashes[toChainId], "unlock", txData), "EthCrossChainManager crossChain executed error!"); 79 | 80 | emit LockEvent(address(this), _msgSender(), toChainId, bondAssetHashes[toChainId], toUserAddr, amount); 81 | 82 | return true; 83 | 84 | } 85 | 86 | function _serializeToBtcTxArgs(TxArgs memory args, bytes memory redeemScript) internal pure returns (bytes memory) { 87 | bytes memory buff; 88 | buff = abi.encodePacked( 89 | ZeroCopySink.WriteVarBytes(args.toAddress), 90 | ZeroCopySink.WriteUint64(args.amount), 91 | ZeroCopySink.WriteVarBytes(redeemScript) 92 | ); 93 | return buff; 94 | } 95 | function _serializeTxArgs(TxArgs memory args) internal pure returns (bytes memory) { 96 | bytes memory buff; 97 | buff = abi.encodePacked( 98 | ZeroCopySink.WriteVarBytes(args.toAddress), 99 | ZeroCopySink.WriteUint64(args.amount) 100 | ); 101 | return buff; 102 | } 103 | 104 | function _deserializeTxArgs(bytes memory valueBs) internal pure returns (TxArgs memory) { 105 | TxArgs memory args; 106 | uint256 off = 0; 107 | (args.toAddress, off) = ZeroCopySource.NextVarBytes(valueBs, off); 108 | (args.amount, off) = ZeroCopySource.NextUint64(valueBs, off); 109 | return args; 110 | } 111 | } -------------------------------------------------------------------------------- /contracts/core/assets/erc20_template/ERC20Template.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../../libs/GSN/Context.sol"; 4 | import "./../../../libs/token/ERC20/ERC20.sol"; 5 | import "./../../../libs/token/ERC20/ERC20Detailed.sol"; 6 | 7 | contract ERC20Template is Context, ERC20, ERC20Detailed { 8 | 9 | constructor () public ERC20Detailed("ERC20 Template", "ERC20T", 9) { 10 | _mint(_msgSender(), 10000000000000); 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/core/assets/neo/eNEO.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../../libs/token/ERC20/ERC20Detailed.sol"; 4 | import "./../../../libs/GSN/Context.sol"; 5 | import "./../../../libs/token/ERC20/ERC20.sol"; 6 | 7 | contract eNEO is Context, ERC20, ERC20Detailed { 8 | 9 | constructor (address lockProxyContractAddress) public ERC20Detailed("NEO Token", "eNEO", 8) { 10 | _mint(lockProxyContractAddress, 10000000000000000); 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/core/assets/oep4_template/OEP4Template.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../../libs/token/ERC20/ERC20Detailed.sol"; 4 | import "./../../../libs/GSN/Context.sol"; 5 | import "./../../../libs/token//ERC20/ERC20.sol"; 6 | import "./../../../libs/math/SafeMath.sol"; 7 | 8 | contract OEP4Template is Context, ERC20, ERC20Detailed { 9 | address public Operator; 10 | address public proxyHash; 11 | constructor (address proxyContractAddress) public ERC20Detailed("OEP4 Template", "OEP4T", 9) { 12 | _mint(address(this), 10000 * 10 ** 9); 13 | Operator = _msgSender(); 14 | proxyHash = proxyContractAddress; 15 | } 16 | 17 | modifier onlyOperator() { 18 | require(_msgSender() == Operator, "Only Operator has access!"); 19 | _; 20 | } 21 | 22 | function deletageToProxy(address _proxyHash, uint256 _amount) onlyOperator public returns (bool) { 23 | if (proxyHash != address(0)) { 24 | require(_proxyHash == proxyHash, "proxy contract address cannot be changed!"); 25 | } else { 26 | proxyHash = _proxyHash; 27 | } 28 | require(this.transfer(_proxyHash, _amount), "transfer token to proxy contract failed!"); 29 | return true; 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /contracts/core/assets/ong/ONGX.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../../libs/token/ERC20/ERC20Detailed.sol"; 4 | import "./../../../libs/GSN/Context.sol"; 5 | import "./../../../libs/token/ERC20/ERC20.sol"; 6 | 7 | contract ONGX is Context, ERC20, ERC20Detailed { 8 | 9 | constructor (address proxyContractAddress) public ERC20Detailed("Ontology Gas", "xONG", 9) { 10 | _mint(proxyContractAddress, 1000000000000000000); 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/core/assets/ont/xONT.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../../libs/token/ERC20/ERC20Detailed.sol"; 4 | import "./../../../libs/GSN/Context.sol"; 5 | import "./../../../libs/token/ERC20/ERC20.sol"; 6 | 7 | contract ONTX is Context, ERC20, ERC20Detailed { 8 | 9 | constructor (address lockProxyContractAddress) public ERC20Detailed("Ontology Token", "xONT", 0) { 10 | _mint(lockProxyContractAddress, 1000000000); 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/core/cross_chain_manager/data/EthCrossChainData.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | import "./../../../libs/ownership/Ownable.sol"; 3 | import "./../../../libs/lifecycle/Pausable.sol"; 4 | import "./../interface/IEthCrossChainData.sol"; 5 | 6 | contract EthCrossChainData is IEthCrossChainData, Ownable, Pausable{ 7 | /* 8 | Ethereum cross chain tx hash indexed by the automatically increased index. 9 | This map exists for the reason that Poly chain can verify the existence of 10 | cross chain request tx coming from Ethereum 11 | */ 12 | mapping(uint256 => bytes32) public EthToPolyTxHashMap; 13 | // This index records the current Map length 14 | uint256 public EthToPolyTxHashIndex; 15 | 16 | /* 17 | When Poly chain switches the consensus epoch book keepers, the consensus peers public keys of Poly chain should be 18 | changed into no-compressed version so that solidity smart contract can convert it to address type and 19 | verify the signature derived from Poly chain account signature. 20 | ConKeepersPkBytes means Consensus book Keepers Public Key Bytes 21 | */ 22 | bytes public ConKeepersPkBytes; 23 | 24 | // CurEpochStartHeight means Current Epoch Start Height of Poly chain block 25 | uint32 public CurEpochStartHeight; 26 | 27 | // Record the from chain txs that have been processed 28 | mapping(uint64 => mapping(bytes32 => bool)) FromChainTxExist; 29 | 30 | // Extra map for the usage of future potentially 31 | mapping(bytes32 => mapping(bytes32 => bytes)) public ExtraData; 32 | 33 | // Store Current Epoch Start Height of Poly chain block 34 | function putCurEpochStartHeight(uint32 curEpochStartHeight) public whenNotPaused onlyOwner returns (bool) { 35 | CurEpochStartHeight = curEpochStartHeight; 36 | return true; 37 | } 38 | 39 | // Get Current Epoch Start Height of Poly chain block 40 | function getCurEpochStartHeight() public view returns (uint32) { 41 | return CurEpochStartHeight; 42 | } 43 | 44 | // Store Consensus book Keepers Public Key Bytes 45 | function putCurEpochConPubKeyBytes(bytes memory curEpochPkBytes) public whenNotPaused onlyOwner returns (bool) { 46 | ConKeepersPkBytes = curEpochPkBytes; 47 | return true; 48 | } 49 | 50 | // Get Consensus book Keepers Public Key Bytes 51 | function getCurEpochConPubKeyBytes() public view returns (bytes memory) { 52 | return ConKeepersPkBytes; 53 | } 54 | 55 | // Mark from chain tx fromChainTx as exist or processed 56 | function markFromChainTxExist(uint64 fromChainId, bytes32 fromChainTx) public whenNotPaused onlyOwner returns (bool) { 57 | FromChainTxExist[fromChainId][fromChainTx] = true; 58 | return true; 59 | } 60 | 61 | // Check if from chain tx fromChainTx has been processed before 62 | function checkIfFromChainTxExist(uint64 fromChainId, bytes32 fromChainTx) public view returns (bool) { 63 | return FromChainTxExist[fromChainId][fromChainTx]; 64 | } 65 | 66 | // Get current recorded index of cross chain txs requesting from Ethereum to other public chains 67 | // in order to help cross chain manager contract differenciate two cross chain tx requests 68 | function getEthTxHashIndex() public view returns (uint256) { 69 | return EthToPolyTxHashIndex; 70 | } 71 | 72 | // Store Ethereum cross chain tx hash, increase the index record by 1 73 | function putEthTxHash(bytes32 ethTxHash) public whenNotPaused onlyOwner returns (bool) { 74 | EthToPolyTxHashMap[EthToPolyTxHashIndex] = ethTxHash; 75 | EthToPolyTxHashIndex = EthToPolyTxHashIndex + 1; 76 | return true; 77 | } 78 | 79 | // Get Ethereum cross chain tx hash indexed by ethTxHashIndex 80 | function getEthTxHash(uint256 ethTxHashIndex) public view returns (bytes32) { 81 | return EthToPolyTxHashMap[ethTxHashIndex]; 82 | } 83 | 84 | // Store extra data, which may be used in the future 85 | function putExtraData(bytes32 key1, bytes32 key2, bytes memory value) public whenNotPaused onlyOwner returns (bool) { 86 | ExtraData[key1][key2] = value; 87 | return true; 88 | } 89 | // Get extra data, which may be used in the future 90 | function getExtraData(bytes32 key1, bytes32 key2) public view returns (bytes memory) { 91 | return ExtraData[key1][key2]; 92 | } 93 | 94 | function pause() onlyOwner whenNotPaused public returns (bool) { 95 | _pause(); 96 | return true; 97 | } 98 | 99 | function unpause() onlyOwner whenPaused public returns (bool) { 100 | _unpause(); 101 | return true; 102 | } 103 | } -------------------------------------------------------------------------------- /contracts/core/cross_chain_manager/interface/IEthCrossChainData.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Interface of the EthCrossChainData contract, the implementation is in EthCrossChainData.sol 5 | */ 6 | interface IEthCrossChainData { 7 | function putCurEpochStartHeight(uint32 curEpochStartHeight) external returns (bool); 8 | function getCurEpochStartHeight() external view returns (uint32); 9 | function putCurEpochConPubKeyBytes(bytes calldata curEpochPkBytes) external returns (bool); 10 | function getCurEpochConPubKeyBytes() external view returns (bytes memory); 11 | function markFromChainTxExist(uint64 fromChainId, bytes32 fromChainTx) external returns (bool); 12 | function checkIfFromChainTxExist(uint64 fromChainId, bytes32 fromChainTx) external view returns (bool); 13 | function getEthTxHashIndex() external view returns (uint256); 14 | function putEthTxHash(bytes32 ethTxHash) external returns (bool); 15 | function putExtraData(bytes32 key1, bytes32 key2, bytes calldata value) external returns (bool); 16 | function getExtraData(bytes32 key1, bytes32 key2) external view returns (bytes memory); 17 | function transferOwnership(address newOwner) external; 18 | function pause() external returns (bool); 19 | function unpause() external returns (bool); 20 | function paused() external view returns (bool); 21 | // Not used currently by ECCM 22 | function getEthTxHash(uint256 ethTxHashIndex) external view returns (bytes32); 23 | } -------------------------------------------------------------------------------- /contracts/core/cross_chain_manager/interface/IEthCrossChainManager.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Interface of the EthCrossChainManager contract for business contract like LockProxy to request cross chain transaction 5 | */ 6 | interface IEthCrossChainManager { 7 | function crossChain(uint64 _toChainId, bytes calldata _toContract, bytes calldata _method, bytes calldata _txData) external returns (bool); 8 | } 9 | -------------------------------------------------------------------------------- /contracts/core/cross_chain_manager/interface/IEthCrossChainManagerProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Interface of the EthCrossChainManagerProxy for business contract like LockProxy to obtain the reliable EthCrossChainManager contract hash. 5 | */ 6 | interface IEthCrossChainManagerProxy { 7 | function getEthCrossChainManager() external view returns (address); 8 | } 9 | -------------------------------------------------------------------------------- /contracts/core/cross_chain_manager/interface/IUpgradableECCM.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Interface of upgradableECCM to make ECCM be upgradable, the implementation is in UpgradableECCM.sol 5 | */ 6 | interface IUpgradableECCM { 7 | function pause() external returns (bool); 8 | function unpause() external returns (bool); 9 | function paused() external view returns (bool); 10 | function upgradeToNew(address) external returns (bool); 11 | function isOwner() external view returns (bool); 12 | function setChainId(uint64 _newChainId) external returns (bool); 13 | } 14 | -------------------------------------------------------------------------------- /contracts/core/cross_chain_manager/libs/EthCrossChainUtils.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | import "./../../../libs/common/ZeroCopySource.sol"; 3 | import "./../../../libs/common/ZeroCopySink.sol"; 4 | import "./../../../libs/utils/Utils.sol"; 5 | import "./../../../libs/math/SafeMath.sol"; 6 | library ECCUtils { 7 | using SafeMath for uint256; 8 | 9 | struct Header { 10 | uint32 version; 11 | uint64 chainId; 12 | uint32 timestamp; 13 | uint32 height; 14 | uint64 consensusData; 15 | bytes32 prevBlockHash; 16 | bytes32 transactionsRoot; 17 | bytes32 crossStatesRoot; 18 | bytes32 blockRoot; 19 | bytes consensusPayload; 20 | bytes20 nextBookkeeper; 21 | } 22 | 23 | struct ToMerkleValue { 24 | bytes txHash; // cross chain txhash 25 | uint64 fromChainID; 26 | TxParam makeTxParam; 27 | } 28 | 29 | struct TxParam { 30 | bytes txHash; // source chain txhash 31 | bytes crossChainId; 32 | bytes fromContract; 33 | uint64 toChainId; 34 | bytes toContract; 35 | bytes method; 36 | bytes args; 37 | } 38 | 39 | uint constant POLYCHAIN_PUBKEY_LEN = 67; 40 | uint constant POLYCHAIN_SIGNATURE_LEN = 65; 41 | 42 | /* @notice Verify Poly chain transaction whether exist or not 43 | * @param _auditPath Poly chain merkle proof 44 | * @param _root Poly chain root 45 | * @return The verified value included in _auditPath 46 | */ 47 | function merkleProve(bytes memory _auditPath, bytes32 _root) internal pure returns (bytes memory) { 48 | uint256 off = 0; 49 | bytes memory value; 50 | (value, off) = ZeroCopySource.NextVarBytes(_auditPath, off); 51 | 52 | bytes32 hash = Utils.hashLeaf(value); 53 | uint size = _auditPath.length.sub(off).div(33); 54 | bytes32 nodeHash; 55 | byte pos; 56 | for (uint i = 0; i < size; i++) { 57 | (pos, off) = ZeroCopySource.NextByte(_auditPath, off); 58 | (nodeHash, off) = ZeroCopySource.NextHash(_auditPath, off); 59 | if (pos == 0x00) { 60 | hash = Utils.hashChildren(nodeHash, hash); 61 | } else if (pos == 0x01) { 62 | hash = Utils.hashChildren(hash, nodeHash); 63 | } else { 64 | revert("merkleProve, NextByte for position info failed"); 65 | } 66 | } 67 | require(hash == _root, "merkleProve, expect root is not equal actual root"); 68 | return value; 69 | } 70 | 71 | /* @notice calculate next book keeper according to public key list 72 | * @param _keyLen consensus node number 73 | * @param _m minimum signature number 74 | * @param _pubKeyList consensus node public key list 75 | * @return two element: next book keeper, consensus node signer addresses 76 | */ 77 | function _getBookKeeper(uint _keyLen, uint _m, bytes memory _pubKeyList) internal pure returns (bytes20, address[] memory){ 78 | bytes memory buff; 79 | buff = ZeroCopySink.WriteUint16(uint16(_keyLen)); 80 | address[] memory keepers = new address[](_keyLen); 81 | bytes32 hash; 82 | bytes memory publicKey; 83 | for(uint i = 0; i < _keyLen; i++){ 84 | publicKey = Utils.slice(_pubKeyList, i*POLYCHAIN_PUBKEY_LEN, POLYCHAIN_PUBKEY_LEN); 85 | buff = abi.encodePacked(buff, ZeroCopySink.WriteVarBytes(Utils.compressMCPubKey(publicKey))); 86 | hash = keccak256(Utils.slice(publicKey, 3, 64)); 87 | keepers[i] = address(uint160(uint256(hash))); 88 | } 89 | 90 | buff = abi.encodePacked(buff, ZeroCopySink.WriteUint16(uint16(_m))); 91 | bytes20 nextBookKeeper = ripemd160(abi.encodePacked(sha256(buff))); 92 | return (nextBookKeeper, keepers); 93 | } 94 | 95 | /* @notice Verify public key derived from Poly chain 96 | * @param _pubKeyList serialized consensus node public key list 97 | * @param _sigList consensus node signature list 98 | * @return return two element: next book keeper, consensus node signer addresses 99 | */ 100 | function verifyPubkey(bytes memory _pubKeyList) internal pure returns (bytes20, address[] memory) { 101 | require(_pubKeyList.length % POLYCHAIN_PUBKEY_LEN == 0, "_pubKeyList length illegal!"); 102 | uint n = _pubKeyList.length / POLYCHAIN_PUBKEY_LEN; 103 | require(n >= 1, "too short _pubKeyList!"); 104 | return _getBookKeeper(n, n - (n - 1) / 3, _pubKeyList); 105 | } 106 | 107 | /* @notice Verify Poly chain consensus node signature 108 | * @param _rawHeader Poly chain block header raw bytes 109 | * @param _sigList consensus node signature list 110 | * @param _keepers addresses corresponding with Poly chain book keepers' public keys 111 | * @param _m minimum signature number 112 | * @return true or false 113 | */ 114 | function verifySig(bytes memory _rawHeader, bytes memory _sigList, address[] memory _keepers, uint _m) internal pure returns (bool){ 115 | bytes32 hash = getHeaderHash(_rawHeader); 116 | 117 | uint sigCount = _sigList.length.div(POLYCHAIN_SIGNATURE_LEN); 118 | address[] memory signers = new address[](sigCount); 119 | bytes32 r; 120 | bytes32 s; 121 | uint8 v; 122 | for(uint j = 0; j < sigCount; j++){ 123 | r = Utils.bytesToBytes32(Utils.slice(_sigList, j*POLYCHAIN_SIGNATURE_LEN, 32)); 124 | s = Utils.bytesToBytes32(Utils.slice(_sigList, j*POLYCHAIN_SIGNATURE_LEN + 32, 32)); 125 | v = uint8(_sigList[j*POLYCHAIN_SIGNATURE_LEN + 64]) + 27; 126 | signers[j] = ecrecover(sha256(abi.encodePacked(hash)), v, r, s); 127 | if (signers[j] == address(0)) return false; 128 | } 129 | return Utils.containMAddresses(_keepers, signers, _m); 130 | } 131 | 132 | 133 | /* @notice Serialize Poly chain book keepers' info in Ethereum addresses format into raw bytes 134 | * @param keepersBytes The serialized addresses 135 | * @return serialized bytes result 136 | */ 137 | function serializeKeepers(address[] memory keepers) internal pure returns (bytes memory) { 138 | uint256 keeperLen = keepers.length; 139 | bytes memory keepersBytes = ZeroCopySink.WriteUint64(uint64(keeperLen)); 140 | for(uint i = 0; i < keeperLen; i++) { 141 | keepersBytes = abi.encodePacked(keepersBytes, ZeroCopySink.WriteVarBytes(Utils.addressToBytes(keepers[i]))); 142 | } 143 | return keepersBytes; 144 | } 145 | 146 | /* @notice Deserialize bytes into Ethereum addresses 147 | * @param keepersBytes The serialized addresses derived from Poly chain book keepers in bytes format 148 | * @return addresses 149 | */ 150 | function deserializeKeepers(bytes memory keepersBytes) internal pure returns (address[] memory) { 151 | uint256 off = 0; 152 | uint64 keeperLen; 153 | (keeperLen, off) = ZeroCopySource.NextUint64(keepersBytes, off); 154 | address[] memory keepers = new address[](keeperLen); 155 | bytes memory keeperBytes; 156 | for(uint i = 0; i < keeperLen; i++) { 157 | (keeperBytes, off) = ZeroCopySource.NextVarBytes(keepersBytes, off); 158 | keepers[i] = Utils.bytesToAddress(keeperBytes); 159 | } 160 | return keepers; 161 | } 162 | 163 | /* @notice Deserialize Poly chain transaction raw value 164 | * @param _valueBs Poly chain transaction raw bytes 165 | * @return ToMerkleValue struct 166 | */ 167 | function deserializeMerkleValue(bytes memory _valueBs) internal pure returns (ToMerkleValue memory) { 168 | ToMerkleValue memory toMerkleValue; 169 | uint256 off = 0; 170 | 171 | (toMerkleValue.txHash, off) = ZeroCopySource.NextVarBytes(_valueBs, off); 172 | 173 | (toMerkleValue.fromChainID, off) = ZeroCopySource.NextUint64(_valueBs, off); 174 | 175 | TxParam memory txParam; 176 | 177 | (txParam.txHash, off) = ZeroCopySource.NextVarBytes(_valueBs, off); 178 | 179 | (txParam.crossChainId, off) = ZeroCopySource.NextVarBytes(_valueBs, off); 180 | 181 | (txParam.fromContract, off) = ZeroCopySource.NextVarBytes(_valueBs, off); 182 | 183 | (txParam.toChainId, off) = ZeroCopySource.NextUint64(_valueBs, off); 184 | 185 | (txParam.toContract, off) = ZeroCopySource.NextVarBytes(_valueBs, off); 186 | 187 | (txParam.method, off) = ZeroCopySource.NextVarBytes(_valueBs, off); 188 | 189 | (txParam.args, off) = ZeroCopySource.NextVarBytes(_valueBs, off); 190 | toMerkleValue.makeTxParam = txParam; 191 | 192 | return toMerkleValue; 193 | } 194 | 195 | /* @notice Deserialize Poly chain block header raw bytes 196 | * @param _valueBs Poly chain block header raw bytes 197 | * @return Header struct 198 | */ 199 | function deserializeHeader(bytes memory _headerBs) internal pure returns (Header memory) { 200 | Header memory header; 201 | uint256 off = 0; 202 | (header.version, off) = ZeroCopySource.NextUint32(_headerBs, off); 203 | 204 | (header.chainId, off) = ZeroCopySource.NextUint64(_headerBs, off); 205 | 206 | (header.prevBlockHash, off) = ZeroCopySource.NextHash(_headerBs, off); 207 | 208 | (header.transactionsRoot, off) = ZeroCopySource.NextHash(_headerBs, off); 209 | 210 | (header.crossStatesRoot, off) = ZeroCopySource.NextHash(_headerBs, off); 211 | 212 | (header.blockRoot, off) = ZeroCopySource.NextHash(_headerBs, off); 213 | 214 | (header.timestamp, off) = ZeroCopySource.NextUint32(_headerBs, off); 215 | 216 | (header.height, off) = ZeroCopySource.NextUint32(_headerBs, off); 217 | 218 | (header.consensusData, off) = ZeroCopySource.NextUint64(_headerBs, off); 219 | 220 | (header.consensusPayload, off) = ZeroCopySource.NextVarBytes(_headerBs, off); 221 | 222 | (header.nextBookkeeper, off) = ZeroCopySource.NextBytes20(_headerBs, off); 223 | 224 | return header; 225 | } 226 | 227 | /* @notice Deserialize Poly chain block header raw bytes 228 | * @param rawHeader Poly chain block header raw bytes 229 | * @return header hash same as Poly chain 230 | */ 231 | function getHeaderHash(bytes memory rawHeader) internal pure returns (bytes32) { 232 | return sha256(abi.encodePacked(sha256(rawHeader))); 233 | } 234 | } -------------------------------------------------------------------------------- /contracts/core/cross_chain_manager/logic/EthCrossChainManagerForUpgrade.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.16; 2 | 3 | import "./../../../libs/math/SafeMath.sol"; 4 | import "./../../../libs/common/ZeroCopySource.sol"; 5 | import "./../../../libs/common/ZeroCopySink.sol"; 6 | import "./../../../libs/utils/Utils.sol"; 7 | import "./../upgrade/UpgradableECCM.sol"; 8 | import "./../libs/EthCrossChainUtils.sol"; 9 | import "./../interface/IEthCrossChainManager.sol"; 10 | import "./../interface/IEthCrossChainData.sol"; 11 | contract EthCrossChainManagerForUpgrade is IEthCrossChainManager, UpgradableECCM { 12 | using SafeMath for uint256; 13 | 14 | event InitGenesisBlockEvent(uint256 height, bytes rawHeader); 15 | event ChangeBookKeeperEvent(uint256 height, bytes rawHeader); 16 | event CrossChainEvent(address indexed sender, bytes txId, address proxyOrAssetContract, uint64 toChainId, bytes toContract, bytes rawdata); 17 | event VerifyHeaderAndExecuteTxEvent(uint64 fromChainID, bytes toContract, bytes crossChainTxHash, bytes fromChainTxHash); 18 | constructor( 19 | address _eccd, 20 | uint64 _chainId 21 | ) UpgradableECCM(_eccd,_chainId) public {} 22 | 23 | 24 | function crossChain(uint64 toChainId, bytes calldata toContract, bytes calldata method, bytes calldata txData) whenNotPaused external returns (bool) { 25 | revert("Polynetwork v1.0 has been suspended, try v2.0."); 26 | return true; 27 | } 28 | 29 | /* @notice Verify Poly chain header and proof, execute the cross chain tx from Poly chain to Ethereum 30 | * @param proof Poly chain tx merkle proof 31 | * @param rawHeader The header containing crossStateRoot to verify the above tx merkle proof 32 | * @param headerProof The header merkle proof used to verify rawHeader 33 | * @param curRawHeader Any header in current epoch consensus of Poly chain 34 | * @param headerSig The coverted signature veriable for solidity derived from Poly chain consensus nodes' signature 35 | * used to verify the validity of curRawHeader 36 | * @return true or false 37 | */ 38 | function verifyHeaderAndExecuteTx(bytes memory proof, bytes memory rawHeader, bytes memory headerProof, bytes memory curRawHeader,bytes memory headerSig) whenNotPaused public returns (bool){ 39 | ECCUtils.Header memory header = ECCUtils.deserializeHeader(rawHeader); 40 | // Load ehereum cross chain data contract 41 | IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress); 42 | 43 | // Get stored consensus public key bytes of current poly chain epoch and deserialize Poly chain consensus public key bytes to address[] 44 | address[] memory polyChainBKs = ECCUtils.deserializeKeepers(eccd.getCurEpochConPubKeyBytes()); 45 | 46 | uint256 curEpochStartHeight = eccd.getCurEpochStartHeight(); 47 | 48 | uint n = polyChainBKs.length; 49 | if (header.height >= curEpochStartHeight) { 50 | // It's enough to verify rawHeader signature 51 | require(ECCUtils.verifySig(rawHeader, headerSig, polyChainBKs, n - ( n - 1) / 3), "Verify poly chain header signature failed!"); 52 | } else { 53 | // We need to verify the signature of curHeader 54 | require(ECCUtils.verifySig(curRawHeader, headerSig, polyChainBKs, n - ( n - 1) / 3), "Verify poly chain current epoch header signature failed!"); 55 | 56 | // Then use curHeader.StateRoot and headerProof to verify rawHeader.CrossStateRoot 57 | ECCUtils.Header memory curHeader = ECCUtils.deserializeHeader(curRawHeader); 58 | bytes memory proveValue = ECCUtils.merkleProve(headerProof, curHeader.blockRoot); 59 | require(ECCUtils.getHeaderHash(rawHeader) == Utils.bytesToBytes32(proveValue), "verify header proof failed!"); 60 | } 61 | 62 | // Through rawHeader.CrossStatesRoot, the toMerkleValue or cross chain msg can be verified and parsed from proof 63 | bytes memory toMerkleValueBs = ECCUtils.merkleProve(proof, header.crossStatesRoot); 64 | 65 | // Parse the toMerkleValue struct and make sure the tx has not been processed, then mark this tx as processed 66 | ECCUtils.ToMerkleValue memory toMerkleValue = ECCUtils.deserializeMerkleValue(toMerkleValueBs); 67 | require(!eccd.checkIfFromChainTxExist(toMerkleValue.fromChainID, Utils.bytesToBytes32(toMerkleValue.txHash)), "the transaction has been executed!"); 68 | require(eccd.markFromChainTxExist(toMerkleValue.fromChainID, Utils.bytesToBytes32(toMerkleValue.txHash)), "Save crosschain tx exist failed!"); 69 | 70 | // Ethereum ChainId is 2, we need to check the transaction is for Ethereum network 71 | require(toMerkleValue.makeTxParam.toChainId == chainId, "This Tx is not aiming at this network!"); 72 | 73 | // Obtain the targeting contract, so that Ethereum cross chain manager contract can trigger the executation of cross chain tx on Ethereum side 74 | address toContract = Utils.bytesToAddress(toMerkleValue.makeTxParam.toContract); 75 | require(toContract != EthCrossChainDataAddress, "No eccd here!"); 76 | 77 | //TODO: check this part to make sure we commit the next line when doing local net UT test 78 | require(_executeCrossChainTx(toContract, toMerkleValue.makeTxParam.method, toMerkleValue.makeTxParam.args, toMerkleValue.makeTxParam.fromContract, toMerkleValue.fromChainID), "Execute CrossChain Tx failed!"); 79 | 80 | // Fire the cross chain event denoting the executation of cross chain tx is successful, 81 | // and this tx is coming from other public chains to current Ethereum network 82 | emit VerifyHeaderAndExecuteTxEvent(toMerkleValue.fromChainID, toMerkleValue.makeTxParam.toContract, toMerkleValue.txHash, toMerkleValue.makeTxParam.txHash); 83 | 84 | return true; 85 | } 86 | 87 | /* @notice Dynamically invoke the targeting contract, and trigger executation of cross chain tx on Ethereum side 88 | * @param _toContract The targeting contract that will be invoked by the Ethereum Cross Chain Manager contract 89 | * @param _method At which method will be invoked within the targeting contract 90 | * @param _args The parameter that will be passed into the targeting contract 91 | * @param _fromContractAddr From chain smart contract address 92 | * @param _fromChainId Indicate from which chain current cross chain tx comes 93 | * @return true or false 94 | */ 95 | function _executeCrossChainTx(address _toContract, bytes memory _method, bytes memory _args, bytes memory _fromContractAddr, uint64 _fromChainId) internal returns (bool){ 96 | // Ensure the targeting contract gonna be invoked is indeed a contract rather than a normal account address 97 | require(Utils.isContract(_toContract), "The passed in address is not a contract!"); 98 | bytes memory returnData; 99 | bool success; 100 | 101 | // The returnData will be bytes32, the last byte must be 01; 102 | (success, returnData) = _toContract.call(abi.encodePacked(bytes4(keccak256(abi.encodePacked(_method, "(bytes,bytes,uint64)"))), abi.encode(_args, _fromContractAddr, _fromChainId))); 103 | 104 | // Ensure the executation is successful 105 | require(success == true, "EthCrossChain call business contract failed"); 106 | 107 | // Ensure the returned value is true 108 | require(returnData.length != 0, "No return value from business contract!"); 109 | (bool res,) = ZeroCopySource.NextBool(returnData, 31); 110 | require(res == true, "EthCrossChain call business contract return is not true"); 111 | 112 | return true; 113 | } 114 | } -------------------------------------------------------------------------------- /contracts/core/cross_chain_manager/upgrade/EthCrossChainManagerProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | import "./../../../libs/ownership/Ownable.sol"; 3 | import "./../../../libs/lifecycle/Pausable.sol"; 4 | import "./../interface/IUpgradableECCM.sol"; 5 | import "./../interface/IEthCrossChainManagerProxy.sol"; 6 | 7 | contract EthCrossChainManagerProxy is IEthCrossChainManagerProxy, Ownable, Pausable { 8 | address private EthCrossChainManagerAddr_; 9 | 10 | constructor(address _ethCrossChainManagerAddr) public { 11 | EthCrossChainManagerAddr_ = _ethCrossChainManagerAddr; 12 | } 13 | 14 | function pause() onlyOwner public returns (bool) { 15 | if (paused()) { 16 | return true; 17 | } 18 | _pause(); 19 | return true; 20 | } 21 | function unpause() onlyOwner public returns (bool) { 22 | if (!paused()) { 23 | return true; 24 | } 25 | _unpause(); 26 | return true; 27 | } 28 | function pauseEthCrossChainManager() onlyOwner whenNotPaused public returns (bool) { 29 | IUpgradableECCM eccm = IUpgradableECCM(EthCrossChainManagerAddr_); 30 | require(pause(), "pause EthCrossChainManagerProxy contract failed!"); 31 | require(eccm.pause(), "pause EthCrossChainManager contract failed!"); 32 | } 33 | function upgradeEthCrossChainManager(address _newEthCrossChainManagerAddr) onlyOwner whenPaused public returns (bool) { 34 | IUpgradableECCM eccm = IUpgradableECCM(EthCrossChainManagerAddr_); 35 | if (!eccm.paused()) { 36 | require(eccm.pause(), "Pause old EthCrossChainManager contract failed!"); 37 | } 38 | require(eccm.upgradeToNew(_newEthCrossChainManagerAddr), "EthCrossChainManager upgradeToNew failed!"); 39 | IUpgradableECCM neweccm = IUpgradableECCM(_newEthCrossChainManagerAddr); 40 | require(neweccm.isOwner(), "EthCrossChainManagerProxy is not owner of new EthCrossChainManager contract"); 41 | EthCrossChainManagerAddr_ = _newEthCrossChainManagerAddr; 42 | } 43 | function unpauseEthCrossChainManager() onlyOwner whenPaused public returns (bool) { 44 | IUpgradableECCM eccm = IUpgradableECCM(EthCrossChainManagerAddr_); 45 | require(eccm.unpause(), "unpause EthCrossChainManager contract failed!"); 46 | require(unpause(), "unpause EthCrossChainManagerProxy contract failed!"); 47 | } 48 | function getEthCrossChainManager() whenNotPaused public view returns (address) { 49 | return EthCrossChainManagerAddr_; 50 | } 51 | function changeManagerChainID(uint64 _newChainId) onlyOwner whenPaused public { 52 | IUpgradableECCM eccm = IUpgradableECCM(EthCrossChainManagerAddr_); 53 | if (!eccm.paused()) { 54 | require(eccm.pause(), "Pause old EthCrossChainManager contract failed!"); 55 | } 56 | require(eccm.setChainId(_newChainId), "set chain ID failed. "); 57 | } 58 | } -------------------------------------------------------------------------------- /contracts/core/cross_chain_manager/upgrade/UpgradableECCM.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../interface/IEthCrossChainData.sol"; 4 | import "./../interface/IUpgradableECCM.sol"; 5 | import "./../../../libs/lifecycle/Pausable.sol"; 6 | import "./../../../libs/ownership/Ownable.sol"; 7 | 8 | contract UpgradableECCM is IUpgradableECCM, Ownable, Pausable { 9 | address public EthCrossChainDataAddress; 10 | uint64 public chainId; 11 | 12 | constructor (address ethCrossChainDataAddr, uint64 _chainId) Pausable() Ownable() public { 13 | EthCrossChainDataAddress = ethCrossChainDataAddr; 14 | chainId = _chainId; 15 | } 16 | function pause() onlyOwner public returns (bool) { 17 | if (!paused()) { 18 | _pause(); 19 | } 20 | IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress); 21 | if (!eccd.paused()) { 22 | require(eccd.pause(), "pause EthCrossChainData contract failed"); 23 | } 24 | return true; 25 | } 26 | 27 | function unpause() onlyOwner public returns (bool) { 28 | if (paused()) { 29 | _unpause(); 30 | } 31 | IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress); 32 | if (eccd.paused()) { 33 | require(eccd.unpause(), "unpause EthCrossChainData contract failed"); 34 | } 35 | return true; 36 | } 37 | 38 | // if we want to upgrade this contract, we need to invoke this method 39 | function upgradeToNew(address newEthCrossChainManagerAddress) whenPaused onlyOwner public returns (bool) { 40 | IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress); 41 | eccd.transferOwnership(newEthCrossChainManagerAddress); 42 | return true; 43 | } 44 | 45 | function setChainId(uint64 _newChainId) whenPaused onlyOwner public returns (bool) { 46 | chainId = _newChainId; 47 | return true; 48 | } 49 | } -------------------------------------------------------------------------------- /contracts/core/lock_proxy/LockProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../libs/ownership/Ownable.sol"; 4 | import "./../../libs/common/ZeroCopySource.sol"; 5 | import "./../../libs/common/ZeroCopySink.sol"; 6 | import "./../../libs/utils/Utils.sol"; 7 | import "./../../libs/token/ERC20/SafeERC20.sol"; 8 | import "./../cross_chain_manager/interface/IEthCrossChainManager.sol"; 9 | import "./../cross_chain_manager/interface/IEthCrossChainManagerProxy.sol"; 10 | 11 | 12 | contract LockProxy is Ownable { 13 | using SafeMath for uint; 14 | using SafeERC20 for IERC20; 15 | 16 | struct TxArgs { 17 | bytes toAssetHash; 18 | bytes toAddress; 19 | uint256 amount; 20 | } 21 | address public managerProxyContract; 22 | mapping(uint64 => bytes) public proxyHashMap; 23 | mapping(address => mapping(uint64 => bytes)) public assetHashMap; 24 | mapping(address => bool) safeTransfer; 25 | 26 | event SetManagerProxyEvent(address manager); 27 | event BindProxyEvent(uint64 toChainId, bytes targetProxyHash); 28 | event BindAssetEvent(address fromAssetHash, uint64 toChainId, bytes targetProxyHash, uint initialAmount); 29 | event UnlockEvent(address toAssetHash, address toAddress, uint256 amount); 30 | event LockEvent(address fromAssetHash, address fromAddress, uint64 toChainId, bytes toAssetHash, bytes toAddress, uint256 amount); 31 | 32 | modifier onlyManagerContract() { 33 | IEthCrossChainManagerProxy ieccmp = IEthCrossChainManagerProxy(managerProxyContract); 34 | require(_msgSender() == ieccmp.getEthCrossChainManager(), "msgSender is not EthCrossChainManagerContract"); 35 | _; 36 | } 37 | 38 | function setManagerProxy(address ethCCMProxyAddr) onlyOwner public { 39 | managerProxyContract = ethCCMProxyAddr; 40 | emit SetManagerProxyEvent(managerProxyContract); 41 | } 42 | 43 | function bindProxyHash(uint64 toChainId, bytes memory targetProxyHash) onlyOwner public returns (bool) { 44 | proxyHashMap[toChainId] = targetProxyHash; 45 | emit BindProxyEvent(toChainId, targetProxyHash); 46 | return true; 47 | } 48 | 49 | function bindAssetHash(address fromAssetHash, uint64 toChainId, bytes memory toAssetHash) onlyOwner public returns (bool) { 50 | assetHashMap[fromAssetHash][toChainId] = toAssetHash; 51 | emit BindAssetEvent(fromAssetHash, toChainId, toAssetHash, getBalanceFor(fromAssetHash)); 52 | return true; 53 | } 54 | 55 | /* @notice This function is meant to be invoked by the user, 56 | * a certin amount teokens will be locked in the proxy contract the invoker/msg.sender immediately. 57 | * Then the same amount of tokens will be unloked from target chain proxy contract at the target chain with chainId later. 58 | * @param fromAssetHash The asset address in current chain, uniformly named as `fromAssetHash` 59 | * @param toChainId The target chain id 60 | * 61 | * @param toAddress The address in bytes format to receive same amount of tokens in target chain 62 | * @param amount The amount of tokens to be crossed from ethereum to the chain with chainId 63 | */ 64 | function lock(address fromAssetHash, uint64 toChainId, bytes memory toAddress, uint256 amount) public payable returns (bool) { 65 | require(amount != 0, "amount cannot be zero!"); 66 | 67 | 68 | require(_transferToContract(fromAssetHash, amount), "transfer asset from fromAddress to lock_proxy contract failed!"); 69 | 70 | bytes memory toAssetHash = assetHashMap[fromAssetHash][toChainId]; 71 | require(toAssetHash.length != 0, "empty illegal toAssetHash"); 72 | 73 | TxArgs memory txArgs = TxArgs({ 74 | toAssetHash: toAssetHash, 75 | toAddress: toAddress, 76 | amount: amount 77 | }); 78 | bytes memory txData = _serializeTxArgs(txArgs); 79 | 80 | IEthCrossChainManagerProxy eccmp = IEthCrossChainManagerProxy(managerProxyContract); 81 | address eccmAddr = eccmp.getEthCrossChainManager(); 82 | IEthCrossChainManager eccm = IEthCrossChainManager(eccmAddr); 83 | 84 | bytes memory toProxyHash = proxyHashMap[toChainId]; 85 | require(toProxyHash.length != 0, "empty illegal toProxyHash"); 86 | require(eccm.crossChain(toChainId, toProxyHash, "unlock", txData), "EthCrossChainManager crossChain executed error!"); 87 | 88 | emit LockEvent(fromAssetHash, _msgSender(), toChainId, toAssetHash, toAddress, amount); 89 | 90 | return true; 91 | 92 | } 93 | 94 | // /* @notice This function is meant to be invoked by the ETH crosschain management contract, 95 | // * then mint a certin amount of tokens to the designated address since a certain amount 96 | // * was burnt from the source chain invoker. 97 | // * @param argsBs The argument bytes recevied by the ethereum lock proxy contract, need to be deserialized. 98 | // * based on the way of serialization in the source chain proxy contract. 99 | // * @param fromContractAddr The source chain contract address 100 | // * @param fromChainId The source chain id 101 | // */ 102 | function unlock(bytes memory argsBs, bytes memory fromContractAddr, uint64 fromChainId) onlyManagerContract public returns (bool) { 103 | TxArgs memory args = _deserializeTxArgs(argsBs); 104 | 105 | require(fromContractAddr.length != 0, "from proxy contract address cannot be empty"); 106 | require(Utils.equalStorage(proxyHashMap[fromChainId], fromContractAddr), "From Proxy contract address error!"); 107 | 108 | require(args.toAssetHash.length != 0, "toAssetHash cannot be empty"); 109 | address toAssetHash = Utils.bytesToAddress(args.toAssetHash); 110 | 111 | require(args.toAddress.length != 0, "toAddress cannot be empty"); 112 | address toAddress = Utils.bytesToAddress(args.toAddress); 113 | 114 | 115 | require(_transferFromContract(toAssetHash, toAddress, args.amount), "transfer asset from lock_proxy contract to toAddress failed!"); 116 | 117 | emit UnlockEvent(toAssetHash, toAddress, args.amount); 118 | return true; 119 | } 120 | 121 | function getBalanceFor(address fromAssetHash) public view returns (uint256) { 122 | if (fromAssetHash == address(0)) { 123 | // return address(this).balance; // this expression would result in error: Failed to decode output: Error: insufficient data for uint256 type 124 | address selfAddr = address(this); 125 | return selfAddr.balance; 126 | } else { 127 | IERC20 erc20Token = IERC20(fromAssetHash); 128 | return erc20Token.balanceOf(address(this)); 129 | } 130 | } 131 | function _transferToContract(address fromAssetHash, uint256 amount) internal returns (bool) { 132 | if (fromAssetHash == address(0)) { 133 | // fromAssetHash === address(0) denotes user choose to lock ether 134 | // passively check if the received msg.value equals amount 135 | require(msg.value != 0, "transferred ether cannot be zero!"); 136 | require(msg.value == amount, "transferred ether is not equal to amount!"); 137 | } else { 138 | // make sure lockproxy contract will decline any received ether 139 | require(msg.value == 0, "there should be no ether transfer!"); 140 | // actively transfer amount of asset from msg.sender to lock_proxy contract 141 | require(_transferERC20ToContract(fromAssetHash, _msgSender(), address(this), amount), "transfer erc20 asset to lock_proxy contract failed!"); 142 | } 143 | return true; 144 | } 145 | function _transferFromContract(address toAssetHash, address toAddress, uint256 amount) internal returns (bool) { 146 | if (toAssetHash == address(0x0000000000000000000000000000000000000000)) { 147 | // toAssetHash === address(0) denotes contract needs to unlock ether to toAddress 148 | // convert toAddress from 'address' type to 'address payable' type, then actively transfer ether 149 | address(uint160(toAddress)).transfer(amount); 150 | } else { 151 | // actively transfer amount of asset from lock_proxy contract to toAddress 152 | require(_transferERC20FromContract(toAssetHash, toAddress, amount), "transfer erc20 asset from lock_proxy contract to toAddress failed!"); 153 | } 154 | return true; 155 | } 156 | 157 | 158 | function _transferERC20ToContract(address fromAssetHash, address fromAddress, address toAddress, uint256 amount) internal returns (bool) { 159 | IERC20 erc20Token = IERC20(fromAssetHash); 160 | // require(erc20Token.transferFrom(fromAddress, toAddress, amount), "trasnfer ERC20 Token failed!"); 161 | erc20Token.safeTransferFrom(fromAddress, toAddress, amount); 162 | return true; 163 | } 164 | function _transferERC20FromContract(address toAssetHash, address toAddress, uint256 amount) internal returns (bool) { 165 | IERC20 erc20Token = IERC20(toAssetHash); 166 | // require(erc20Token.transfer(toAddress, amount), "trasnfer ERC20 Token failed!"); 167 | erc20Token.safeTransfer(toAddress, amount); 168 | return true; 169 | } 170 | 171 | function _serializeTxArgs(TxArgs memory args) internal pure returns (bytes memory) { 172 | bytes memory buff; 173 | buff = abi.encodePacked( 174 | ZeroCopySink.WriteVarBytes(args.toAssetHash), 175 | ZeroCopySink.WriteVarBytes(args.toAddress), 176 | ZeroCopySink.WriteUint255(args.amount) 177 | ); 178 | return buff; 179 | } 180 | 181 | function _deserializeTxArgs(bytes memory valueBs) internal pure returns (TxArgs memory) { 182 | TxArgs memory args; 183 | uint256 off = 0; 184 | (args.toAssetHash, off) = ZeroCopySource.NextVarBytes(valueBs, off); 185 | (args.toAddress, off) = ZeroCopySource.NextVarBytes(valueBs, off); 186 | (args.amount, off) = ZeroCopySource.NextUint255(valueBs, off); 187 | return args; 188 | } 189 | } -------------------------------------------------------------------------------- /contracts/core/lock_proxy/LockProxySingleAsset.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../libs/ownership/Ownable.sol"; 4 | import "./../../libs/common/ZeroCopySource.sol"; 5 | import "./../../libs/common/ZeroCopySink.sol"; 6 | import "./../../libs/utils/Utils.sol"; 7 | import "./../../libs/token/ERC20/SafeERC20.sol"; 8 | import "./../../libs/token/ERC20/ERC20.sol"; 9 | import "./../../libs/token/ERC20/ERC20Detailed.sol"; 10 | import "./../cross_chain_manager/interface/IEthCrossChainManager.sol"; 11 | import "./../cross_chain_manager/interface/IEthCrossChainManagerProxy.sol"; 12 | 13 | contract bridgeAsset is Context, ERC20, ERC20Detailed { 14 | 15 | address public bridge; 16 | 17 | constructor (string memory name, string memory symbol, uint8 decimals, address bridge_) 18 | public ERC20Detailed(name, symbol, decimals) { 19 | bridge = bridge_; 20 | } 21 | 22 | modifier onlyBridge() { 23 | require(_msgSender() == bridge, "msgSender is not Bridge!"); 24 | _; 25 | } 26 | 27 | function mint(address to, uint256 amount) public onlyBridge { 28 | _mint(to, amount); 29 | } 30 | 31 | function burnFrom(address account, uint256 amount) public onlyBridge { 32 | _burnFrom(account, amount); 33 | } 34 | } 35 | 36 | contract LockProxySingleAsset is Ownable { 37 | using SafeMath for uint; 38 | using SafeERC20 for IERC20; 39 | 40 | struct TxArgs { 41 | bytes toAddress; 42 | uint256 amount; 43 | } 44 | bridgeAsset public token; 45 | address public managerProxyContract; 46 | mapping(uint64 => bytes) public proxyHashMap; 47 | 48 | event SetManagerProxyEvent(address manager); 49 | event BindProxyEvent(uint64 toChainId, bytes targetProxyHash); 50 | event UnlockEvent(address toAssetHash, address toAddress, uint256 amount); 51 | event LockEvent(address fromAssetHash, address fromAddress, uint64 toChainId, bytes toAssetHash, bytes toAddress, uint256 amount); 52 | 53 | constructor(string memory name, string memory symbol, uint8 decimals) public { 54 | token = new bridgeAsset(name, symbol, decimals, address(this)); 55 | } 56 | 57 | modifier onlyManagerContract() { 58 | IEthCrossChainManagerProxy ieccmp = IEthCrossChainManagerProxy(managerProxyContract); 59 | require(_msgSender() == ieccmp.getEthCrossChainManager(), "msgSender is not EthCrossChainManagerContract"); 60 | _; 61 | } 62 | 63 | function setManagerProxy(address ethCCMProxyAddr) onlyOwner public { 64 | managerProxyContract = ethCCMProxyAddr; 65 | emit SetManagerProxyEvent(managerProxyContract); 66 | } 67 | 68 | function bindProxyHash(uint64 toChainId, bytes memory targetProxyHash) onlyOwner public returns (bool) { 69 | proxyHashMap[toChainId] = targetProxyHash; 70 | emit BindProxyEvent(toChainId, targetProxyHash); 71 | return true; 72 | } 73 | 74 | /* @notice This function is meant to be invoked by the user, 75 | * a certin amount teokens will be locked in the proxy contract the invoker/msg.sender immediately. 76 | * Then the same amount of tokens will be unloked from target chain proxy contract at the target chain with chainId later. 77 | * @param fromAssetHash The asset address in current chain, uniformly named as `fromAssetHash` 78 | * @param toChainId The target chain id 79 | * 80 | * @param toAddress The address in bytes format to receive same amount of tokens in target chain 81 | * @param amount The amount of tokens to be crossed from ethereum to the chain with chainId 82 | */ 83 | function lock(uint64 toChainId, bytes memory toAddress, uint256 amount) public payable returns (bool) { 84 | require(amount != 0, "amount cannot be zero!"); 85 | 86 | bridgeAsset(token).burnFrom(_msgSender(), amount); 87 | 88 | TxArgs memory txArgs = TxArgs({ 89 | toAddress: toAddress, 90 | amount: amount 91 | }); 92 | bytes memory txData = _serializeTxArgs(txArgs); 93 | 94 | IEthCrossChainManagerProxy eccmp = IEthCrossChainManagerProxy(managerProxyContract); 95 | address eccmAddr = eccmp.getEthCrossChainManager(); 96 | IEthCrossChainManager eccm = IEthCrossChainManager(eccmAddr); 97 | 98 | bytes memory toProxyHash = proxyHashMap[toChainId]; 99 | require(toProxyHash.length != 0, "empty illegal toProxyHash"); 100 | require(eccm.crossChain(toChainId, toProxyHash, "unlock", txData), "EthCrossChainManager crossChain executed error!"); 101 | 102 | emit LockEvent(address(token), _msgSender(), toChainId, toProxyHash, toAddress, amount); 103 | 104 | return true; 105 | 106 | } 107 | 108 | // /* @notice This function is meant to be invoked by the ETH crosschain management contract, 109 | // * then mint a certin amount of tokens to the designated address since a certain amount 110 | // * was burnt from the source chain invoker. 111 | // * @param argsBs The argument bytes recevied by the ethereum lock proxy contract, need to be deserialized. 112 | // * based on the way of serialization in the source chain proxy contract. 113 | // * @param fromContractAddr The source chain contract address 114 | // * @param fromChainId The source chain id 115 | // */ 116 | function unlock(bytes memory argsBs, bytes memory fromContractAddr, uint64 fromChainId) onlyManagerContract public returns (bool) { 117 | TxArgs memory args = _deserializeTxArgs(argsBs); 118 | 119 | require(fromContractAddr.length != 0, "from proxy contract address cannot be empty"); 120 | require(Utils.equalStorage(proxyHashMap[fromChainId], fromContractAddr), "From Proxy contract address error!"); 121 | 122 | require(args.toAddress.length != 0, "toAddress cannot be empty"); 123 | address toAddress = Utils.bytesToAddress(args.toAddress); 124 | 125 | bridgeAsset(token).mint(toAddress, args.amount); 126 | 127 | emit UnlockEvent(address(token), toAddress, args.amount); 128 | return true; 129 | } 130 | 131 | function _serializeTxArgs(TxArgs memory args) internal pure returns (bytes memory) { 132 | bytes memory buff; 133 | buff = abi.encodePacked( 134 | ZeroCopySink.WriteVarBytes(args.toAddress), 135 | ZeroCopySink.WriteUint255(args.amount) 136 | ); 137 | return buff; 138 | } 139 | 140 | function _deserializeTxArgs(bytes memory valueBs) internal pure returns (TxArgs memory) { 141 | TxArgs memory args; 142 | uint256 off = 0; 143 | (args.toAddress, off) = ZeroCopySource.NextVarBytes(valueBs, off); 144 | (args.amount, off) = ZeroCopySource.NextUint255(valueBs, off); 145 | return args; 146 | } 147 | } -------------------------------------------------------------------------------- /contracts/core/lock_proxy/RippleLockProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../libs/ownership/Ownable.sol"; 4 | import "./../../libs/common/ZeroCopySource.sol"; 5 | import "./../../libs/common/ZeroCopySink.sol"; 6 | import "./../../libs/utils/Utils.sol"; 7 | import "./../../libs/token/ERC20/SafeERC20.sol"; 8 | import "./../../libs/token/ERC20/ERC20.sol"; 9 | import "./../../libs/token/ERC20/ERC20Detailed.sol"; 10 | import "./../cross_chain_manager/interface/IEthCrossChainManager.sol"; 11 | import "./../cross_chain_manager/interface/IEthCrossChainManagerProxy.sol"; 12 | 13 | contract bridgeAsset is Context, ERC20, ERC20Detailed { 14 | 15 | address public bridge; 16 | 17 | constructor (string memory name, string memory symbol, uint8 decimals, address bridge_) 18 | public ERC20Detailed(name, symbol, decimals) { 19 | bridge = bridge_; 20 | } 21 | 22 | modifier onlyBridge() { 23 | require(_msgSender() == bridge, "msgSender is not Bridge!"); 24 | _; 25 | } 26 | 27 | function mint(address to, uint256 amount) public onlyBridge { 28 | _mint(to, amount); 29 | } 30 | 31 | function burnFrom(address account, uint256 amount) public onlyBridge { 32 | _burnFrom(account, amount); 33 | } 34 | } 35 | 36 | contract RippleLockProxy is Ownable { 37 | using SafeMath for uint; 38 | using SafeERC20 for IERC20; 39 | 40 | struct TxArgs { 41 | bytes toAddress; 42 | uint256 amount; 43 | } 44 | bridgeAsset public token; 45 | address public managerProxyContract; 46 | mapping(uint64 => bytes) public proxyHashMap; 47 | 48 | uint public rippleMinAmount = 30000000; 49 | uint64 public rippleChainId = 39; 50 | uint public rippleAddressLength = 20; 51 | 52 | event SetManagerProxyEvent(address manager); 53 | event BindProxyEvent(uint64 toChainId, bytes targetProxyHash); 54 | event UnlockEvent(address toAssetHash, address toAddress, uint256 amount); 55 | event LockEvent(address fromAssetHash, address fromAddress, uint64 toChainId, bytes toAssetHash, bytes toAddress, uint256 amount); 56 | 57 | constructor(string memory name, string memory symbol, uint8 decimals) public { 58 | token = new bridgeAsset(name, symbol, decimals, address(this)); 59 | } 60 | 61 | modifier onlyManagerContract() { 62 | IEthCrossChainManagerProxy ieccmp = IEthCrossChainManagerProxy(managerProxyContract); 63 | require(_msgSender() == ieccmp.getEthCrossChainManager(), "msgSender is not EthCrossChainManagerContract"); 64 | _; 65 | } 66 | 67 | function setManagerProxy(address ethCCMProxyAddr) onlyOwner public { 68 | managerProxyContract = ethCCMProxyAddr; 69 | emit SetManagerProxyEvent(managerProxyContract); 70 | } 71 | 72 | function bindProxyHash(uint64 toChainId, bytes memory targetProxyHash) onlyOwner public returns (bool) { 73 | proxyHashMap[toChainId] = targetProxyHash; 74 | emit BindProxyEvent(toChainId, targetProxyHash); 75 | return true; 76 | } 77 | 78 | function rippleSetup(uint64 _rippleChainId, uint _rippleMinAmount, uint _rippleAddressLength) external onlyOwner { 79 | rippleChainId = _rippleChainId; 80 | rippleAddressLength = _rippleAddressLength; 81 | rippleMinAmount = _rippleMinAmount; 82 | } 83 | 84 | function rippleSetup(uint64 _rippleChainId) external onlyOwner { 85 | rippleChainId = _rippleChainId; 86 | } 87 | 88 | /* @notice This function is meant to be invoked by the user, 89 | * a certin amount teokens will be locked in the proxy contract the invoker/msg.sender immediately. 90 | * Then the same amount of tokens will be unloked from target chain proxy contract at the target chain with chainId later. 91 | * @param fromAssetHash The asset address in current chain, uniformly named as `fromAssetHash` 92 | * @param toChainId The target chain id 93 | * 94 | * @param toAddress The address in bytes format to receive same amount of tokens in target chain 95 | * @param amount The amount of tokens to be crossed from ethereum to the chain with chainId 96 | */ 97 | function lock(uint64 toChainId, bytes memory toAddress, uint256 amount) public payable returns (bool) { 98 | _rippleCheck(toChainId, toAddress, amount); 99 | require(amount != 0, "amount cannot be zero!"); 100 | 101 | bridgeAsset(token).burnFrom(_msgSender(), amount); 102 | 103 | TxArgs memory txArgs = TxArgs({ 104 | toAddress: toAddress, 105 | amount: amount 106 | }); 107 | bytes memory txData = _serializeTxArgs(txArgs); 108 | 109 | IEthCrossChainManagerProxy eccmp = IEthCrossChainManagerProxy(managerProxyContract); 110 | address eccmAddr = eccmp.getEthCrossChainManager(); 111 | IEthCrossChainManager eccm = IEthCrossChainManager(eccmAddr); 112 | 113 | bytes memory toProxyHash = proxyHashMap[toChainId]; 114 | require(toProxyHash.length != 0, "empty illegal toProxyHash"); 115 | require(eccm.crossChain(toChainId, toProxyHash, "unlock", txData), "EthCrossChainManager crossChain executed error!"); 116 | 117 | emit LockEvent(address(token), _msgSender(), toChainId, toProxyHash, toAddress, amount); 118 | 119 | return true; 120 | 121 | } 122 | 123 | // /* @notice This function is meant to be invoked by the ETH crosschain management contract, 124 | // * then mint a certin amount of tokens to the designated address since a certain amount 125 | // * was burnt from the source chain invoker. 126 | // * @param argsBs The argument bytes recevied by the ethereum lock proxy contract, need to be deserialized. 127 | // * based on the way of serialization in the source chain proxy contract. 128 | // * @param fromContractAddr The source chain contract address 129 | // * @param fromChainId The source chain id 130 | // */ 131 | function unlock(bytes memory argsBs, bytes memory fromContractAddr, uint64 fromChainId) onlyManagerContract public returns (bool) { 132 | TxArgs memory args = _deserializeTxArgs(argsBs); 133 | 134 | require(fromContractAddr.length != 0, "from proxy contract address cannot be empty"); 135 | require(Utils.equalStorage(proxyHashMap[fromChainId], fromContractAddr), "From Proxy contract address error!"); 136 | 137 | require(args.toAddress.length != 0, "toAddress cannot be empty"); 138 | address toAddress = Utils.bytesToAddress(args.toAddress); 139 | 140 | bridgeAsset(token).mint(toAddress, args.amount); 141 | 142 | emit UnlockEvent(address(token), toAddress, args.amount); 143 | return true; 144 | } 145 | 146 | function _rippleCheck(uint64 toChainId, bytes memory toAddress, uint amount) internal view { 147 | if (toChainId == rippleChainId) { 148 | require(toAddress.length == rippleAddressLength, "invalid ripple address"); 149 | require(amount >= rippleMinAmount, "amount less than the minimum"); 150 | } 151 | } 152 | 153 | function _serializeTxArgs(TxArgs memory args) internal pure returns (bytes memory) { 154 | bytes memory buff; 155 | buff = abi.encodePacked( 156 | ZeroCopySink.WriteVarBytes(args.toAddress), 157 | ZeroCopySink.WriteUint255(args.amount) 158 | ); 159 | return buff; 160 | } 161 | 162 | function _deserializeTxArgs(bytes memory valueBs) internal pure returns (TxArgs memory) { 163 | TxArgs memory args; 164 | uint256 off = 0; 165 | (args.toAddress, off) = ZeroCopySource.NextVarBytes(valueBs, off); 166 | (args.amount, off) = ZeroCopySource.NextUint255(valueBs, off); 167 | return args; 168 | } 169 | } -------------------------------------------------------------------------------- /contracts/core/wrapper/PolyWrapper_v1: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.5.0; 3 | 4 | import "../../libs/token/ERC20/SafeERC20.sol"; 5 | import "../../libs/token/ERC20/IERC20.sol"; 6 | import "../../libs/ownership/Ownable.sol"; 7 | import "../../libs/utils/ReentrancyGuard.sol"; 8 | import "../../libs/math/SafeMath.sol"; 9 | import "../../libs/lifecycle/Pausable.sol"; 10 | 11 | import "./interfaces/ILockProxy.sol"; 12 | 13 | contract PolyWrapper is Ownable, Pausable, ReentrancyGuard { 14 | using SafeMath for uint; 15 | using SafeERC20 for IERC20; 16 | 17 | uint public chainId; 18 | address public feeCollector; 19 | 20 | ILockProxy public lockProxy; 21 | 22 | constructor(address _owner, uint _chainId) public { 23 | require(_chainId != 0, "!legal"); 24 | transferOwnership(_owner); 25 | chainId = _chainId; 26 | } 27 | 28 | function setFeeCollector(address collector) external onlyOwner { 29 | require(collector != address(0), "emtpy address"); 30 | feeCollector = collector; 31 | } 32 | 33 | 34 | function setLockProxy(address _lockProxy) external onlyOwner { 35 | require(_lockProxy != address(0)); 36 | lockProxy = ILockProxy(_lockProxy); 37 | require(lockProxy.managerProxyContract() != address(0), "not lockproxy"); 38 | } 39 | 40 | function pause() external onlyOwner { 41 | _pause(); 42 | } 43 | 44 | function unpause() external onlyOwner { 45 | _unpause(); 46 | } 47 | 48 | 49 | function extractFee(address token) external { 50 | require(msg.sender == feeCollector, "!feeCollector"); 51 | if (token == address(0)) { 52 | msg.sender.transfer(address(this).balance); 53 | } else { 54 | IERC20(token).safeTransfer(feeCollector, IERC20(token).balanceOf(address(this))); 55 | } 56 | } 57 | 58 | function lock(address fromAsset, uint64 toChainId, bytes memory toAddress, uint amount, uint fee, uint id) public payable nonReentrant whenNotPaused { 59 | 60 | require(toChainId != chainId && toChainId != 0, "!toChainId"); 61 | require(amount > fee, "amount less than fee"); 62 | require(toAddress.length !=0, "empty toAddress"); 63 | address addr; 64 | assembly { addr := mload(add(toAddress,0x14)) } 65 | require(addr != address(0),"zero toAddress"); 66 | 67 | _pull(fromAsset, amount); 68 | 69 | _push(fromAsset, toChainId, toAddress, amount.sub(fee)); 70 | 71 | emit PolyWrapperLock(fromAsset, msg.sender, toChainId, toAddress, amount.sub(fee), fee, id); 72 | } 73 | 74 | function speedUp(address fromAsset, bytes memory txHash, uint fee) public payable nonReentrant whenNotPaused { 75 | _pull(fromAsset, fee); 76 | emit PolyWrapperSpeedUp(fromAsset, txHash, msg.sender, fee); 77 | } 78 | 79 | function _pull(address fromAsset, uint amount) internal { 80 | if (fromAsset == address(0)) { 81 | require(msg.value == amount, "insufficient ether"); 82 | } else { 83 | IERC20(fromAsset).safeTransferFrom(msg.sender, address(this), amount); 84 | } 85 | } 86 | 87 | function _push(address fromAsset, uint64 toChainId, bytes memory toAddress, uint amount) internal { 88 | if (fromAsset == address(0)) { 89 | require(lockProxy.lock.value(amount)(fromAsset, toChainId, toAddress, amount), "lock ether fail"); 90 | } else { 91 | IERC20(fromAsset).safeApprove(address(lockProxy), 0); 92 | IERC20(fromAsset).safeApprove(address(lockProxy), amount); 93 | require(lockProxy.lock(fromAsset, toChainId, toAddress, amount), "lock erc20 fail"); 94 | } 95 | } 96 | 97 | event PolyWrapperLock(address indexed fromAsset, address indexed sender, uint64 toChainId, bytes toAddress, uint net, uint fee, uint id); 98 | event PolyWrapperSpeedUp(address indexed fromAsset, bytes indexed txHash, address indexed sender, uint efee); 99 | 100 | } 101 | -------------------------------------------------------------------------------- /contracts/core/wrapper/PolyWrapper_v1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.5.0; 3 | 4 | import "../../libs/token/ERC20/SafeERC20.sol"; 5 | import "../../libs/token/ERC20/IERC20.sol"; 6 | import "../../libs/ownership/Ownable.sol"; 7 | import "../../libs/utils/ReentrancyGuard.sol"; 8 | import "../../libs/math/SafeMath.sol"; 9 | import "../../libs/lifecycle/Pausable.sol"; 10 | 11 | import "./interfaces/ILockProxy.sol"; 12 | 13 | contract PolyWrapperV1 is Ownable, Pausable, ReentrancyGuard { 14 | using SafeMath for uint; 15 | using SafeERC20 for IERC20; 16 | 17 | uint public chainId; 18 | address public feeCollector; 19 | 20 | ILockProxy public lockProxy; 21 | 22 | constructor(address _owner, uint _chainId) public { 23 | require(_chainId != 0, "!legal"); 24 | transferOwnership(_owner); 25 | chainId = _chainId; 26 | } 27 | 28 | function setFeeCollector(address collector) external onlyOwner { 29 | require(collector != address(0), "emtpy address"); 30 | feeCollector = collector; 31 | } 32 | 33 | 34 | function setLockProxy(address _lockProxy) external onlyOwner { 35 | require(_lockProxy != address(0)); 36 | lockProxy = ILockProxy(_lockProxy); 37 | require(lockProxy.managerProxyContract() != address(0), "not lockproxy"); 38 | } 39 | 40 | function pause() external onlyOwner { 41 | _pause(); 42 | } 43 | 44 | function unpause() external onlyOwner { 45 | _unpause(); 46 | } 47 | 48 | 49 | function extractFee(address token) external { 50 | require(msg.sender == feeCollector, "!feeCollector"); 51 | if (token == address(0)) { 52 | msg.sender.transfer(address(this).balance); 53 | } else { 54 | IERC20(token).safeTransfer(feeCollector, IERC20(token).balanceOf(address(this))); 55 | } 56 | } 57 | 58 | function lock(address fromAsset, uint64 toChainId, bytes memory toAddress, uint amount, uint fee, uint id) public payable nonReentrant whenNotPaused { 59 | 60 | require(toChainId != chainId && toChainId != 0, "!toChainId"); 61 | require(amount > fee, "amount less than fee"); 62 | require(toAddress.length !=0, "empty toAddress"); 63 | address addr; 64 | assembly { addr := mload(add(toAddress,0x14)) } 65 | require(addr != address(0),"zero toAddress"); 66 | 67 | _pull(fromAsset, amount); 68 | 69 | _push(fromAsset, toChainId, toAddress, amount.sub(fee)); 70 | 71 | emit PolyWrapperLock(fromAsset, msg.sender, toChainId, toAddress, amount.sub(fee), fee, id); 72 | } 73 | 74 | function speedUp(address fromAsset, bytes memory txHash, uint fee) public payable nonReentrant whenNotPaused { 75 | _pull(fromAsset, fee); 76 | emit PolyWrapperSpeedUp(fromAsset, txHash, msg.sender, fee); 77 | } 78 | 79 | function _pull(address fromAsset, uint amount) internal { 80 | if (fromAsset == address(0)) { 81 | require(msg.value == amount, "insufficient ether"); 82 | } else { 83 | IERC20(fromAsset).safeTransferFrom(msg.sender, address(this), amount); 84 | } 85 | } 86 | 87 | function _push(address fromAsset, uint64 toChainId, bytes memory toAddress, uint amount) internal { 88 | if (fromAsset == address(0)) { 89 | require(lockProxy.lock.value(amount)(fromAsset, toChainId, toAddress, amount), "lock ether fail"); 90 | } else { 91 | IERC20(fromAsset).safeApprove(address(lockProxy), 0); 92 | IERC20(fromAsset).safeApprove(address(lockProxy), amount); 93 | require(lockProxy.lock(fromAsset, toChainId, toAddress, amount), "lock erc20 fail"); 94 | } 95 | } 96 | 97 | event PolyWrapperLock(address indexed fromAsset, address indexed sender, uint64 toChainId, bytes toAddress, uint net, uint fee, uint id); 98 | event PolyWrapperSpeedUp(address indexed fromAsset, bytes indexed txHash, address indexed sender, uint efee); 99 | 100 | } 101 | -------------------------------------------------------------------------------- /contracts/core/wrapper/PolyWrapper_v2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.5.0; 3 | 4 | import "../../libs/token/ERC20/SafeERC20.sol"; 5 | import "../../libs/token/ERC20/IERC20.sol"; 6 | import "../../libs/ownership/Ownable.sol"; 7 | import "../../libs/utils/ReentrancyGuard.sol"; 8 | import "../../libs/math/SafeMath.sol"; 9 | import "../../libs/lifecycle/Pausable.sol"; 10 | 11 | import "./interfaces/ILockProxy.sol"; 12 | 13 | contract PolyWrapperV2 is Ownable, Pausable, ReentrancyGuard { 14 | using SafeMath for uint; 15 | using SafeERC20 for IERC20; 16 | 17 | uint public chainId; 18 | address public feeCollector; 19 | 20 | ILockProxy public lockProxy; 21 | 22 | constructor(address _owner, uint _chainId) public { 23 | require(_chainId != 0, "!legal"); 24 | transferOwnership(_owner); 25 | chainId = _chainId; 26 | } 27 | 28 | function setFeeCollector(address collector) external onlyOwner { 29 | require(collector != address(0), "emtpy address"); 30 | feeCollector = collector; 31 | } 32 | 33 | 34 | function setLockProxy(address _lockProxy) external onlyOwner { 35 | require(_lockProxy != address(0)); 36 | lockProxy = ILockProxy(_lockProxy); 37 | require(lockProxy.managerProxyContract() != address(0), "not lockproxy"); 38 | } 39 | 40 | function pause() external onlyOwner { 41 | _pause(); 42 | } 43 | 44 | function unpause() external onlyOwner { 45 | _unpause(); 46 | } 47 | 48 | 49 | function extractFee(address token) external { 50 | require(msg.sender == feeCollector, "!feeCollector"); 51 | if (token == address(0)) { 52 | msg.sender.transfer(address(this).balance); 53 | } else { 54 | IERC20(token).safeTransfer(feeCollector, IERC20(token).balanceOf(address(this))); 55 | } 56 | } 57 | 58 | function lock(address fromAsset, uint64 toChainId, bytes memory toAddress, uint amount, uint fee, uint id) public payable nonReentrant whenNotPaused { 59 | 60 | require(toChainId != chainId && toChainId != 0, "!toChainId"); 61 | require(toAddress.length !=0, "empty toAddress"); 62 | address addr; 63 | assembly { addr := mload(add(toAddress,0x14)) } 64 | require(addr != address(0),"zero toAddress"); 65 | 66 | _pull(fromAsset, amount); 67 | 68 | amount = _checkoutFee(fromAsset, amount, fee); 69 | 70 | _push(fromAsset, toChainId, toAddress, amount); 71 | 72 | emit PolyWrapperLock(fromAsset, msg.sender, toChainId, toAddress, amount, fee, id); 73 | } 74 | 75 | function speedUp(address fromAsset, bytes memory txHash, uint fee) public payable nonReentrant whenNotPaused { 76 | _pull(fromAsset, fee); 77 | emit PolyWrapperSpeedUp(fromAsset, txHash, msg.sender, fee); 78 | } 79 | 80 | function _pull(address fromAsset, uint amount) internal { 81 | if (fromAsset == address(0)) { 82 | require(msg.value == amount, "insufficient ether"); 83 | } else { 84 | IERC20(fromAsset).safeTransferFrom(msg.sender, address(this), amount); 85 | } 86 | } 87 | 88 | // take fee in the form of ether 89 | function _checkoutFee(address fromAsset, uint amount, uint fee) internal view returns (uint) { 90 | if (fromAsset == address(0)) { 91 | require(msg.value >= amount, "insufficient ether"); 92 | require(amount > fee, "amount less than fee"); 93 | return amount.sub(fee); 94 | } else { 95 | require(msg.value >= fee, "insufficient ether"); 96 | return amount; 97 | } 98 | } 99 | 100 | function _push(address fromAsset, uint64 toChainId, bytes memory toAddress, uint amount) internal { 101 | if (fromAsset == address(0)) { 102 | require(lockProxy.lock.value(amount)(fromAsset, toChainId, toAddress, amount), "lock ether fail"); 103 | } else { 104 | IERC20(fromAsset).safeApprove(address(lockProxy), 0); 105 | IERC20(fromAsset).safeApprove(address(lockProxy), amount); 106 | require(lockProxy.lock(fromAsset, toChainId, toAddress, amount), "lock erc20 fail"); 107 | } 108 | } 109 | 110 | event PolyWrapperLock(address indexed fromAsset, address indexed sender, uint64 toChainId, bytes toAddress, uint net, uint fee, uint id); 111 | event PolyWrapperSpeedUp(address indexed fromAsset, bytes indexed txHash, address indexed sender, uint efee); 112 | 113 | } -------------------------------------------------------------------------------- /contracts/core/wrapper/interfaces/ILockProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.5.0; 3 | 4 | interface ILockProxy { 5 | function managerProxyContract() external view returns (address); 6 | function proxyHashMap(uint64) external view returns (bytes memory); 7 | function assetHashMap(address, uint64) external view returns (bytes memory); 8 | function getBalanceFor(address) external view returns (uint256); 9 | function setManagerProxy( 10 | address eccmpAddr 11 | ) external; 12 | 13 | function bindProxyHash( 14 | uint64 toChainId, 15 | bytes calldata targetProxyHash 16 | ) external returns (bool); 17 | 18 | function bindAssetHash( 19 | address fromAssetHash, 20 | uint64 toChainId, 21 | bytes calldata toAssetHash 22 | ) external returns (bool); 23 | 24 | function lock( 25 | address fromAssetHash, 26 | uint64 toChainId, 27 | bytes calldata toAddress, 28 | uint256 amount 29 | ) external payable returns (bool); 30 | } -------------------------------------------------------------------------------- /contracts/core/wrapper/interfaces/IPolyWrapper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | interface IPolyWrapper { 4 | function feeCollector() external view returns (address); 5 | function lockProxy() external view returns (address); 6 | function paused() external view returns (bool); 7 | function chainId() external view returns (uint); 8 | function owner() external view returns (address); 9 | 10 | function lock( 11 | address fromAsset, 12 | uint64 toChainId, 13 | bytes calldata toAddress, 14 | uint amount, 15 | uint fee, 16 | uint id 17 | ) external payable; 18 | 19 | function speedUp( 20 | address fromAsset, 21 | bytes calldata txHash, 22 | uint fee 23 | ) external payable; 24 | 25 | function setFeeCollector(address collector) external; 26 | function setLockProxy(address _lockProxy) external; 27 | function extractFee(address token) external; 28 | function pause() external; 29 | function unpause() external; 30 | 31 | event PolyWrapperLock(address indexed fromAsset, address indexed sender, uint64 toChainId, bytes toAddress, uint net, uint fee, uint id); 32 | event PolyWrapperSpeedUp(address indexed fromAsset, bytes indexed txHash, address indexed sender, uint efee); 33 | } -------------------------------------------------------------------------------- /contracts/libs/GSN/Context.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /* 4 | * @dev Provides information about the current execution context, including the 5 | * sender of the transaction and its data. While these are generally available 6 | * via msg.sender and msg.data, they should not be accessed in such a direct 7 | * manner, since when dealing with GSN meta-transactions the account sending and 8 | * paying for execution may not be the actual sender (as far as an application 9 | * is concerned). 10 | * 11 | * This contract is only required for intermediate, library-like contracts. 12 | * Refer from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/GSN/Context.sol 13 | */ 14 | contract Context { 15 | // Empty internal constructor, to prevent people from mistakenly deploying 16 | // an instance of this contract, which should be used via inheritance. 17 | constructor () internal { } 18 | // solhint-disable-previous-line no-empty-blocks 19 | 20 | function _msgSender() internal view returns (address payable) { 21 | return msg.sender; 22 | } 23 | 24 | function _msgData() internal view returns (bytes memory) { 25 | this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 26 | return msg.data; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /contracts/libs/common/ZeroCopySink.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Wrappers over encoding and serialization operation into bytes from bassic types in Solidity for PolyNetwork cross chain utility. 5 | * 6 | * Encode basic types in Solidity into bytes easily. It's designed to be used 7 | * for PolyNetwork cross chain application, and the encoding rules on Ethereum chain 8 | * and the decoding rules on other chains should be consistent. Here we 9 | * follow the underlying serialization rule with implementation found here: 10 | * https://github.com/polynetwork/poly/blob/master/common/zero_copy_sink.go 11 | * 12 | * Using this library instead of the unchecked serialization method can help reduce 13 | * the risk of serious bugs and handfule, so it's recommended to use it. 14 | * 15 | * Please note that risk can be minimized, yet not eliminated. 16 | */ 17 | library ZeroCopySink { 18 | /* @notice Convert boolean value into bytes 19 | * @param b The boolean value 20 | * @return Converted bytes array 21 | */ 22 | function WriteBool(bool b) internal pure returns (bytes memory) { 23 | bytes memory buff; 24 | assembly{ 25 | buff := mload(0x40) 26 | mstore(buff, 1) 27 | switch iszero(b) 28 | case 1 { 29 | mstore(add(buff, 0x20), shl(248, 0x00)) 30 | // mstore8(add(buff, 0x20), 0x00) 31 | } 32 | default { 33 | mstore(add(buff, 0x20), shl(248, 0x01)) 34 | // mstore8(add(buff, 0x20), 0x01) 35 | } 36 | mstore(0x40, add(buff, 0x21)) 37 | } 38 | return buff; 39 | } 40 | 41 | /* @notice Convert byte value into bytes 42 | * @param b The byte value 43 | * @return Converted bytes array 44 | */ 45 | function WriteByte(byte b) internal pure returns (bytes memory) { 46 | return WriteUint8(uint8(b)); 47 | } 48 | 49 | /* @notice Convert uint8 value into bytes 50 | * @param v The uint8 value 51 | * @return Converted bytes array 52 | */ 53 | function WriteUint8(uint8 v) internal pure returns (bytes memory) { 54 | bytes memory buff; 55 | assembly{ 56 | buff := mload(0x40) 57 | mstore(buff, 1) 58 | mstore(add(buff, 0x20), shl(248, v)) 59 | // mstore(add(buff, 0x20), byte(0x1f, v)) 60 | mstore(0x40, add(buff, 0x21)) 61 | } 62 | return buff; 63 | } 64 | 65 | /* @notice Convert uint16 value into bytes 66 | * @param v The uint16 value 67 | * @return Converted bytes array 68 | */ 69 | function WriteUint16(uint16 v) internal pure returns (bytes memory) { 70 | bytes memory buff; 71 | 72 | assembly{ 73 | buff := mload(0x40) 74 | let byteLen := 0x02 75 | mstore(buff, byteLen) 76 | for { 77 | let mindex := 0x00 78 | let vindex := 0x1f 79 | } lt(mindex, byteLen) { 80 | mindex := add(mindex, 0x01) 81 | vindex := sub(vindex, 0x01) 82 | }{ 83 | mstore8(add(add(buff, 0x20), mindex), byte(vindex, v)) 84 | } 85 | mstore(0x40, add(buff, 0x22)) 86 | } 87 | return buff; 88 | } 89 | 90 | /* @notice Convert uint32 value into bytes 91 | * @param v The uint32 value 92 | * @return Converted bytes array 93 | */ 94 | function WriteUint32(uint32 v) internal pure returns(bytes memory) { 95 | bytes memory buff; 96 | assembly{ 97 | buff := mload(0x40) 98 | let byteLen := 0x04 99 | mstore(buff, byteLen) 100 | for { 101 | let mindex := 0x00 102 | let vindex := 0x1f 103 | } lt(mindex, byteLen) { 104 | mindex := add(mindex, 0x01) 105 | vindex := sub(vindex, 0x01) 106 | }{ 107 | mstore8(add(add(buff, 0x20), mindex), byte(vindex, v)) 108 | } 109 | mstore(0x40, add(buff, 0x24)) 110 | } 111 | return buff; 112 | } 113 | 114 | /* @notice Convert uint64 value into bytes 115 | * @param v The uint64 value 116 | * @return Converted bytes array 117 | */ 118 | function WriteUint64(uint64 v) internal pure returns(bytes memory) { 119 | bytes memory buff; 120 | 121 | assembly{ 122 | buff := mload(0x40) 123 | let byteLen := 0x08 124 | mstore(buff, byteLen) 125 | for { 126 | let mindex := 0x00 127 | let vindex := 0x1f 128 | } lt(mindex, byteLen) { 129 | mindex := add(mindex, 0x01) 130 | vindex := sub(vindex, 0x01) 131 | }{ 132 | mstore8(add(add(buff, 0x20), mindex), byte(vindex, v)) 133 | } 134 | mstore(0x40, add(buff, 0x28)) 135 | } 136 | return buff; 137 | } 138 | 139 | /* @notice Convert limited uint256 value into bytes 140 | * @param v The uint256 value 141 | * @return Converted bytes array 142 | */ 143 | function WriteUint255(uint256 v) internal pure returns (bytes memory) { 144 | require(v <= 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "Value exceeds uint255 range"); 145 | bytes memory buff; 146 | 147 | assembly{ 148 | buff := mload(0x40) 149 | let byteLen := 0x20 150 | mstore(buff, byteLen) 151 | for { 152 | let mindex := 0x00 153 | let vindex := 0x1f 154 | } lt(mindex, byteLen) { 155 | mindex := add(mindex, 0x01) 156 | vindex := sub(vindex, 0x01) 157 | }{ 158 | mstore8(add(add(buff, 0x20), mindex), byte(vindex, v)) 159 | } 160 | mstore(0x40, add(buff, 0x40)) 161 | } 162 | return buff; 163 | } 164 | 165 | /* @notice Encode bytes format data into bytes 166 | * @param data The bytes array data 167 | * @return Encoded bytes array 168 | */ 169 | function WriteVarBytes(bytes memory data) internal pure returns (bytes memory) { 170 | uint64 l = uint64(data.length); 171 | return abi.encodePacked(WriteVarUint(l), data); 172 | } 173 | 174 | function WriteVarUint(uint64 v) internal pure returns (bytes memory) { 175 | if (v < 0xFD){ 176 | return WriteUint8(uint8(v)); 177 | } else if (v <= 0xFFFF) { 178 | return abi.encodePacked(WriteByte(0xFD), WriteUint16(uint16(v))); 179 | } else if (v <= 0xFFFFFFFF) { 180 | return abi.encodePacked(WriteByte(0xFE), WriteUint32(uint32(v))); 181 | } else { 182 | return abi.encodePacked(WriteByte(0xFF), WriteUint64(uint64(v))); 183 | } 184 | } 185 | } -------------------------------------------------------------------------------- /contracts/libs/lifecycle/Pausable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../GSN/Context.sol"; 4 | 5 | /** 6 | * @dev Contract module which allows children to implement an emergency stop 7 | * mechanism that can be triggered by an authorized account. 8 | * 9 | * This module is used through inheritance. It will make available the 10 | * modifiers `whenNotPaused` and `whenPaused`, which can be applied to 11 | * the functions of your contract. Note that they will not be pausable by 12 | * simply including this module, only once the modifiers are put in place. 13 | */ 14 | contract Pausable is Context { 15 | /** 16 | * @dev Emitted when the pause is triggered by a pauser (`account`). 17 | */ 18 | event Paused(address account); 19 | 20 | /** 21 | * @dev Emitted when the pause is lifted by a pauser (`account`). 22 | */ 23 | event Unpaused(address account); 24 | 25 | bool private _paused; 26 | 27 | /** 28 | * @dev Initializes the contract in unpaused state. 29 | */ 30 | constructor () internal { 31 | _paused = false; 32 | } 33 | 34 | /** 35 | * @dev Returns true if the contract is paused, and false otherwise. 36 | */ 37 | function paused() public view returns (bool) { 38 | return _paused; 39 | } 40 | 41 | /** 42 | * @dev Modifier to make a function callable only when the contract is not paused. 43 | */ 44 | modifier whenNotPaused() { 45 | require(!_paused, "Pausable: paused"); 46 | _; 47 | } 48 | 49 | /** 50 | * @dev Modifier to make a function callable only when the contract is paused. 51 | */ 52 | modifier whenPaused() { 53 | require(_paused, "Pausable: not paused"); 54 | _; 55 | } 56 | 57 | /** 58 | * @dev Called to pause, triggers stopped state. 59 | */ 60 | function _pause() internal whenNotPaused { 61 | _paused = true; 62 | emit Paused(_msgSender()); 63 | } 64 | 65 | /** 66 | * @dev Called to unpause, returns to normal state. 67 | */ 68 | function _unpause() internal whenPaused { 69 | _paused = false; 70 | emit Unpaused(_msgSender()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /contracts/libs/math/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 5 | * checks. 6 | * 7 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 8 | * in bugs, because programmers usually assume that an overflow raises an 9 | * error, which is the standard behavior in high level programming languages. 10 | * `SafeMath` restores this intuition by reverting the transaction when an 11 | * operation overflows. 12 | * 13 | * Using this library instead of the unchecked operations eliminates an entire 14 | * class of bugs, so it's recommended to use it always. 15 | */ 16 | library SafeMath { 17 | /** 18 | * @dev Returns the addition of two unsigned integers, reverting on 19 | * overflow. 20 | * 21 | * Counterpart to Solidity's `+` operator. 22 | * 23 | * Requirements: 24 | * - Addition cannot overflow. 25 | */ 26 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 27 | uint256 c = a + b; 28 | require(c >= a, "SafeMath: addition overflow"); 29 | 30 | return c; 31 | } 32 | 33 | /** 34 | * @dev Returns the subtraction of two unsigned integers, reverting on 35 | * overflow (when the result is negative). 36 | * 37 | * Counterpart to Solidity's `-` operator. 38 | * 39 | * Requirements: 40 | * - Subtraction cannot overflow. 41 | */ 42 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 43 | return sub(a, b, "SafeMath: subtraction overflow"); 44 | } 45 | 46 | /** 47 | * @dev Returns the subtraction of two unsigned integers, reverting with custom message on 48 | * overflow (when the result is negative). 49 | * 50 | * Counterpart to Solidity's `-` operator. 51 | * 52 | * Requirements: 53 | * - Subtraction cannot overflow. 54 | * 55 | * _Available since v2.4.0._ 56 | */ 57 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 58 | require(b <= a, errorMessage); 59 | uint256 c = a - b; 60 | 61 | return c; 62 | } 63 | 64 | /** 65 | * @dev Returns the multiplication of two unsigned integers, reverting on 66 | * overflow. 67 | * 68 | * Counterpart to Solidity's `*` operator. 69 | * 70 | * Requirements: 71 | * - Multiplication cannot overflow. 72 | */ 73 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 74 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 75 | // benefit is lost if 'b' is also tested. 76 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 77 | if (a == 0) { 78 | return 0; 79 | } 80 | 81 | uint256 c = a * b; 82 | require(c / a == b, "SafeMath: multiplication overflow"); 83 | 84 | return c; 85 | } 86 | 87 | /** 88 | * @dev Returns the integer division of two unsigned integers. Reverts on 89 | * division by zero. The result is rounded towards zero. 90 | * 91 | * Counterpart to Solidity's `/` operator. Note: this function uses a 92 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 93 | * uses an invalid opcode to revert (consuming all remaining gas). 94 | * 95 | * Requirements: 96 | * - The divisor cannot be zero. 97 | */ 98 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 99 | return div(a, b, "SafeMath: division by zero"); 100 | } 101 | 102 | /** 103 | * @dev Returns the integer division of two unsigned integers. Reverts with custom message on 104 | * division by zero. The result is rounded towards zero. 105 | * 106 | * Counterpart to Solidity's `/` operator. Note: this function uses a 107 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 108 | * uses an invalid opcode to revert (consuming all remaining gas). 109 | * 110 | * Requirements: 111 | * - The divisor cannot be zero. 112 | * 113 | * _Available since v2.4.0._ 114 | */ 115 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 116 | // Solidity only automatically asserts when dividing by 0 117 | require(b != 0, errorMessage); 118 | uint256 c = a / b; 119 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 120 | 121 | return c; 122 | } 123 | 124 | /** 125 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 126 | * Reverts when dividing by zero. 127 | * 128 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 129 | * opcode (which leaves remaining gas untouched) while Solidity uses an 130 | * invalid opcode to revert (consuming all remaining gas). 131 | * 132 | * Requirements: 133 | * - The divisor cannot be zero. 134 | */ 135 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 136 | return mod(a, b, "SafeMath: modulo by zero"); 137 | } 138 | 139 | /** 140 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 141 | * Reverts with custom message when dividing by zero. 142 | * 143 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 144 | * opcode (which leaves remaining gas untouched) while Solidity uses an 145 | * invalid opcode to revert (consuming all remaining gas). 146 | * 147 | * Requirements: 148 | * - The divisor cannot be zero. 149 | * 150 | * _Available since v2.4.0._ 151 | */ 152 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 153 | require(b != 0, errorMessage); 154 | return a % b; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /contracts/libs/ownership/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../GSN/Context.sol"; 4 | /** 5 | * @dev Contract module which provides a basic access control mechanism, where 6 | * there is an account (an owner) that can be granted exclusive access to 7 | * specific functions. 8 | * 9 | * This module is used through inheritance. It will make available the modifier 10 | * `onlyOwner`, which can be applied to your functions to restrict their use to 11 | * the owner. 12 | */ 13 | contract Ownable is Context { 14 | address private _owner; 15 | 16 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 17 | 18 | /** 19 | * @dev Initializes the contract setting the deployer as the initial owner. 20 | */ 21 | constructor () internal { 22 | address msgSender = _msgSender(); 23 | _owner = msgSender; 24 | emit OwnershipTransferred(address(0), msgSender); 25 | } 26 | 27 | /** 28 | * @dev Returns the address of the current owner. 29 | */ 30 | function owner() public view returns (address) { 31 | return _owner; 32 | } 33 | 34 | /** 35 | * @dev Throws if called by any account other than the owner. 36 | */ 37 | modifier onlyOwner() { 38 | require(isOwner(), "Ownable: caller is not the owner"); 39 | _; 40 | } 41 | 42 | /** 43 | * @dev Returns true if the caller is the current owner. 44 | */ 45 | function isOwner() public view returns (bool) { 46 | return _msgSender() == _owner; 47 | } 48 | 49 | /** 50 | * @dev Leaves the contract without owner. It will not be possible to call 51 | * `onlyOwner` functions anymore. Can only be called by the current owner. 52 | * 53 | * NOTE: Renouncing ownership will leave the contract without an owner, 54 | * thereby removing any functionality that is only available to the owner. 55 | */ 56 | function renounceOwnership() public onlyOwner { 57 | emit OwnershipTransferred(_owner, address(0)); 58 | _owner = address(0); 59 | } 60 | 61 | /** 62 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 63 | * Can only be called by the current owner. 64 | */ 65 | function transferOwnership(address newOwner) public onlyOwner { 66 | _transferOwnership(newOwner); 67 | } 68 | 69 | /** 70 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 71 | */ 72 | function _transferOwnership(address newOwner) internal { 73 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 74 | emit OwnershipTransferred(_owner, newOwner); 75 | _owner = newOwner; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/libs/token/ERC20/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../GSN/Context.sol"; 4 | import "./IERC20.sol"; 5 | import "./../../math/SafeMath.sol"; 6 | 7 | /** 8 | * @dev Implementation of the {IERC20} interface. 9 | * 10 | * This implementation is agnostic to the way tokens are created. This means 11 | * that a supply mechanism has to be added in a derived contract using {_mint}. 12 | * For a generic mechanism see {ERC20Mintable}. 13 | * 14 | * TIP: For a detailed writeup see our guide 15 | * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How 16 | * to implement supply mechanisms]. 17 | * 18 | * We have followed general OpenZeppelin guidelines: functions revert instead 19 | * of returning `false` on failure. This behavior is nonetheless conventional 20 | * and does not conflict with the expectations of ERC20 applications. 21 | * 22 | * Additionally, an {Approval} event is emitted on calls to {transferFrom}. 23 | * This allows applications to reconstruct the allowance for all accounts just 24 | * by listening to said events. Other implementations of the EIP may not emit 25 | * these events, as it isn't required by the specification. 26 | * 27 | * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} 28 | * functions have been added to mitigate the well-known issues around setting 29 | * allowances. See {IERC20-approve}. 30 | * Refer from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol 31 | */ 32 | contract ERC20 is Context, IERC20 { 33 | using SafeMath for uint256; 34 | 35 | mapping (address => uint256) private _balances; 36 | 37 | mapping (address => mapping (address => uint256)) private _allowances; 38 | 39 | uint256 private _totalSupply; 40 | 41 | /** 42 | * @dev See {IERC20-totalSupply}. 43 | */ 44 | function totalSupply() public view returns (uint256) { 45 | return _totalSupply; 46 | } 47 | 48 | /** 49 | * @dev See {IERC20-balanceOf}. 50 | */ 51 | function balanceOf(address account) public view returns (uint256) { 52 | return _balances[account]; 53 | } 54 | 55 | /** 56 | * @dev See {IERC20-transfer}. 57 | * 58 | * Requirements: 59 | * 60 | * - `recipient` cannot be the zero address. 61 | * - the caller must have a balance of at least `amount`. 62 | */ 63 | function transfer(address recipient, uint256 amount) public returns (bool) { 64 | _transfer(_msgSender(), recipient, amount); 65 | return true; 66 | } 67 | 68 | /** 69 | * @dev See {IERC20-allowance}. 70 | */ 71 | function allowance(address owner, address spender) public view returns (uint256) { 72 | return _allowances[owner][spender]; 73 | } 74 | 75 | /** 76 | * @dev See {IERC20-approve}. 77 | * 78 | * Requirements: 79 | * 80 | * - `spender` cannot be the zero address. 81 | */ 82 | function approve(address spender, uint256 amount) public returns (bool) { 83 | _approve(_msgSender(), spender, amount); 84 | return true; 85 | } 86 | 87 | /** 88 | * @dev See {IERC20-transferFrom}. 89 | * 90 | * Emits an {Approval} event indicating the updated allowance. This is not 91 | * required by the EIP. See the note at the beginning of {ERC20}; 92 | * 93 | * Requirements: 94 | * - `sender` and `recipient` cannot be the zero address. 95 | * - `sender` must have a balance of at least `amount`. 96 | * - the caller must have allowance for `sender`'s tokens of at least 97 | * `amount`. 98 | */ 99 | function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { 100 | _transfer(sender, recipient, amount); 101 | _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); 102 | return true; 103 | } 104 | 105 | /** 106 | * @dev Atomically increases the allowance granted to `spender` by the caller. 107 | * 108 | * This is an alternative to {approve} that can be used as a mitigation for 109 | * problems described in {IERC20-approve}. 110 | * 111 | * Emits an {Approval} event indicating the updated allowance. 112 | * 113 | * Requirements: 114 | * 115 | * - `spender` cannot be the zero address. 116 | */ 117 | function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 118 | _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); 119 | return true; 120 | } 121 | 122 | /** 123 | * @dev Atomically decreases the allowance granted to `spender` by the caller. 124 | * 125 | * This is an alternative to {approve} that can be used as a mitigation for 126 | * problems described in {IERC20-approve}. 127 | * 128 | * Emits an {Approval} event indicating the updated allowance. 129 | * 130 | * Requirements: 131 | * 132 | * - `spender` cannot be the zero address. 133 | * - `spender` must have allowance for the caller of at least 134 | * `subtractedValue`. 135 | */ 136 | function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 137 | _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); 138 | return true; 139 | } 140 | 141 | /** 142 | * @dev Moves tokens `amount` from `sender` to `recipient`. 143 | * 144 | * This is internal function is equivalent to {transfer}, and can be used to 145 | * e.g. implement automatic token fees, slashing mechanisms, etc. 146 | * 147 | * Emits a {Transfer} event. 148 | * 149 | * Requirements: 150 | * 151 | * - `sender` cannot be the zero address. 152 | * - `recipient` cannot be the zero address. 153 | * - `sender` must have a balance of at least `amount`. 154 | */ 155 | function _transfer(address sender, address recipient, uint256 amount) internal { 156 | require(sender != address(0), "ERC20: transfer from the zero address"); 157 | require(recipient != address(0), "ERC20: transfer to the zero address"); 158 | 159 | _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); 160 | _balances[recipient] = _balances[recipient].add(amount); 161 | emit Transfer(sender, recipient, amount); 162 | } 163 | 164 | /** @dev Creates `amount` tokens and assigns them to `account`, increasing 165 | * the total supply. 166 | * 167 | * Emits a {Transfer} event with `from` set to the zero address. 168 | * 169 | * Requirements 170 | * 171 | * - `to` cannot be the zero address. 172 | */ 173 | function _mint(address account, uint256 amount) internal { 174 | require(account != address(0), "ERC20: mint to the zero address"); 175 | 176 | _totalSupply = _totalSupply.add(amount); 177 | _balances[account] = _balances[account].add(amount); 178 | emit Transfer(address(0), account, amount); 179 | } 180 | 181 | /** 182 | * @dev Destroys `amount` tokens from `account`, reducing the 183 | * total supply. 184 | * 185 | * Emits a {Transfer} event with `to` set to the zero address. 186 | * 187 | * Requirements 188 | * 189 | * - `account` cannot be the zero address. 190 | * - `account` must have at least `amount` tokens. 191 | */ 192 | function _burn(address account, uint256 amount) internal { 193 | require(account != address(0), "ERC20: burn from the zero address"); 194 | 195 | _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); 196 | _totalSupply = _totalSupply.sub(amount); 197 | emit Transfer(account, address(0), amount); 198 | } 199 | 200 | /** 201 | * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. 202 | * 203 | * This is internal function is equivalent to `approve`, and can be used to 204 | * e.g. set automatic allowances for certain subsystems, etc. 205 | * 206 | * Emits an {Approval} event. 207 | * 208 | * Requirements: 209 | * 210 | * - `owner` cannot be the zero address. 211 | * - `spender` cannot be the zero address. 212 | */ 213 | function _approve(address owner, address spender, uint256 amount) internal { 214 | require(owner != address(0), "ERC20: approve from the zero address"); 215 | require(spender != address(0), "ERC20: approve to the zero address"); 216 | 217 | _allowances[owner][spender] = amount; 218 | emit Approval(owner, spender, amount); 219 | } 220 | 221 | /** 222 | * @dev Destroys `amount` tokens from `account`.`amount` is then deducted 223 | * from the caller's allowance. 224 | * 225 | * See {_burn} and {_approve}. 226 | */ 227 | function _burnFrom(address account, uint256 amount) internal { 228 | _burn(account, amount); 229 | _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /contracts/libs/token/ERC20/ERC20Detailed.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IERC20.sol"; 4 | 5 | /** 6 | * @dev Optional functions from the ERC20 standard. 7 | * Refer from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20Detailed.sol 8 | */ 9 | contract ERC20Detailed is IERC20 { 10 | string private _name; 11 | string private _symbol; 12 | uint8 private _decimals; 13 | 14 | /** 15 | * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of 16 | * these values are immutable: they can only be set once during 17 | * construction. 18 | */ 19 | constructor (string memory name, string memory symbol, uint8 decimals) public { 20 | _name = name; 21 | _symbol = symbol; 22 | _decimals = decimals; 23 | } 24 | 25 | /** 26 | * @dev Returns the name of the token. 27 | */ 28 | function name() public view returns (string memory) { 29 | return _name; 30 | } 31 | 32 | /** 33 | * @dev Returns the symbol of the token, usually a shorter version of the 34 | * name. 35 | */ 36 | function symbol() public view returns (string memory) { 37 | return _symbol; 38 | } 39 | 40 | /** 41 | * @dev Returns the number of decimals used to get its user representation. 42 | * For example, if `decimals` equals `2`, a balance of `505` tokens should 43 | * be displayed to a user as `5,05` (`505 / 10 ** 2`). 44 | * 45 | * Tokens usually opt for a value of 18, imitating the relationship between 46 | * Ether and Wei. 47 | * 48 | * NOTE: This information is only used for _display_ purposes: it in 49 | * no way affects any of the arithmetic of the contract, including 50 | * {IERC20-balanceOf} and {IERC20-transfer}. 51 | */ 52 | function decimals() public view returns (uint8) { 53 | return _decimals; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /contracts/libs/token/ERC20/ERC20Extended.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./ERC20Detailed.sol"; 4 | import "./../../GSN/Context.sol"; 5 | import "./ERC20.sol"; 6 | import "./../../../core/cross_chain_manager/interface/IEthCrossChainManagerProxy.sol"; 7 | 8 | contract ERC20Extended is Context, ERC20, ERC20Detailed { 9 | 10 | address public managerProxyContract; // here managerContract should only be set as the ETH cross chain managing contract address 11 | address public operator; // operator should be the address who deploys this contract, and responsible for 'setManager' and 'bindContractAddrWithChainId' 12 | mapping(uint64 => bytes) public bondAssetHashes; 13 | 14 | event BindAssetHash(uint64 chainId, bytes contractAddr); 15 | event SetManagerProxyEvent(address managerContract); 16 | 17 | 18 | modifier onlyManagerContract() { 19 | IEthCrossChainManagerProxy ieccmp = IEthCrossChainManagerProxy(managerProxyContract); 20 | require(_msgSender() == ieccmp.getEthCrossChainManager(), "msgSender is not EthCrossChainManagerContract"); 21 | _; 22 | } 23 | 24 | modifier onlyOperator() { 25 | require(_msgSender() == operator) ; 26 | _; 27 | } 28 | 29 | /* @notice Mint amount of tokens to the account 30 | * @param account The account which will receive the minted tokens 31 | * @param amount The amount of tokens to be minted 32 | */ 33 | function mint(address account, uint256 amount) public onlyManagerContract returns (bool) { 34 | _mint(account, amount); 35 | return true; 36 | } 37 | 38 | /* @notice Burn amount of tokens from the msg.sender's balance 39 | * @param amount The amount of tokens to be burnt 40 | */ 41 | function burn(uint256 amount) public returns (bool) { 42 | _burn(_msgSender(), amount); 43 | return true; 44 | } 45 | 46 | /* @notice Set the ETH cross chain contract as the manager such that the ETH cross chain contract 47 | * will be able to mint tokens to the designated account after a certain amount of tokens 48 | * are locked in the source chain 49 | * @param ethCrossChainContractAddr The ETH cross chain management contract address 50 | */ 51 | function setManagerProxy(address ethCrossChainManagerProxyAddr) onlyOperator public { 52 | managerProxyContract = ethCrossChainManagerProxyAddr; 53 | emit SetManagerProxyEvent(managerProxyContract); 54 | } 55 | 56 | /* @notice Bind the target chain with the target chain id 57 | * @param chainId The target chain id 58 | * @param contractAddr The specific contract address in bytes format in the target chain 59 | */ 60 | function bindAssetHash(uint64 chainId, bytes memory contractAddr) onlyOperator public { 61 | require(chainId != 0, "chainId illegal!"); 62 | bondAssetHashes[chainId] = contractAddr; 63 | emit BindAssetHash(chainId, contractAddr); 64 | } 65 | } -------------------------------------------------------------------------------- /contracts/libs/token/ERC20/IERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Interface of the ERC20 standard as defined in the EIP. Does not include 5 | * the optional functions; to access them see {ERC20Detailed}. 6 | */ 7 | interface IERC20 { 8 | /** 9 | * @dev Returns the amount of tokens in existence. 10 | */ 11 | function totalSupply() external view returns (uint256); 12 | 13 | /** 14 | * @dev Returns the amount of tokens owned by `account`. 15 | */ 16 | function balanceOf(address account) external view returns (uint256); 17 | 18 | /** 19 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 20 | * 21 | * Returns a boolean value indicating whether the operation succeeded. 22 | * 23 | * Emits a {Transfer} event. 24 | */ 25 | function transfer(address recipient, uint256 amount) external returns (bool); 26 | 27 | /** 28 | * @dev Returns the remaining number of tokens that `spender` will be 29 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 30 | * zero by default. 31 | * 32 | * This value changes when {approve} or {transferFrom} are called. 33 | */ 34 | function allowance(address owner, address spender) external view returns (uint256); 35 | 36 | /** 37 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 38 | * 39 | * Returns a boolean value indicating whether the operation succeeded. 40 | * 41 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 42 | * that someone may use both the old and the new allowance by unfortunate 43 | * transaction ordering. One possible solution to mitigate this race 44 | * condition is to first reduce the spender's allowance to 0 and set the 45 | * desired value afterwards: 46 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 47 | * 48 | * Emits an {Approval} event. 49 | */ 50 | function approve(address spender, uint256 amount) external returns (bool); 51 | 52 | /** 53 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 54 | * allowance mechanism. `amount` is then deducted from the caller's 55 | * allowance. 56 | * 57 | * Returns a boolean value indicating whether the operation succeeded. 58 | * 59 | * Emits a {Transfer} event. 60 | */ 61 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 62 | 63 | /** 64 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 65 | * another (`to`). 66 | * 67 | * Note that `value` may be zero. 68 | */ 69 | event Transfer(address indexed from, address indexed to, uint256 value); 70 | 71 | /** 72 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 73 | * a call to {approve}. `value` is the new allowance. 74 | */ 75 | event Approval(address indexed owner, address indexed spender, uint256 value); 76 | } 77 | -------------------------------------------------------------------------------- /contracts/libs/token/ERC20/SafeERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IERC20.sol"; 4 | import "../../math/SafeMath.sol"; 5 | import "../../utils/Utils.sol"; 6 | 7 | /** 8 | * @title SafeERC20 9 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 10 | * contract returns false). Tokens that return no value (and instead revert or 11 | * throw on failure) are also supported, non-reverting calls are assumed to be 12 | * successful. 13 | * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, 14 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 15 | */ 16 | library SafeERC20 { 17 | using SafeMath for uint256; 18 | 19 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 20 | callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 21 | } 22 | 23 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 24 | callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 25 | } 26 | 27 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 28 | // safeApprove should only be called when setting an initial allowance, 29 | // or when resetting it to zero. To increase and decrease it, use 30 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 31 | // solhint-disable-next-line max-line-length 32 | require((value == 0) || (token.allowance(address(this), spender) == 0), 33 | "SafeERC20: approve from non-zero to non-zero allowance" 34 | ); 35 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 36 | } 37 | 38 | function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { 39 | uint256 newAllowance = token.allowance(address(this), spender).add(value); 40 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 41 | } 42 | 43 | function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { 44 | uint256 newAllowance = token.allowance(address(this), spender).sub(value); 45 | callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 46 | } 47 | 48 | /** 49 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 50 | * on the return value: the return value is optional (but if data is returned, it must not be false). 51 | * @param token The token targeted by the call. 52 | * @param data The call data (encoded using abi.encode or one of its variants). 53 | */ 54 | function callOptionalReturn(IERC20 token, bytes memory data) private { 55 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 56 | // we're implementing it ourselves. 57 | 58 | // A Solidity high level call has three parts: 59 | // 1. The target address is checked to verify it contains contract code 60 | // 2. The call itself is made, and success asserted 61 | // 3. The return value is decoded, which in turn checks the size of the returned data. 62 | // solhint-disable-next-line max-line-length 63 | require(Utils.isContract(address(token)), "SafeERC20: call to non-contract"); 64 | 65 | // solhint-disable-next-line avoid-low-level-calls 66 | (bool success, bytes memory returndata) = address(token).call(data); 67 | require(success, "SafeERC20: low-level call failed"); 68 | 69 | if (returndata.length > 0) { // Return data is optional 70 | // solhint-disable-next-line max-line-length 71 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /contracts/libs/utils/Encoder.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | contract AbiEncoder { 5 | function encodeWhiteList(address _contract, bytes[] memory _methods) public pure returns(bytes memory) { 6 | return abi.encode(_contract,_methods); 7 | } 8 | } -------------------------------------------------------------------------------- /contracts/libs/utils/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.5.0; 3 | 4 | /** 5 | * @dev Contract module that helps prevent reentrant calls to a function. 6 | * 7 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 8 | * available, which can be applied to functions to make sure there are no nested 9 | * (reentrant) calls to them. 10 | * 11 | * Note that because there is a single `nonReentrant` guard, functions marked as 12 | * `nonReentrant` may not call one another. This can be worked around by making 13 | * those functions `private`, and then adding `external` `nonReentrant` entry 14 | * points to them. 15 | * 16 | * TIP: If you would like to learn more about reentrancy and alternative ways 17 | * to protect against it, check out our blog post 18 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 19 | * 20 | * _Since v2.5.0:_ this module is now much more gas efficient, given net gas 21 | * metering changes introduced in the Istanbul hardfork. 22 | */ 23 | contract ReentrancyGuard { 24 | bool private _notEntered; 25 | 26 | constructor () internal { 27 | // Storing an initial non-zero value makes deployment a bit more 28 | // expensive, but in exchange the refund on every call to nonReentrant 29 | // will be lower in amount. Since refunds are capped to a percetange of 30 | // the total transaction's gas, it is best to keep them low in cases 31 | // like this one, to increase the likelihood of the full refund coming 32 | // into effect. 33 | _notEntered = true; 34 | } 35 | 36 | /** 37 | * @dev Prevents a contract from calling itself, directly or indirectly. 38 | * Calling a `nonReentrant` function from another `nonReentrant` 39 | * function is not supported. It is possible to prevent this from happening 40 | * by making the `nonReentrant` function external, and make it call a 41 | * `private` function that does the actual work. 42 | */ 43 | modifier nonReentrant() { 44 | // On the first call to nonReentrant, _notEntered will be true 45 | require(_notEntered, "ReentrancyGuard: reentrant call"); 46 | 47 | // Any calls to nonReentrant after this point will fail 48 | _notEntered = false; 49 | 50 | _; 51 | 52 | // By storing the original value once again, a refund is triggered (see 53 | // https://eips.ethereum.org/EIPS/eip-2200) 54 | _notEntered = true; 55 | } 56 | } -------------------------------------------------------------------------------- /contracts/mocks/libs/common/ZeroCopySinkMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../../../../contracts/libs/common/ZeroCopySink.sol"; 4 | 5 | contract ZeroCopySinkMock { 6 | uint N = 10; 7 | function WriteBool(bool _b) public view returns (bytes memory) { 8 | bytes memory executeResult; 9 | for (uint i = 0; i <= N; i++) { 10 | executeResult = ZeroCopySink.WriteBool(_b); 11 | } 12 | return ZeroCopySink.WriteBool(_b); 13 | } 14 | 15 | function WriteByte(byte _b) public view returns (bytes memory) { 16 | bytes memory executeResult; 17 | for (uint i = 0; i <= N; i++) { 18 | executeResult = ZeroCopySink.WriteByte(_b); 19 | } 20 | return ZeroCopySink.WriteByte(_b); 21 | } 22 | 23 | function WriteUint8(uint8 _v) public view returns (bytes memory) { 24 | bytes memory executeResult; 25 | for (uint i = 0; i <= N; i++) { 26 | executeResult = ZeroCopySink.WriteUint8(_v); 27 | } 28 | return ZeroCopySink.WriteUint8(_v); 29 | } 30 | 31 | function WriteUint16(uint16 _v) public view returns (bytes memory) { 32 | bytes memory executeResult; 33 | for (uint i = 0; i <= N; i++) { 34 | executeResult = ZeroCopySink.WriteUint16(_v); 35 | } 36 | return ZeroCopySink.WriteUint16(_v); 37 | } 38 | 39 | function WriteUint32(uint32 _v) public view returns (bytes memory) { 40 | bytes memory executeResult; 41 | for (uint i = 0; i <= N; i++) { 42 | executeResult = ZeroCopySink.WriteUint32(_v); 43 | } 44 | return ZeroCopySink.WriteUint32(_v); 45 | } 46 | 47 | function WriteUint64(uint64 _v) public view returns (bytes memory) { 48 | bytes memory executeResult; 49 | for (uint i = 0; i <= N; i++) { 50 | executeResult = ZeroCopySink.WriteUint64(_v); 51 | } 52 | return ZeroCopySink.WriteUint64(_v); 53 | } 54 | function WriteUint255(uint256 _v) public view returns (bytes memory) { 55 | bytes memory executeResult; 56 | for (uint i = 0; i <= N; i++) { 57 | executeResult = ZeroCopySink.WriteUint255(_v); 58 | } 59 | return ZeroCopySink.WriteUint255(_v); 60 | } 61 | 62 | function WriteVarBytes(bytes memory _b) public view returns (bytes memory) { 63 | bytes memory executeResult; 64 | for (uint i = 0; i <= N; i++) { 65 | executeResult = ZeroCopySink.WriteVarBytes(_b); 66 | } 67 | return ZeroCopySink.WriteVarBytes(_b); 68 | } 69 | 70 | function WriteVarUint(uint64 _v) public view returns (bytes memory) { 71 | bytes memory executeResult; 72 | for (uint i = 0; i <= N; i++) { 73 | executeResult = ZeroCopySink.WriteVarUint(_v); 74 | } 75 | return ZeroCopySink.WriteVarUint(_v); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/mocks/libs/common/ZeroCopySourceMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../../../../contracts/libs/common/ZeroCopySource.sol"; 4 | 5 | contract ZeroCopySourceMock { 6 | uint N = 10; 7 | function NextBool(bytes memory _b, uint256 _off) public view returns (bool, uint256) { 8 | bool res; 9 | uint256 offset = 0; 10 | for (uint i = 0; i <= N; i++) { 11 | (res, offset) = ZeroCopySource.NextBool(_b, _off); 12 | } 13 | return ZeroCopySource.NextBool(_b, _off); 14 | } 15 | 16 | function NextByte(bytes memory _b, uint256 _off) public pure returns (byte, uint256) { 17 | return ZeroCopySource.NextByte(_b, _off); 18 | } 19 | 20 | function NextUint8(bytes memory _b, uint256 _off) public pure returns (uint8, uint256) { 21 | return ZeroCopySource.NextUint8(_b, _off); 22 | } 23 | 24 | function NextUint16(bytes memory _b, uint256 _off) public pure returns (uint16, uint256) { 25 | return ZeroCopySource.NextUint16(_b, _off); 26 | } 27 | 28 | function NextUint32(bytes memory _b, uint256 _off) public pure returns (uint32, uint256) { 29 | return ZeroCopySource.NextUint32(_b, _off); 30 | } 31 | 32 | function NextUint64(bytes memory _b, uint256 _off) public pure returns (uint64, uint256) { 33 | return ZeroCopySource.NextUint64(_b, _off); 34 | } 35 | 36 | function NextVarBytes(bytes memory _b, uint256 _off) public pure returns (bytes memory, uint256) { 37 | return ZeroCopySource.NextVarBytes(_b, _off); 38 | } 39 | 40 | function NextHash(bytes memory _b, uint256 _off) public pure returns (bytes32, uint256) { 41 | return ZeroCopySource.NextHash(_b, _off); 42 | } 43 | 44 | // function NextAddress(bytes _b, uint256 _off) public pure returns (bytes20, uint256) { 45 | // return ZeroCopySource.NextAddress(_b, _off); 46 | // } 47 | 48 | function NextBytes20(bytes memory _b, uint256 _off) public pure returns (bytes20, uint256) { 49 | return ZeroCopySource.NextBytes20(_b, _off); 50 | } 51 | 52 | function NextUint255(bytes memory _b, uint256 _off) public pure returns (uint256, uint256) { 53 | return ZeroCopySource.NextUint255(_b, _off); 54 | } 55 | function NextVarUint(bytes memory _b, uint256 _off) public pure returns (uint, uint256) { 56 | return ZeroCopySource.NextVarUint(_b, _off); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /contracts/mocks/libs/math/SafeMathMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | 4 | import "../../../../contracts/libs/math/SafeMath.sol"; 5 | 6 | 7 | contract SafeMathMock { 8 | function sub(uint256 a, uint256 b) public pure returns (uint256) { 9 | return SafeMath.sub(a, b); 10 | } 11 | 12 | function add(uint256 a, uint256 b) public pure returns (uint256) { 13 | return SafeMath.add(a, b); 14 | } 15 | function mul(uint256 a, uint256 b) public pure returns (uint256) { 16 | return SafeMath.mul(a, b); 17 | } 18 | 19 | function div(uint256 a, uint256 b) public pure returns (uint256) { 20 | return SafeMath.div(a, b); 21 | } 22 | function mod(uint256 a, uint256 b) public pure returns (uint256) { 23 | return SafeMath.mod(a, b); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mocks/libs/utils/UtilsMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./../../../../contracts/libs/utils//Utils.sol"; 4 | 5 | contract UtilsMock { 6 | bytes public storageBytes; 7 | constructor() public { 8 | storageBytes = bytes("I am global in global storage"); 9 | } 10 | function bytesToBytes32(bytes memory _b) public pure returns (bytes32) { 11 | return Utils.bytesToBytes32(_b); 12 | } 13 | 14 | function bytesToUint256(bytes memory _v) public pure returns (uint256) { 15 | return Utils.bytesToUint256(_v); 16 | } 17 | 18 | function uint256ToBytes(uint256 _v) public pure returns (bytes memory) { 19 | return Utils.uint256ToBytes(_v); 20 | } 21 | 22 | function bytesToAddress(bytes memory _v) public pure returns (address) { 23 | return Utils.bytesToAddress(_v); 24 | } 25 | 26 | function addressToBytes(address _v) public pure returns (bytes memory) { 27 | return Utils.addressToBytes(_v); 28 | } 29 | function hashLeaf(bytes memory _data) public pure returns (bytes32) { 30 | return Utils.hashLeaf(_data); 31 | } 32 | function hashChildren(bytes32 left, bytes32 right) public pure returns (bytes32) { 33 | return Utils.hashChildren(left, right); 34 | } 35 | function equalStorage( bytes memory memoryBytes) public view returns (bool) { 36 | return Utils.equalStorage(storageBytes, memoryBytes); 37 | } 38 | function slice(bytes memory _bytes, uint _start, uint _length )public pure returns (bytes memory){ 39 | return Utils.slice(_bytes, _start, _length); 40 | } 41 | 42 | function containMAddresses(address[] memory keepers, address[] memory signers, uint m) public pure returns(bool){ 43 | return Utils.containMAddresses(keepers, signers, m); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /document/images/eccm_design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polynetwork/eth-contracts/097214982454bb2e225c2bfba81d28f4852c2203/document/images/eccm_design.png -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | // require("dotenv").config(); 2 | 3 | require("@nomiclabs/hardhat-etherscan"); 4 | require("@nomiclabs/hardhat-waffle"); 5 | //require("hardhat-gas-reporter"); 6 | //require("solidity-coverage"); 7 | 8 | // This is a sample Hardhat task. To learn how to create your own go to 9 | // https://hardhat.org/guides/create-task.html 10 | task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { 11 | const accounts = await hre.ethers.getSigners(); 12 | 13 | for (const account of accounts) { 14 | console.log(account.address); 15 | } 16 | }); 17 | 18 | let PRIVATE_KEY = ''; 19 | let PRIVATE_KEY_1 = ''; 20 | let ETHERSCAN_API_KEY = ''; 21 | 22 | // You need to export an object to set up your config 23 | // Go to https://hardhat.org/config/ to learn more 24 | 25 | /** 26 | * @type import('hardhat/config').HardhatUserConfig 27 | */ 28 | module.exports = { 29 | solidity: { 30 | version: "0.5.17", 31 | settings: { 32 | optimizer: { 33 | enabled: true, 34 | runs: 200 35 | } 36 | } 37 | }, 38 | networks: { 39 | hardhat: { 40 | initialBaseFeePerGas: 0, // workaround from https://github.com/sc-forks/solidity-coverage/issues/652#issuecomment-896330136 . Remove when that issue is closed. 41 | }, 42 | mainnet: { 43 | url: `https://mainnet.infura.io/v3/f7fd127c230e49b292bafd6c338995ea`, 44 | accounts: [] 45 | }, 46 | arbitrum: { 47 | url: `https://arb1.arbitrum.io/rpc`, 48 | accounts: [] 49 | }, 50 | bsc: { 51 | url: `http://172.168.3.40:8545`, 52 | accounts: [] 53 | }, 54 | heco: { 55 | url: `https://http-mainnet.hecochain.com`, 56 | accounts: [] 57 | }, 58 | ok: { 59 | url: `https://exchainrpc.okex.org/`, 60 | accounts: [] 61 | }, 62 | polygon: { 63 | url: `https://rpc-mainnet.matic.network`, 64 | accounts: [] 65 | }, 66 | 67 | 68 | ropsten: { 69 | url: `https://ropsten.infura.io/v3/9bca539684b6408d9dbcbb179e593eab`, 70 | accounts: [] 71 | }, 72 | arbitrum_testnet: { 73 | url: `https://rinkeby.arbitrum.io/rpc`, 74 | accounts: [] 75 | }, 76 | bsc_testnet: { 77 | url: `https://data-seed-prebsc-1-s1.binance.org:8545`, 78 | accounts: [] 79 | }, 80 | heco_testnet: { 81 | url: `https://http-testnet.hecochain.com`, 82 | accounts: [] 83 | }, 84 | ok_testnet: { 85 | url: `https://exchaintestrpc.okex.org/`, 86 | accounts: [] 87 | }, 88 | polygon_testnet: { 89 | url: `https://rpc-mumbai.maticvigil.com`, 90 | accounts: [] 91 | }, 92 | // ropsten: { 93 | // url: process.env.ROPSTEN_URL || "", 94 | // accounts: 95 | // process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 96 | // }, 97 | }, 98 | gasReporter: { 99 | enabled: process.env.REPORT_GAS !== undefined, 100 | currency: "USD", 101 | }, 102 | etherscan: { 103 | apiKey: ETHERSCAN_API_KEY, 104 | }, 105 | }; -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const hre = require("hardhat"); 3 | const fs = require("fs"); 4 | const Web3 = require("web3"); 5 | const colors = require('colors'); 6 | hre.web3 = new Web3(hre.network.provider); 7 | 8 | async function main() { 9 | 10 | [deployer] = await hre.ethers.getSigners(); 11 | let polyId; 12 | 13 | // check if given networkId is registered 14 | await getPolyChainId().then((_polyId) => { 15 | polyId = _polyId; 16 | console.log("\nDeploy EthCrossChainManager on chain with Poly_Chain_Id:".cyan, _polyId); 17 | }).catch((error) => { 18 | throw error; 19 | });; 20 | 21 | console.log("Start , deployer:".cyan, deployer.address.blue); 22 | 23 | // deploy EthCrossChainData 24 | console.log("\ndeploy EthCrossChainData ......".cyan); 25 | const ECCD = await hre.ethers.getContractFactory("EthCrossChainData"); 26 | const eccd = await ECCD.deploy(); 27 | await eccd.deployed(); 28 | console.log("EthCrossChainData deployed to:".green, eccd.address.blue); 29 | 30 | // deploy EthCrossChainManager 31 | console.log("\ndeploy EthCrossChainManager ......".cyan); 32 | const CCM = await hre.ethers.getContractFactory("EthCrossChainManager"); 33 | const ccm = await CCM.deploy(eccd.address, polyId, [], []); 34 | await ccm.deployed(); 35 | console.log("EthCrossChainManager deployed to:".green, ccm.address.blue); 36 | 37 | // deploy EthCrossChainManagerProxy 38 | console.log("\ndeploy EthCrossChainManagerProxy ......".cyan); 39 | const CCMP = await hre.ethers.getContractFactory("EthCrossChainManagerProxy"); 40 | const ccmp = await CCMP.deploy(ccm.address); 41 | await ccmp.deployed(); 42 | console.log("EthCrossChainManagerProxy deployed to:".green, ccmp.address.blue); 43 | 44 | // transfer ownership 45 | console.log("\ntransfer eccd's ownership to ccm ......".cyan); 46 | await eccd.transferOwnership(ccm.address); 47 | console.log("ownership transferred".green); 48 | 49 | console.log("\ntransfer ccm's ownership to ccmp ......".cyan); 50 | await ccm.transferOwnership(ccmp.address); 51 | console.log("ownership transferred".green); 52 | 53 | console.log("\nDone.\n".magenta); 54 | 55 | } 56 | 57 | async function getPolyChainId() { 58 | const chainId = await hre.web3.eth.getChainId(); 59 | switch (chainId) { 60 | 61 | // mainnet 62 | case 1: // eth-main 63 | return 2; 64 | case 56: // bsc-main 65 | return 6; 66 | case 128: // heco-main 67 | return 7; 68 | case 137: // polygon-main 69 | return 17; 70 | case 66: // ok-main 71 | return 12; 72 | case 1718: // plt-main 73 | return 8; 74 | case 42161: // arbitrum-main 75 | return 19; 76 | 77 | // testnet 78 | case 3: // eth-test 79 | return 2; 80 | case 97: // bsc-test 81 | return 79; 82 | case 256: // heco-test 83 | return 7; 84 | case 80001: // polygon-test 85 | return 202; 86 | case 65: // ok-test 87 | return 200; 88 | case 101: // plt-test 89 | return 107; 90 | case 421611: // arbitrum-test 91 | return 205; 92 | 93 | // hardhat devnet 94 | case 31337: 95 | return 77777; 96 | 97 | // unknown chainid 98 | default: 99 | throw new Error("fail to get Poly_Chain_Id, unknown Network_Id: "+chainId); 100 | } 101 | } 102 | 103 | // We recommend this pattern to be able to use async/await everywhere 104 | // and properly handle errors. 105 | main() 106 | .then(() => process.exit(0)) 107 | .catch((error) => { 108 | console.error(error); 109 | process.exit(1); 110 | }); -------------------------------------------------------------------------------- /scripts/deployBasic.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const Web3 = require("web3"); 3 | const fs = require("fs"); 4 | hre.web3 = new Web3(hre.network.provider); 5 | require("colors"); 6 | 7 | var configPath = './polyConfig.json' 8 | 9 | async function main() { 10 | [deployer] = await hre.ethers.getSigners(); 11 | var config = {} 12 | await readConfig(hre.network.name).then((netConfig) => { 13 | if (netConfig !== undefined) { 14 | config = netConfig 15 | } 16 | }).catch((err) => { 17 | console.error(err); 18 | process.exit(1); 19 | }); 20 | if (config.Name === undefined) { 21 | config.Name = hre.network.name 22 | } 23 | if (config.PolyChainID === undefined) { 24 | if (hre.config.networks[hre.network.name].polyId === undefined) { 25 | console.error("unknown network: invalid PolyChainID".red); 26 | process.exit(1); 27 | } 28 | config.PolyChainID = hre.config.networks[hre.network.name].polyId 29 | } 30 | if (config.Provider === undefined) { 31 | config.Provider = hre.config.networks[hre.network.name].url 32 | writeConfig(config) 33 | } 34 | if (config.Deployer === undefined) { 35 | config.Deployer = deployer.address 36 | } 37 | 38 | const ECCD = await hre.ethers.getContractFactory("EthCrossChainData"); 39 | const CCM = await hre.ethers.getContractFactory("EthCrossChainManager"); 40 | const CCMP = await hre.ethers.getContractFactory("EthCrossChainManagerProxy"); 41 | let polyId = config.PolyChainID 42 | let eccd 43 | let ccm 44 | let ccmp 45 | 46 | console.log("\nDeploy basic contracts on chain with Poly_Chain_Id:".cyan, polyId); 47 | 48 | if (config.EthCrossChainData === undefined) { 49 | // deploy EthCrossChainData 50 | console.log("\ndeploy EthCrossChainData ......".cyan); 51 | eccd = await ECCD.deploy(); 52 | await eccd.deployed(); 53 | console.log("EthCrossChainData deployed to:".green, eccd.address.blue); 54 | config.EthCrossChainData = eccd.address 55 | writeConfig(config) 56 | } else { 57 | console.log("\nEthCrossChainData already deployed at".green, config.EthCrossChainData.blue) 58 | eccd = await ECCD.attach(config.EthCrossChainData) 59 | } 60 | 61 | if (config.EthCrossChainManager === undefined) { 62 | // deploy EthCrossChainManager 63 | console.log("\ndeploy EthCrossChainManager ......".cyan); 64 | ccm = await CCM.deploy(eccd.address, polyId, [], []); 65 | await ccm.deployed(); 66 | console.log("EthCrossChainManager deployed to:".green, ccm.address.blue); 67 | config.EthCrossChainManager = ccm.address 68 | writeConfig(config) 69 | } else { 70 | console.log("\nEthCrossChainManager already deployed at".green, config.EthCrossChainManager.blue) 71 | ccm = await CCM.attach(config.EthCrossChainManager) 72 | } 73 | 74 | if (config.EthCrossChainManagerProxy === undefined) { 75 | // deploy EthCrossChainManagerProxy 76 | console.log("\ndeploy EthCrossChainManagerProxy ......".cyan); 77 | ccmp = await CCMP.deploy(ccm.address); 78 | await ccmp.deployed(); 79 | console.log("EthCrossChainManagerProxy deployed to:".green, ccmp.address.blue); 80 | config.EthCrossChainManagerProxy = ccmp.address 81 | writeConfig(config) 82 | } else { 83 | console.log("\nEthCrossChainManagerProxy already deployed at".green, config.EthCrossChainManagerProxy.blue) 84 | ccmp = await CCMP.attach(config.EthCrossChainManagerProxy) 85 | } 86 | 87 | let eccdOwner = await eccd.owner() 88 | let ccmOwner = await ccm.owner() 89 | // transfer ownership 90 | if (eccdOwner == ccm.address) { 91 | console.log("eccd ownership already transferred".green); 92 | } else { 93 | console.log("\ntransfer eccd's ownership to ccm ......".cyan); 94 | tx = await eccd.transferOwnership(ccm.address); 95 | await tx.wait(); 96 | console.log("ownership transferred".green); 97 | } 98 | if (ccmOwner == ccmp.address) { 99 | console.log("ccm ownership already transferred".green); 100 | } else { 101 | console.log("\ntransfer ccm's ownership to ccmp ......".cyan); 102 | tx = await ccm.transferOwnership(ccmp.address); 103 | await tx.wait(); 104 | console.log("ownership transferred".green); 105 | } 106 | 107 | // config 108 | // config.Name = hre.network.name 109 | // config.PolyChainID = hre.config.networks[config.Name].polyId 110 | // config.Provider = hre.config.networks[config.Name].url 111 | // config.Deployer = deployer.address 112 | // config.EthCrossChainData = eccd.address 113 | // config.EthCrossChainManager = ccm.address 114 | // config.EthCrossChainManagerProxy = ccmp.address 115 | // config.LockProxy = lockProxy.address 116 | // config.LockProxyPip4 = lockProxyPip4.address 117 | // config.Swapper = swapper.address 118 | // config.Wrapper = wrapper2.address 119 | // config.WrapperV1 = wrapper1.address 120 | // config.WrapperV2 = wrapper2.address 121 | // config.WrapperV3 = wrapper3.address 122 | // config.PrivateKeyNo = 1 123 | console.log("constract output:\n".cyan,config); 124 | await writeConfig(config) 125 | console.log("\nwrite config done\n".green); 126 | 127 | console.log("\nDone.\n".magenta); 128 | } 129 | 130 | async function readConfig(networkName) { 131 | let jsonData 132 | try { 133 | jsonData = fs.readFileSync(configPath) 134 | } catch(err) { 135 | if (err.code == 'ENOENT') { 136 | createEmptyConfig() 137 | return 138 | }else{ 139 | console.error(err); 140 | process.exit(1); 141 | } 142 | } 143 | if (jsonData === undefined) { 144 | return 145 | } 146 | var json=JSON.parse(jsonData.toString()) 147 | if (json.Networks === undefined) { 148 | return 149 | } 150 | for (let i=0; i{ 165 | if (err) { 166 | console.error(err); 167 | process.exit(1); 168 | }else{ 169 | previous=data.toString(); 170 | } 171 | }); 172 | var json = JSON.parse(data.toString()) 173 | var writeIndex = json.Networks.length 174 | for (let i=0; i process.exit(0)) 203 | .catch((err) => { 204 | console.error(err) 205 | process.exit(1) 206 | }); -------------------------------------------------------------------------------- /scripts/deployBasicTestnet.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const Web3 = require("web3"); 3 | const fs = require("fs"); 4 | hre.web3 = new Web3(hre.network.provider); 5 | require("colors"); 6 | 7 | var configPath = './polyTestnetConfig.json' 8 | 9 | async function main() { 10 | [deployer] = await hre.ethers.getSigners(); 11 | var config = {} 12 | await readConfig(hre.network.name).then((netConfig) => { 13 | if (netConfig !== undefined) { 14 | config = netConfig 15 | } 16 | }).catch((err) => { 17 | console.error(err); 18 | process.exit(1); 19 | }); 20 | if (config.Name === undefined) { 21 | config.Name = hre.network.name 22 | } 23 | if (config.PolyChainID === undefined) { 24 | if (hre.config.networks[hre.network.name].polyId === undefined) { 25 | console.error("unknown network: invalid PolyChainID".red); 26 | process.exit(1); 27 | } 28 | config.PolyChainID = hre.config.networks[hre.network.name].polyId 29 | } 30 | if (config.Provider === undefined) { 31 | config.Provider = hre.config.networks[hre.network.name].url 32 | writeConfig(config) 33 | } 34 | if (config.Deployer === undefined) { 35 | config.Deployer = deployer.address 36 | } 37 | 38 | const ECCD = await hre.ethers.getContractFactory("EthCrossChainData"); 39 | const CCM = await hre.ethers.getContractFactory("EthCrossChainManagerNoWhiteList"); 40 | const CCMP = await hre.ethers.getContractFactory("EthCrossChainManagerProxy"); 41 | let polyId = config.PolyChainID 42 | let eccd 43 | let ccm 44 | let ccmp 45 | 46 | console.log("\nDeploy basic contracts on chain with Poly_Chain_Id:".cyan, polyId); 47 | 48 | if (config.EthCrossChainData === undefined) { 49 | // deploy EthCrossChainData 50 | console.log("\ndeploy EthCrossChainData ......".cyan); 51 | eccd = await ECCD.deploy(); 52 | await eccd.deployed(); 53 | console.log("EthCrossChainData deployed to:".green, eccd.address.blue); 54 | config.EthCrossChainData = eccd.address 55 | writeConfig(config) 56 | } else { 57 | console.log("\nEthCrossChainData already deployed at".green, config.EthCrossChainData.blue) 58 | eccd = await ECCD.attach(config.EthCrossChainData) 59 | } 60 | 61 | if (config.EthCrossChainManager === undefined) { 62 | // deploy EthCrossChainManager 63 | console.log("\ndeploy EthCrossChainManager ......".cyan); 64 | ccm = await CCM.deploy(eccd.address, polyId); 65 | await ccm.deployed(); 66 | console.log("EthCrossChainManager deployed to:".green, ccm.address.blue); 67 | config.EthCrossChainManager = ccm.address 68 | writeConfig(config) 69 | } else { 70 | console.log("\nEthCrossChainManager already deployed at".green, config.EthCrossChainManager.blue) 71 | ccm = await CCM.attach(config.EthCrossChainManager) 72 | } 73 | 74 | if (config.EthCrossChainManagerProxy === undefined) { 75 | // deploy EthCrossChainManagerProxy 76 | console.log("\ndeploy EthCrossChainManagerProxy ......".cyan); 77 | ccmp = await CCMP.deploy(ccm.address); 78 | await ccmp.deployed(); 79 | console.log("EthCrossChainManagerProxy deployed to:".green, ccmp.address.blue); 80 | config.EthCrossChainManagerProxy = ccmp.address 81 | writeConfig(config) 82 | } else { 83 | console.log("\nEthCrossChainManagerProxy already deployed at".green, config.EthCrossChainManagerProxy.blue) 84 | ccmp = await CCMP.attach(config.EthCrossChainManagerProxy) 85 | } 86 | 87 | let eccdOwner = await eccd.owner() 88 | let ccmOwner = await ccm.owner() 89 | // transfer ownership 90 | if (eccdOwner == ccm.address) { 91 | console.log("eccd ownership already transferred".green); 92 | } else { 93 | console.log("\ntransfer eccd's ownership to ccm ......".cyan); 94 | tx = await eccd.transferOwnership(ccm.address); 95 | await tx.wait(); 96 | console.log("ownership transferred".green); 97 | } 98 | if (ccmOwner == ccmp.address) { 99 | console.log("ccm ownership already transferred".green); 100 | } else { 101 | console.log("\ntransfer ccm's ownership to ccmp ......".cyan); 102 | tx = await ccm.transferOwnership(ccmp.address); 103 | await tx.wait(); 104 | console.log("ownership transferred".green); 105 | } 106 | 107 | // config 108 | // config.Name = hre.network.name 109 | // config.PolyChainID = hre.config.networks[config.Name].polyId 110 | // config.Provider = hre.config.networks[config.Name].url 111 | // config.Deployer = deployer.address 112 | // config.EthCrossChainData = eccd.address 113 | // config.EthCrossChainManager = ccm.address 114 | // config.EthCrossChainManagerProxy = ccmp.address 115 | // config.LockProxy = lockProxy.address 116 | // config.LockProxyPip4 = lockProxyPip4.address 117 | // config.Swapper = swapper.address 118 | // config.Wrapper = wrapper2.address 119 | // config.WrapperV1 = wrapper1.address 120 | // config.WrapperV2 = wrapper2.address 121 | // config.WrapperV3 = wrapper3.address 122 | // config.PrivateKeyNo = 1 123 | console.log("constract output:\n".cyan,config); 124 | await writeConfig(config) 125 | console.log("\nwrite config done\n".green); 126 | 127 | console.log("\nDone.\n".magenta); 128 | } 129 | 130 | async function readConfig(networkName) { 131 | let jsonData 132 | try { 133 | jsonData = fs.readFileSync(configPath) 134 | } catch(err) { 135 | if (err.code == 'ENOENT') { 136 | createEmptyConfig() 137 | return 138 | }else{ 139 | console.error(err); 140 | process.exit(1); 141 | } 142 | } 143 | if (jsonData === undefined) { 144 | return 145 | } 146 | var json=JSON.parse(jsonData.toString()) 147 | if (json.Networks === undefined) { 148 | return 149 | } 150 | for (let i=0; i{ 165 | if (err) { 166 | console.error(err); 167 | process.exit(1); 168 | }else{ 169 | previous=data.toString(); 170 | } 171 | }); 172 | var json = JSON.parse(data.toString()) 173 | var writeIndex = json.Networks.length 174 | for (let i=0; i process.exit(0)) 203 | .catch((err) => { 204 | console.error(err) 205 | process.exit(1) 206 | }); -------------------------------------------------------------------------------- /scripts/deployLockProxy.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const Web3 = require("web3"); 3 | const fs = require("fs"); 4 | hre.web3 = new Web3(hre.network.provider); 5 | require("colors"); 6 | 7 | var configPath = './polyConfig.json' 8 | 9 | async function main() { 10 | [admin] = await hre.ethers.getSigners(); 11 | var config = {} 12 | await readConfig(hre.network.name).then((netConfig) => { 13 | if (netConfig === undefined) { 14 | console.error("unknown network: network config does not exisit".red); 15 | process.exit(1) 16 | } 17 | config = netConfig 18 | }).catch((err) => { 19 | console.error(err); 20 | process.exit(1); 21 | }); 22 | if (config.EthCrossChainManagerProxy === undefined) { 23 | console.error("invalid network config: EthCrossChainManagerProxy does not exisit".red); 24 | process.exit(1) 25 | } 26 | 27 | const LockProxy = await hre.ethers.getContractFactory("LockProxy"); 28 | let polyId = config.PolyChainID 29 | let lockproxy 30 | let ccmp = config.EthCrossChainManagerProxy 31 | 32 | console.log("\nDeploy LockProxy on chain with Poly_Chain_Id:".cyan, polyId); 33 | 34 | if (config.LockProxy === undefined) { 35 | // deploy LockProxy 36 | console.log("\ndeploy LockProxy ......".cyan); 37 | lockproxy = await LockProxy.deploy(); 38 | await lockproxy.deployed(); 39 | console.log("LockProxy deployed to:".green, lockproxy.address.blue); 40 | config.LockProxy = lockproxy.address 41 | writeConfig(config) 42 | } else { 43 | console.log("\nLockProxy already deployed at".green, config.LockProxy.blue) 44 | lockproxy = await LockProxy.attach(config.LockProxy) 45 | } 46 | 47 | let alreadySetCCMP = await lockproxy.managerProxyContract(); 48 | if (alreadySetCCMP == ccmp) { 49 | console.log("managerProxyContract already set".green); 50 | } else { 51 | // setup LockProxy 52 | console.log("\nsetup LockProxy ......".cyan); 53 | tx = await lockproxy.setManagerProxy(ccmp); 54 | await tx.wait(); 55 | console.log("setManagerProxy Done".green); 56 | } 57 | 58 | console.log("\nDone.\n".magenta); 59 | 60 | // config 61 | // config.Name = hre.network.name 62 | // config.PolyChainID = hre.config.networks[config.Name].polyId 63 | // config.Provider = hre.config.networks[config.Name].url 64 | // config.Deployer = deployer.address 65 | // config.EthCrossChainData = eccd.address 66 | // config.EthCrossChainManager = ccm.address 67 | // config.EthCrossChainManagerProxy = ccmp.address 68 | // config.LockProxy = lockProxy.address 69 | // config.LockProxyPip4 = lockProxyPip4.address 70 | // config.Swapper = swapper.address 71 | // config.Wrapper = wrapper2.address 72 | // config.WrapperV1 = wrapper1.address 73 | // config.WrapperV2 = wrapper2.address 74 | // config.WrapperV3 = wrapper3.address 75 | // config.PrivateKeyNo = 1 76 | console.log("constract output:\n".cyan,config); 77 | await writeConfig(config) 78 | console.log("\nwrite config done\n".green); 79 | 80 | console.log("\nDone.\n".magenta); 81 | } 82 | 83 | async function readConfig(networkName) { 84 | let jsonData 85 | try { 86 | jsonData = fs.readFileSync(configPath) 87 | } catch(err) { 88 | if (err.code == 'ENOENT') { 89 | createEmptyConfig() 90 | return 91 | }else{ 92 | console.error(err); 93 | process.exit(1); 94 | } 95 | } 96 | if (jsonData === undefined) { 97 | return 98 | } 99 | var json=JSON.parse(jsonData.toString()) 100 | if (json.Networks === undefined) { 101 | return 102 | } 103 | for (let i=0; i{ 118 | if (err) { 119 | console.error(err); 120 | process.exit(1); 121 | }else{ 122 | previous=data.toString(); 123 | } 124 | }); 125 | var json = JSON.parse(data.toString()) 126 | var writeIndex = json.Networks.length 127 | for (let i=0; i process.exit(0)) 156 | .catch((err) => { 157 | console.error(err) 158 | process.exit(1) 159 | }); -------------------------------------------------------------------------------- /scripts/deployLockProxyTestnet.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const Web3 = require("web3"); 3 | const fs = require("fs"); 4 | hre.web3 = new Web3(hre.network.provider); 5 | require("colors"); 6 | 7 | var configPath = './polyTestnetConfig.json' 8 | 9 | async function main() { 10 | [admin] = await hre.ethers.getSigners(); 11 | var config = {} 12 | await readConfig(hre.network.name).then((netConfig) => { 13 | if (netConfig === undefined) { 14 | console.error("unknown network: network config does not exisit".red); 15 | process.exit(1) 16 | } 17 | config = netConfig 18 | }).catch((err) => { 19 | console.error(err); 20 | process.exit(1); 21 | }); 22 | if (config.EthCrossChainManagerProxy === undefined) { 23 | console.error("invalid network config: EthCrossChainManagerProxy does not exisit".red); 24 | process.exit(1) 25 | } 26 | 27 | const LockProxy = await hre.ethers.getContractFactory("LockProxy"); 28 | let polyId = config.PolyChainID 29 | let lockproxy 30 | let ccmp = config.EthCrossChainManagerProxy 31 | 32 | console.log("\nDeploy LockProxy on chain with Poly_Chain_Id:".cyan, polyId); 33 | 34 | if (config.LockProxy === undefined) { 35 | // deploy LockProxy 36 | console.log("\ndeploy LockProxy ......".cyan); 37 | lockproxy = await LockProxy.deploy(); 38 | await lockproxy.deployed(); 39 | console.log("LockProxy deployed to:".green, lockproxy.address.blue); 40 | config.LockProxy = lockproxy.address 41 | writeConfig(config) 42 | } else { 43 | console.log("\nLockProxy already deployed at".green, config.LockProxy.blue) 44 | lockproxy = await LockProxy.attach(config.LockProxy) 45 | } 46 | 47 | let alreadySetCCMP = await lockproxy.managerProxyContract(); 48 | if (alreadySetCCMP == ccmp) { 49 | console.log("managerProxyContract already set".green); 50 | } else { 51 | // setup LockProxy 52 | console.log("\nsetup LockProxy ......".cyan); 53 | tx = await lockproxy.setManagerProxy(ccmp); 54 | await tx.wait(); 55 | console.log("setManagerProxy Done".green); 56 | } 57 | 58 | console.log("\nDone.\n".magenta); 59 | 60 | // config 61 | // config.Name = hre.network.name 62 | // config.PolyChainID = hre.config.networks[config.Name].polyId 63 | // config.Provider = hre.config.networks[config.Name].url 64 | // config.Deployer = deployer.address 65 | // config.EthCrossChainData = eccd.address 66 | // config.EthCrossChainManager = ccm.address 67 | // config.EthCrossChainManagerProxy = ccmp.address 68 | // config.LockProxy = lockProxy.address 69 | // config.LockProxyPip4 = lockProxyPip4.address 70 | // config.Swapper = swapper.address 71 | // config.Wrapper = wrapper2.address 72 | // config.WrapperV1 = wrapper1.address 73 | // config.WrapperV2 = wrapper2.address 74 | // config.WrapperV3 = wrapper3.address 75 | // config.PrivateKeyNo = 1 76 | console.log("constract output:\n".cyan,config); 77 | await writeConfig(config) 78 | console.log("\nwrite config done\n".green); 79 | 80 | console.log("\nDone.\n".magenta); 81 | } 82 | 83 | async function readConfig(networkName) { 84 | let jsonData 85 | try { 86 | jsonData = fs.readFileSync(configPath) 87 | } catch(err) { 88 | if (err.code == 'ENOENT') { 89 | createEmptyConfig() 90 | return 91 | }else{ 92 | console.error(err); 93 | process.exit(1); 94 | } 95 | } 96 | if (jsonData === undefined) { 97 | return 98 | } 99 | var json=JSON.parse(jsonData.toString()) 100 | if (json.Networks === undefined) { 101 | return 102 | } 103 | for (let i=0; i{ 118 | if (err) { 119 | console.error(err); 120 | process.exit(1); 121 | }else{ 122 | previous=data.toString(); 123 | } 124 | }); 125 | var json = JSON.parse(data.toString()) 126 | var writeIndex = json.Networks.length 127 | for (let i=0; i process.exit(0)) 156 | .catch((err) => { 157 | console.error(err) 158 | process.exit(1) 159 | }); -------------------------------------------------------------------------------- /scripts/deployPIP4.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const Web3 = require("web3"); 3 | const fs = require("fs"); 4 | hre.web3 = new Web3(hre.network.provider); 5 | require("colors"); 6 | 7 | var configPath = './polyConfig.json' 8 | 9 | async function main() { 10 | [admin] = await hre.ethers.getSigners(); 11 | var config = {} 12 | await readConfig(hre.network.name).then((netConfig) => { 13 | if (netConfig === undefined) { 14 | console.error("unknown network: network config does not exisit".red); 15 | process.exit(1) 16 | } 17 | config = netConfig 18 | }).catch((err) => { 19 | console.error(err); 20 | process.exit(1); 21 | }); 22 | if (config.EthCrossChainManagerProxy === undefined) { 23 | console.error("invalid network config: EthCrossChainManagerProxy does not exisit".red); 24 | process.exit(1) 25 | } 26 | 27 | const LockProxyWithLP = await hre.ethers.getContractFactory("LockProxyWithLP"); 28 | let polyId = config.PolyChainID 29 | let lockproxy 30 | let ccmp = config.EthCrossChainManagerProxy 31 | 32 | console.log("\nDeploy LockProxyPIP4 on chain with Poly_Chain_Id:".cyan, polyId); 33 | 34 | if (config.LockProxyPip4 === undefined) { 35 | // deploy LockProxyPIP4 36 | console.log("\ndeploy LockProxyWithLP ......".cyan); 37 | lockproxy = await LockProxyWithLP.deploy(); 38 | await lockproxy.deployed(); 39 | console.log("LockProxyWithLP deployed to:".green, lockproxy.address.blue); 40 | config.LockProxyPip4 = lockproxy.address 41 | writeConfig(config) 42 | } else { 43 | console.log("\nLockProxyPIP4 already deployed at".green, config.LockProxyPip4.blue) 44 | lockproxy = await LockProxyWithLP.attach(config.LockProxyPip4) 45 | } 46 | 47 | let alreadySetCCMP = await lockproxy.managerProxyContract(); 48 | if (alreadySetCCMP == ccmp) { 49 | console.log("managerProxyContract already set".green); 50 | } else { 51 | // setup LockProxy 52 | console.log("\nsetup LockProxyWithLP ......".cyan); 53 | tx = await lockproxy.setManagerProxy(ccmp); 54 | await tx.wait(); 55 | console.log("setManagerProxy Done".green); 56 | } 57 | 58 | console.log("\nDone.\n".magenta); 59 | 60 | // config 61 | // config.Name = hre.network.name 62 | // config.PolyChainID = hre.config.networks[config.Name].polyId 63 | // config.Provider = hre.config.networks[config.Name].url 64 | // config.Deployer = deployer.address 65 | // config.EthCrossChainData = eccd.address 66 | // config.EthCrossChainManager = ccm.address 67 | // config.EthCrossChainManagerProxy = ccmp.address 68 | // config.LockProxy = lockProxy.address 69 | // config.LockProxyPip4 = lockProxyPip4.address 70 | // config.Swapper = swapper.address 71 | // config.Wrapper = wrapper2.address 72 | // config.WrapperV1 = wrapper1.address 73 | // config.WrapperV2 = wrapper2.address 74 | // config.WrapperV3 = wrapper3.address 75 | // config.PrivateKeyNo = 1 76 | console.log("constract output:\n".cyan,config); 77 | await writeConfig(config) 78 | console.log("\nwrite config done\n".green); 79 | 80 | console.log("\nDone.\n".magenta); 81 | } 82 | 83 | async function readConfig(networkName) { 84 | let jsonData 85 | try { 86 | jsonData = fs.readFileSync(configPath) 87 | } catch(err) { 88 | if (err.code == 'ENOENT') { 89 | createEmptyConfig() 90 | return 91 | }else{ 92 | console.error(err); 93 | process.exit(1); 94 | } 95 | } 96 | if (jsonData === undefined) { 97 | return 98 | } 99 | var json=JSON.parse(jsonData.toString()) 100 | if (json.Networks === undefined) { 101 | return 102 | } 103 | for (let i=0; i{ 118 | if (err) { 119 | console.error(err); 120 | process.exit(1); 121 | }else{ 122 | previous=data.toString(); 123 | } 124 | }); 125 | var json = JSON.parse(data.toString()) 126 | var writeIndex = json.Networks.length 127 | for (let i=0; i process.exit(0)) 156 | .catch((err) => { 157 | console.error(err) 158 | process.exit(1) 159 | }); -------------------------------------------------------------------------------- /scripts/deployPIP4Testnet.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const Web3 = require("web3"); 3 | const fs = require("fs"); 4 | hre.web3 = new Web3(hre.network.provider); 5 | require("colors"); 6 | 7 | var configPath = './polyTestnetConfig.json' 8 | 9 | async function main() { 10 | [admin] = await hre.ethers.getSigners(); 11 | var config = {} 12 | await readConfig(hre.network.name).then((netConfig) => { 13 | if (netConfig === undefined) { 14 | console.error("unknown network: network config does not exisit".red); 15 | process.exit(1) 16 | } 17 | config = netConfig 18 | }).catch((err) => { 19 | console.error(err); 20 | process.exit(1); 21 | }); 22 | if (config.EthCrossChainManagerProxy === undefined) { 23 | console.error("invalid network config: EthCrossChainManagerProxy does not exisit".red); 24 | process.exit(1) 25 | } 26 | 27 | const LockProxyWithLP = await hre.ethers.getContractFactory("LockProxyWithLP"); 28 | let polyId = config.PolyChainID 29 | let lockproxy 30 | let ccmp = config.EthCrossChainManagerProxy 31 | 32 | console.log("\nDeploy LockProxyPIP4 on chain with Poly_Chain_Id:".cyan, polyId); 33 | 34 | if (config.LockProxyPip4 === undefined) { 35 | // deploy LockProxyPIP4 36 | console.log("\ndeploy LockProxyWithLP ......".cyan); 37 | lockproxy = await LockProxyWithLP.deploy(); 38 | await lockproxy.deployed(); 39 | console.log("LockProxyWithLP deployed to:".green, lockproxy.address.blue); 40 | config.LockProxyPip4 = lockproxy.address 41 | writeConfig(config) 42 | } else { 43 | console.log("\nLockProxyPIP4 already deployed at".green, config.LockProxyPip4.blue) 44 | lockproxy = await LockProxyWithLP.attach(config.LockProxyPip4) 45 | } 46 | 47 | let alreadySetCCMP = await lockproxy.managerProxyContract(); 48 | if (alreadySetCCMP == ccmp) { 49 | console.log("managerProxyContract already set".green); 50 | } else { 51 | // setup LockProxy 52 | console.log("\nsetup LockProxyWithLP ......".cyan); 53 | tx = await lockproxy.setManagerProxy(ccmp); 54 | await tx.wait(); 55 | console.log("setManagerProxy Done".green); 56 | } 57 | 58 | console.log("\nDone.\n".magenta); 59 | 60 | // config 61 | // config.Name = hre.network.name 62 | // config.PolyChainID = hre.config.networks[config.Name].polyId 63 | // config.Provider = hre.config.networks[config.Name].url 64 | // config.Deployer = deployer.address 65 | // config.EthCrossChainData = eccd.address 66 | // config.EthCrossChainManager = ccm.address 67 | // config.EthCrossChainManagerProxy = ccmp.address 68 | // config.LockProxy = lockProxy.address 69 | // config.LockProxyPip4 = lockProxyPip4.address 70 | // config.Swapper = swapper.address 71 | // config.Wrapper = wrapper2.address 72 | // config.WrapperV1 = wrapper1.address 73 | // config.WrapperV2 = wrapper2.address 74 | // config.WrapperV3 = wrapper3.address 75 | // config.PrivateKeyNo = 1 76 | console.log("constract output:\n".cyan,config); 77 | await writeConfig(config) 78 | console.log("\nwrite config done\n".green); 79 | 80 | console.log("\nDone.\n".magenta); 81 | } 82 | 83 | async function readConfig(networkName) { 84 | let jsonData 85 | try { 86 | jsonData = fs.readFileSync(configPath) 87 | } catch(err) { 88 | if (err.code == 'ENOENT') { 89 | createEmptyConfig() 90 | return 91 | }else{ 92 | console.error(err); 93 | process.exit(1); 94 | } 95 | } 96 | if (jsonData === undefined) { 97 | return 98 | } 99 | var json=JSON.parse(jsonData.toString()) 100 | if (json.Networks === undefined) { 101 | return 102 | } 103 | for (let i=0; i{ 118 | if (err) { 119 | console.error(err); 120 | process.exit(1); 121 | }else{ 122 | previous=data.toString(); 123 | } 124 | }); 125 | var json = JSON.parse(data.toString()) 126 | var writeIndex = json.Networks.length 127 | for (let i=0; i process.exit(0)) 156 | .catch((err) => { 157 | console.error(err) 158 | process.exit(1) 159 | }); -------------------------------------------------------------------------------- /scripts/deploy_testnet.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const fs = require("fs"); 3 | const Web3 = require("web3"); 4 | const colors = require('colors'); 5 | const { deployContract } = require("ethereum-waffle"); 6 | hre.web3 = new Web3(hre.network.provider); 7 | 8 | async function main() { 9 | 10 | [deployer] = await hre.ethers.getSigners(); 11 | let polyId; 12 | 13 | // check if given networkId is registered 14 | await getPolyChainId().then((_polyId) => { 15 | polyId = _polyId; 16 | console.log("\nDeploy EthCrossChainManager on chain with Poly_Chain_Id:".cyan, _polyId); 17 | }).catch((error) => { 18 | throw error; 19 | });; 20 | 21 | console.log("Start , deployer:".cyan, deployer.address.blue); 22 | 23 | const ECCD = await hre.ethers.getContractFactory("EthCrossChainData"); 24 | const CCM = await hre.ethers.getContractFactory("EthCrossChainManagerNoWhiteList"); 25 | const CCMP = await hre.ethers.getContractFactory("EthCrossChainManagerProxy"); 26 | const LockProxy = await hre.ethers.getContractFactory("LockProxy"); 27 | const WrapperV2 = await hre.ethers.getContractFactory("PolyWrapper"); 28 | 29 | // deploy EthCrossChainData 30 | console.log("\ndeploy EthCrossChainData ......".cyan); 31 | const eccd = await ECCD.deploy(); 32 | await eccd.deployed(); 33 | console.log("EthCrossChainData deployed to:".green, eccd.address.blue); 34 | 35 | // deploy EthCrossChainManager 36 | console.log("\ndeploy EthCrossChainManager ......".cyan); 37 | const ccm = await CCM.deploy(eccd.address, polyId); 38 | await ccm.deployed(); 39 | console.log("EthCrossChainManager deployed to:".green, ccm.address.blue); 40 | 41 | // deploy EthCrossChainManagerProxy 42 | console.log("\ndeploy EthCrossChainManagerProxy ......".cyan); 43 | const ccmp = await CCMP.deploy(ccm.address); 44 | await ccmp.deployed(); 45 | console.log("EthCrossChainManagerProxy deployed to:".green, ccmp.address.blue); 46 | 47 | // transfer ownership 48 | console.log("\ntransfer eccd's ownership to ccm ......".cyan); 49 | tx = await eccd.transferOwnership(ccm.address); 50 | await tx.wait(); 51 | console.log("ownership transferred".green); 52 | 53 | console.log("\ntransfer ccm's ownership to ccmp ......".cyan); 54 | tx = await ccm.transferOwnership(ccmp.address); 55 | await tx.wait(); 56 | console.log("ownership transferred".green); 57 | 58 | // deploy LockProxy 59 | console.log("\ndeploy LockProxy ......".cyan); 60 | const lockproxy = await LockProxy.deploy(); 61 | await lockproxy.deployed(); 62 | console.log("LockProxy deployed to:".green, lockproxy.address.blue); 63 | 64 | // setup LockProxy 65 | console.log("\nsetup LockProxy ......".cyan); 66 | tx = await lockproxy.setManagerProxy(ccmp.address); 67 | await tx.wait(); 68 | console.log("setManagerProxy Done".green); 69 | 70 | // deploy wrapper 71 | console.log("\ndeploy PolyWrapperV2 ......".cyan); 72 | const wrapper = await WrapperV2.deploy(deployer.address, polyId); 73 | await wrapper.deployed(); 74 | console.log("PolyWrapperV2 deployed to:".green, wrapper.address.blue); 75 | 76 | // setup wrapper 77 | console.log("\nsetup WrapperV2 ......".cyan); 78 | tx = await wrapper.setFeeCollector(deployer.address); 79 | await tx.wait(); 80 | console.log("setFeeCollector Done".green); 81 | tx = await wrapper.setLockProxy(lockproxy.address); 82 | await tx.wait(); 83 | console.log("setLockProxy Done".green); 84 | 85 | 86 | console.log("\nDone.\n".magenta); 87 | 88 | } 89 | 90 | async function getPolyChainId() { 91 | const chainId = await hre.web3.eth.getChainId(); 92 | switch (chainId) { 93 | 94 | // mainnet 95 | case 1: // eth-main 96 | return 2; 97 | case 56: // bsc-main 98 | return 6; 99 | case 128: // heco-main 100 | return 7; 101 | case 137: // polygon-main 102 | return 17; 103 | case 66: // ok-main 104 | return 12; 105 | case 1718: // plt-main 106 | return 8; 107 | case 42161: // arbitrum-main 108 | return 19; 109 | // case 10: // optimistic-main 110 | // return ; 111 | 112 | // testnet 113 | case 3: // ropsten-test 114 | return 2; 115 | case 4: // rinkeby 116 | return 402; 117 | case 5: // goerli 118 | return 502; 119 | case 42: // kovan 120 | return 302; 121 | case 97: // bsc-test 122 | return 79; 123 | case 256: // heco-test 124 | return 7; 125 | case 80001: // polygon-test 126 | return 202; 127 | case 65: // ok-test 128 | return 200; 129 | case 101: // plt-test 130 | return 107; 131 | case 421611: // arbitrum-test 132 | return 205; 133 | case 69: // optimistic-test 134 | return 210; 135 | case 4002: // ftm-test 136 | return 208; 137 | case 43113: // avax-test 138 | return 209; 139 | case 666: // pixie-test 140 | return 320; 141 | 142 | // hardhat devnet 143 | case 31337: 144 | return 77777; 145 | 146 | // unknown chainid 147 | default: 148 | throw new Error("fail to get Poly_Chain_Id, unknown Network_Id: "+chainId); 149 | } 150 | } 151 | 152 | // We recommend this pattern to be able to use async/await everywhere 153 | // and properly handle errors. 154 | main() 155 | .then(() => process.exit(0)) 156 | .catch((error) => { 157 | console.error(error); 158 | process.exit(1); 159 | }); -------------------------------------------------------------------------------- /scripts/setDefaultWhiteList.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const Web3 = require("web3"); 3 | const fs = require("fs"); 4 | hre.web3 = new Web3(hre.network.provider); 5 | require("colors"); 6 | 7 | var configPath = './polyConfig.json' 8 | 9 | async function main() { 10 | [admin] = await hre.ethers.getSigners(); 11 | var config = {} 12 | await readConfig(hre.network.name).then((netConfig) => { 13 | if (netConfig !== undefined) { 14 | config = netConfig 15 | } else { 16 | console.error("unknown network: network config does not exisit".red); 17 | process.exit(1) 18 | } 19 | }).catch((err) => { 20 | console.error(err); 21 | process.exit(1); 22 | }); 23 | if (config.EthCrossChainManager === undefined) { 24 | console.error("invalid network config: EthCrossChainManager does not exisit".red); 25 | } 26 | 27 | const CCM = await hre.ethers.getContractFactory("EthCrossChainManager"); 28 | let ccm = await CCM.attach(config.EthCrossChainManager) 29 | 30 | console.log("\nset white list on chain with Poly_Chain_Id:".cyan, config.PolyChainID); 31 | 32 | let fromContractWls = [] 33 | let contractMethodWls = [] 34 | 35 | if (config.LockProxy !== undefined) { 36 | let name = "LockProxy" 37 | let contract = config.LockProxy 38 | let method = ["0x756e6c6f636b"] // unlock 39 | 40 | console.log("\ncheck ".cyan+name.cyan+" WhiteList ......".cyan); 41 | let flag1 = await ccm.whiteListFromContract(contract) 42 | let flag2 = await ccm.whiteListContractMethodMap(contract, method[0]) 43 | if (flag1 == true) { 44 | console.log(name.green + " already in fromContractWhiteList".green); 45 | } else { 46 | console.log(name.blue + " will be add to fromContractWhiteList".blue); 47 | fromContractWls.push(contract) 48 | } 49 | if (flag2 == true) { 50 | console.log(name.green + " already in contractMethodWhiteList".green); 51 | } else { 52 | console.log(name.blue + " will be add to contractMethodWhiteList".blue); 53 | abiData = hre.web3.eth.abi.encodeParameters(['address','bytes[]'], [contract, method]) 54 | contractMethodWls.push(abiData) 55 | } 56 | } 57 | 58 | if (config.LockProxyPip4 !== undefined) { 59 | let name = "LockProxyPip4" 60 | let contract = config.LockProxyPip4 61 | let method = ["0x756e6c6f636b"] // unlock 62 | 63 | console.log("\ncheck ".cyan+name.cyan+" WhiteList ......".cyan); 64 | let flag1 = await ccm.whiteListFromContract(contract) 65 | let flag2 = await ccm.whiteListContractMethodMap(contract, method[0]) 66 | if (flag1 == true) { 67 | console.log(name.green + " already in fromContractWhiteList".green); 68 | } else { 69 | console.log(name.blue + " will be add to fromContractWhiteList".blue); 70 | fromContractWls.push(contract) 71 | } 72 | if (flag2 == true) { 73 | console.log(name.green + " already in contractMethodWhiteList".green); 74 | } else { 75 | console.log(name.blue + " will be add to contractMethodWhiteList".blue); 76 | abiData = hre.web3.eth.abi.encodeParameters(['address','bytes[]'], [contract, method]) 77 | contractMethodWls.push(abiData) 78 | } 79 | } 80 | 81 | if (config.NftProxy !== undefined) { 82 | let name = "NftProxy" 83 | let contract = config.NftProxy 84 | let method = ["0x756e6c6f636b"] // unlock 85 | 86 | console.log("\ncheck ".cyan+name.cyan+" WhiteList ......".cyan); 87 | let flag1 = await ccm.whiteListFromContract(contract) 88 | let flag2 = await ccm.whiteListContractMethodMap(contract, method[0]) 89 | if (flag1 == true) { 90 | console.log(name.green + " already in fromContractWhiteList".green); 91 | } else { 92 | console.log(name.blue + " will be add to fromContractWhiteList".blue); 93 | fromContractWls.push(contract) 94 | } 95 | if (flag2 == true) { 96 | console.log(name.green + " already in contractMethodWhiteList".green); 97 | } else { 98 | console.log(name.blue + " will be add to contractMethodWhiteList".blue); 99 | abiData = hre.web3.eth.abi.encodeParameters(['address','bytes[]'], [contract, method]) 100 | contractMethodWls.push(abiData) 101 | } 102 | } 103 | 104 | if (config.Swapper !== undefined) { 105 | let name = "Swapper" 106 | let contract = config.Swapper 107 | let method = ["0x6164645f6c6971756964697479", "0x72656d6f76655f6c6971756964697479", "0x73776170"] 108 | // ["add_liquidity", "remove_liquidity", "swap"] 109 | 110 | console.log("\ncheck ".cyan+name.cyan+" WhiteList ......".cyan); 111 | let flag1 = await ccm.whiteListFromContract(contract) 112 | let flag2 = await ccm.whiteListContractMethodMap(contract, method[0]) 113 | if (flag1 == true) { 114 | console.log(name.green + " already in fromContractWhiteList".green); 115 | } else { 116 | console.log(name.blue + " will be add to fromContractWhiteList".blue); 117 | fromContractWls.push(contract) 118 | } 119 | if (flag2 == true) { 120 | console.log(name.green + " already in contractMethodWhiteList".green); 121 | } else { 122 | console.log(name.blue + " will be add to contractMethodWhiteList".blue); 123 | abiData = hre.web3.eth.abi.encodeParameters(['address','bytes[]'], [contract, method]) 124 | contractMethodWls.push(abiData) 125 | } 126 | } 127 | 128 | if (fromContractWls.length != 0) { 129 | console.log("\nsetFromContractWhiteList ......".cyan); 130 | tx = await ccm.setFromContractWhiteList(fromContractWls); 131 | await tx.wait(); 132 | console.log("setFromContractWhiteList done".green); 133 | } 134 | 135 | if (contractMethodWls.length != 0) { 136 | console.log("\nsetContractMethodWhiteList ......".cyan); 137 | tx = await ccm.setContractMethodWhiteList(contractMethodWls); 138 | await tx.wait(); 139 | console.log("setContractMethodWhiteList done".green); 140 | } 141 | 142 | console.log("\nDone.\n".magenta); 143 | } 144 | 145 | async function readConfig(networkName) { 146 | let jsonData 147 | try { 148 | jsonData = fs.readFileSync(configPath) 149 | } catch(err) { 150 | if (err.code == 'ENOENT') { 151 | createEmptyConfig() 152 | return 153 | }else{ 154 | console.error(err); 155 | process.exit(1); 156 | } 157 | } 158 | if (jsonData === undefined) { 159 | return 160 | } 161 | var json=JSON.parse(jsonData.toString()) 162 | if (json.Networks === undefined) { 163 | return 164 | } 165 | for (let i=0; i process.exit(0)) 176 | .catch((err) => { 177 | console.error(err) 178 | process.exit(1) 179 | }); -------------------------------------------------------------------------------- /scripts/setSpecifiedWhiteList.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const Web3 = require("web3"); 3 | const fs = require("fs"); 4 | hre.web3 = new Web3(hre.network.provider); 5 | require("colors"); 6 | 7 | var configPath = './polyConfig.json' 8 | 9 | async function main() { 10 | [admin] = await hre.ethers.getSigners(); 11 | var config = {} 12 | await readConfig(hre.network.name).then((netConfig) => { 13 | if (netConfig !== undefined) { 14 | config = netConfig 15 | } else { 16 | console.error("unknown network: network config does not exisit".red); 17 | process.exit(1) 18 | } 19 | }).catch((err) => { 20 | console.error(err); 21 | process.exit(1); 22 | }); 23 | if (config.EthCrossChainManager === undefined) { 24 | console.error("invalid network config: EthCrossChainManager does not exisit".red); 25 | } 26 | 27 | const CCM = await hre.ethers.getContractFactory("EthCrossChainManager"); 28 | let ccm = await CCM.attach(config.EthCrossChainManager) 29 | 30 | console.log("\nset white list on chain with Poly_Chain_Id:".cyan, config.PolyChainID); 31 | 32 | [fromContractWls, contractMethodWls] = getWL() 33 | 34 | if (fromContractWls.length != 0) { 35 | console.log("\nsetFromContractWhiteList ......".cyan); 36 | tx = await ccm.setFromContractWhiteList(fromContractWls); 37 | await tx.wait(); 38 | console.log("setFromContractWhiteList done".green); 39 | } 40 | 41 | if (contractMethodWls.length != 0) { 42 | console.log("\nsetContractMethodWhiteList ......".cyan); 43 | tx = await ccm.setContractMethodWhiteList(contractMethodWls); 44 | await tx.wait(); 45 | console.log("setContractMethodWhiteList done".green); 46 | } 47 | 48 | console.log("\nDone.\n".magenta); 49 | } 50 | 51 | function getWL() { 52 | let fromContractWLs = ["0x2b07784826146A1Fd2e86D3f4697000B6b97a153","0xcdd05Ebaa1FA06a5cE9eB67663aE9Ec78B37bd5B"] 53 | // something like [address, address, ...] 54 | // e.g. ["0x2b07784826146A1Fd2e86D3f4697000B6b97a153","0xcdd05Ebaa1FA06a5cE9eB67663aE9Ec78B37bd5B"] 55 | 56 | let contractMethodWLs = [["0x2b07784826146A1Fd2e86D3f4697000B6b97a153",["0x756e6c6f636b"]], ["0xcdd05Ebaa1FA06a5cE9eB67663aE9Ec78B37bd5B",["0x6164645f6c6971756964697479", "0x72656d6f76655f6c6971756964697479", "0x73776170"]]] 57 | // something like [[address,[bytes]], [[address,[bytes], ...] 58 | // e.g. [["0x2b07784826146A1Fd2e86D3f4697000B6b97a153",["0x756e6c6f636b"]], ["0xcdd05Ebaa1FA06a5cE9eB67663aE9Ec78B37bd5B",["0x6164645f6c6971756964697479", "0x72656d6f76655f6c6971756964697479", "0x73776170"]]] 59 | 60 | let contractMethodWLData = [] 61 | for (let i=0;i process.exit(0)) 98 | .catch((err) => { 99 | console.error(err) 100 | process.exit(1) 101 | }); -------------------------------------------------------------------------------- /scripts/suspendV1.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("hardhat"); 2 | const hre = require("hardhat"); 3 | const fs = require("fs"); 4 | const Web3 = require("web3"); 5 | const colors = require('colors'); 6 | const { expect } = require("chai"); 7 | hre.web3 = new Web3(hre.network.provider); 8 | 9 | async function main() { 10 | 11 | [deployer] = await hre.ethers.getSigners(); 12 | 13 | let ccmp_addr; 14 | let old_ccm_addr; 15 | let ccd_addr; 16 | let poly_id 17 | 18 | try { 19 | ccmp_addr = getCCMP(); 20 | } catch(error) { 21 | throw error; 22 | } 23 | 24 | const ECCD = await hre.ethers.getContractFactory("EthCrossChainData"); 25 | const CCM = await hre.ethers.getContractFactory("EthCrossChainManager"); 26 | const SUSPEND_CCM = await hre.ethers.getContractFactory("EthCrossChainManagerForUpgrade"); 27 | const CCMP = await hre.ethers.getContractFactory("EthCrossChainManagerProxy"); 28 | 29 | let ccmp = await CCMP.attach(ccmp_addr); 30 | 31 | old_ccm_addr = await ccmp.getEthCrossChainManager(); 32 | let old_ccm = await CCM.attach(old_ccm_addr); 33 | 34 | poly_id = await old_ccm.chainId(); 35 | ccd_addr = await old_ccm.EthCrossChainDataAddress(); 36 | let eccd = await ECCD.attach(ccd_addr); 37 | 38 | console.log("Upgrade ".cyan, hre.network.name.blue); 39 | 40 | // deploy EthCrossChainManager 41 | console.log("\ndeploy new EthCrossChainManager ......".cyan); 42 | let ccm = await SUSPEND_CCM.deploy(eccd.address, poly_id); 43 | await ccm.deployed(); 44 | console.log("New EthCrossChainManager deployed to:".green, ccm.address.blue); 45 | 46 | // transfer ownership 47 | console.log("\ntransfer new ccm's ownership to ccmp ......".cyan); 48 | tx = await ccm.transferOwnership(ccmp.address); 49 | await tx.wait(); 50 | console.log("ownership transferred".green); 51 | 52 | // paused 53 | console.log("\nCheck if paused and pause if not".cyan); 54 | let paused_1 = await ccmp.paused(); 55 | let paused_2 = await old_ccm.paused(); 56 | if (!paused_1 && paused_2) { 57 | tx = await ccmp.pause(); 58 | await tx.wait(); 59 | } else if (!paused_1 && !paused_2) { 60 | tx = await ccmp.pauseEthCrossChainManager(); 61 | await tx.wait(); 62 | } else if (paused_1 && !paused_2) { 63 | tx = await ccmp.unpause(); 64 | await tx.wait(); 65 | tx = await ccmp.pauseEthCrossChainManager(); 66 | await tx.wait(); 67 | } 68 | expect(await ccmp.paused()).to.equal(true); 69 | expect(await old_ccm.paused()).to.equal(true); 70 | console.log("all paused".green); 71 | 72 | // update to new 73 | console.log("\nUpdate to new ccm".cyan); 74 | tx = await ccmp.upgradeEthCrossChainManager(ccm.address); 75 | await tx.wait(); 76 | console.log("updated".green); 77 | 78 | // unpaused 79 | console.log("\nUnpaused all".cyan); 80 | tx = await ccmp.unpauseEthCrossChainManager(); 81 | await tx.wait(); 82 | expect(await ccmp.paused()).to.equal(false); 83 | expect(await ccm.paused()).to.equal(false); 84 | console.log("unpaused".green); 85 | 86 | console.log("\nDone.\n".magenta); 87 | 88 | } 89 | 90 | async function getCCMP() { 91 | const chainId = await hre.web3.eth.getChainId(); 92 | switch (chainId) { 93 | // testnet 94 | case 97: // bsc-test 95 | return "0x7d93fb660776751702d049aDB93968e309315C51"; 96 | // case 256: // heco-test 97 | // case 80001: // polygon-test 98 | 99 | // unknown chainid 100 | default: 101 | throw new Error("fail to get Poly_Chain_Id, unknown Network_Id: "+chainId); 102 | } 103 | } 104 | 105 | // We recommend this pattern to be able to use async/await everywhere 106 | // and properly handle errors. 107 | main() 108 | .then(() => process.exit(0)) 109 | .catch((error) => { 110 | console.error(error); 111 | process.exit(1); 112 | }); -------------------------------------------------------------------------------- /test/ECCUtilsMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../contracts/core/cross_chain_manager/libs/EthCrossChainUtils.sol"; 4 | 5 | contract ECCUtilsMock{ 6 | 7 | // mainnet _keepers pk : 8 | // 0 : 0x3dFcCB7b8A6972CDE3B695d3C0c032514B0f3825 9 | // 1 : 0x4c46e1f946362547546677Bfa719598385ce56f2 10 | // 2 : 0xF81F676832F6dFEC4A5d0671BD27156425fCEF98 11 | // 3 : 0x51b7529137D34002c4ebd81A2244F0ee7e95B2C0 12 | 13 | // header sig : 14 | // 0 : cc6098757cfccb7fc7b83722172d210b19fb587633129925a2c3d9504064e28542ab16cfb09ab5a175a07c91a9018c09534012f41e031d915b54af84f3b2f69200 15 | // 1 : 2b967f19dfb352eb9cccc03c16100dab18749d598c9268c8855f9c4dca604cc37bfd36873dc6c6e1dbaaa6c27cd7d0e0b5183a50dbd4dfbb2d260177fd8ca35f00 16 | // 2 : 0e5314df9e2ccfe835e4238303a036623bc32b41585846d656e287ecde9b488c4a848b8837d908f777b14acbd3b7f058c5489af2ad950ab53bbe5638c445c91e01 17 | // 3 : 00873da4218abdb57b536e6bd2df2d46808d45c8c115d3ea371ec356e1035dd226be50dccca1d8416cda9df04168731b645978f14c66f8e673996973214e66a501 18 | // fake : 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 19 | 20 | // valid sig : 0xcc6098757cfccb7fc7b83722172d210b19fb587633129925a2c3d9504064e28542ab16cfb09ab5a175a07c91a9018c09534012f41e031d915b54af84f3b2f692002b967f19dfb352eb9cccc03c16100dab18749d598c9268c8855f9c4dca604cc37bfd36873dc6c6e1dbaaa6c27cd7d0e0b5183a50dbd4dfbb2d260177fd8ca35f000e5314df9e2ccfe835e4238303a036623bc32b41585846d656e287ecde9b488c4a848b8837d908f777b14acbd3b7f058c5489af2ad950ab53bbe5638c445c91e0100873da4218abdb57b536e6bd2df2d46808d45c8c115d3ea371ec356e1035dd226be50dccca1d8416cda9df04168731b645978f14c66f8e673996973214e66a501 21 | // invalid (passed) : 0xcc6098757cfccb7fc7b83722172d210b19fb587633129925a2c3d9504064e28542ab16cfb09ab5a175a07c91a9018c09534012f41e031d915b54af84f3b2f69200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 22 | // invalid (not passed) : 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 23 | 24 | // header : 0x000000000000000000000000857b5643d8b5b8cb665c005316104f94f09daca4a7cec4639940b7ec385207ab5a6a7a4b763545081d4c64a43388775a8288c423fc2650161c2b15e46fe350e3bd91d18e5507567eaafb21844ca393806a9540c387b85bece9313dc7593c4d5b95453c1a9df3866af54cbe39f77184d6186b2dbc40a0c8fa60695d6acd0eccaecb3740616cf9b9005373fecf4f6cd4fcfd13017b226c6561646572223a322c227672665f76616c7565223a22425055764c5058587230766a347450414c4b506d6a457349456f4b4f684c2b30392f413376426f4e515453426954613148484674785734464f4951784b53585a7a506e4a66504f346c67796d446a5a44313374567335383d222c227672665f70726f6f66223a22357030355468576577487458334a78766e31356e72664339476e566432546451306573487839436d59434c615637395a69785a67644b4872683465474c7a4e55446c4b54637376536d4356724b544b564a55775a42513d3d222c226c6173745f636f6e6669675f626c6f636b5f6e756d223a31323138303030302c226e65775f636861696e5f636f6e666967223a6e756c6c7d0000000000000000000000000000000000000000 25 | function verifySig(bytes memory _rawHeader, bytes memory _sigList) public pure returns(bool) { 26 | address[] memory _keepers = new address[](4); 27 | uint _m = 3; 28 | _keepers[0] = 0x3dFcCB7b8A6972CDE3B695d3C0c032514B0f3825; 29 | _keepers[1] = 0x4c46e1f946362547546677Bfa719598385ce56f2; 30 | _keepers[2] = 0xF81F676832F6dFEC4A5d0671BD27156425fCEF98; 31 | _keepers[3] = 0x51b7529137D34002c4ebd81A2244F0ee7e95B2C0; 32 | 33 | return ECCUtils.verifySig(_rawHeader, _sigList, _keepers, _m); 34 | } 35 | } -------------------------------------------------------------------------------- /test/SafeMathTest.js: -------------------------------------------------------------------------------- 1 | const { expectRevert, expectEvent, constants, BN} = require('@openzeppelin/test-helpers'); 2 | const SafeMathMock = artifacts.require('SafeMathMock'); 3 | const { MAX_UINT256 } = constants; 4 | const { expect } = require('chai'); 5 | const BigNumber = web3.utils.BN; 6 | 7 | contract('SafeMath', () => { 8 | 9 | before(async function () { 10 | this.safeMath = await SafeMathMock.new(); 11 | }); 12 | 13 | describe('add', function () { 14 | it('adds correctly', async function () { 15 | const a = new BigNumber(5678); 16 | const b = new BigNumber(1234); 17 | const c = a.add(b); 18 | 19 | const result = await this.safeMath.add(a, b); 20 | assert(result.eq(a.add(b))); 21 | }); 22 | 23 | it('reverts on addition overflow', async function () { 24 | const a = MAX_UINT256; 25 | const b = new BigNumber(1); 26 | await expectRevert(this.safeMath.add.call(a, b), "SafeMath: addition overflow"); 27 | }); 28 | }); 29 | 30 | describe('sub', function () { 31 | it('subtracts correctly', async function () { 32 | const a = new BigNumber(5678); 33 | const b = new BigNumber(1234); 34 | const result = await this.safeMath.sub(a, b); 35 | 36 | assert(result.eq(a.sub(b))); 37 | }); 38 | 39 | it('throws an error if subtraction result would be negative', async function () { 40 | const a = new BigNumber(1234); 41 | const b = new BigNumber(5678); 42 | await expectRevert(this.safeMath.sub.call(a, b), "SafeMath: subtraction overflow"); 43 | }); 44 | }); 45 | 46 | describe('mul', function () { 47 | it('multiplies correctly', async function () { 48 | const a = new BN('1234'); 49 | const b = new BN('5678'); 50 | let result = await this.safeMath.mul.call(a, b); 51 | let expected = a.mul(b); 52 | // assert.equal(result.toString(), expected.toString()); 53 | expect(result).to.be.bignumber.equal(expected); 54 | }); 55 | 56 | it('multiplies by zero correctly', async function () { 57 | const a = new BN('0'); 58 | const b = new BN('5678'); 59 | let result = await this.safeMath.mul.call(a, b); 60 | let expected = a.mul(b); 61 | expect(result).to.be.bignumber.equal(expected); 62 | }); 63 | 64 | it('reverts on multiplication overflow', async function () { 65 | const a = MAX_UINT256; 66 | const b = new BN('2'); 67 | await expectRevert(this.safeMath.mul.call(a, b), "SafeMath: multiplication overflow"); 68 | }); 69 | }); 70 | 71 | describe('div', function () { 72 | it('divides correctly', async function () { 73 | const a = new BN('5678'); 74 | const b = new BN('5678'); 75 | 76 | expect(await this.safeMath.div(a, b)).to.be.bignumber.equal(a.div(b)); 77 | }); 78 | 79 | it('divides zero correctly', async function () { 80 | const a = new BN('0'); 81 | const b = new BN('5678'); 82 | 83 | expect(await this.safeMath.div(a, b)).to.be.bignumber.equal('0'); 84 | }); 85 | 86 | it('returns complete number result on non-even division', async function () { 87 | const a = new BN('7000'); 88 | const b = new BN('5678'); 89 | 90 | expect(await this.safeMath.div(a, b)).to.be.bignumber.equal('1'); 91 | }); 92 | 93 | it('reverts on division by zero', async function () { 94 | const a = new BN('5678'); 95 | const b = new BN('0'); 96 | 97 | await expectRevert(this.safeMath.div(a, b), 'SafeMath: division by zero'); 98 | }); 99 | }); 100 | 101 | describe('mod', function () { 102 | describe('modulos correctly', async function () { 103 | it('when the dividend is smaller than the divisor', async function () { 104 | const a = new BN('284'); 105 | const b = new BN('5678'); 106 | 107 | expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b)); 108 | }); 109 | 110 | it('when the dividend is equal to the divisor', async function () { 111 | const a = new BN('5678'); 112 | const b = new BN('5678'); 113 | 114 | expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b)); 115 | }); 116 | 117 | it('when the dividend is larger than the divisor', async function () { 118 | const a = new BN('7000'); 119 | const b = new BN('5678'); 120 | 121 | expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b)); 122 | }); 123 | 124 | it('when the dividend is a multiple of the divisor', async function () { 125 | const a = new BN('17034'); // 17034 == 5678 * 3 126 | const b = new BN('5678'); 127 | 128 | expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b)); 129 | }); 130 | }); 131 | 132 | it('reverts with a 0 divisor', async function () { 133 | const a = new BN('5678'); 134 | const b = new BN('0'); 135 | 136 | await expectRevert(this.safeMath.mod(a, b), 'SafeMath: modulo by zero'); 137 | }); 138 | }); 139 | 140 | }); 141 | -------------------------------------------------------------------------------- /test/UtilsTest.js: -------------------------------------------------------------------------------- 1 | const UtilsMock = artifacts.require('./contractmocks/libs/utils/UtilsMock.sol'); 2 | const { expectRevert, expectEvent, constants, BN } = require('@openzeppelin/test-helpers'); 3 | const { expect } = require('chai'); 4 | const { SHA256, SHA3} = require('crypto-js') 5 | contract('Utils', () => { 6 | 7 | before(async function () { 8 | this.utils = await UtilsMock.new(); 9 | }); 10 | 11 | describe('bytesToBytes32', function () { 12 | it('bytesToBytes32 correctly', async function () { 13 | const expected = web3.utils.randomHex(32); 14 | const result = await this.utils.bytesToBytes32(expected); 15 | assert.equal(result, expected); 16 | }); 17 | it('throws an error on bytes length == 31 < 32', async function () { 18 | const expected = web3.utils.randomHex(31); 19 | await expectRevert(this.utils.bytesToBytes32.call(expected), "bytes length is not 32."); 20 | }); 21 | it('throws an error on bytes length == 33 > 32', async function () { 22 | const expected = web3.utils.randomHex(33); 23 | await expectRevert(this.utils.bytesToBytes32.call(expected), "bytes length is not 32."); 24 | }); 25 | }); 26 | describe('bytesToUint256', function () { 27 | it('bytesToUint256 correctly', async function () { 28 | const randomHex32 = web3.utils.randomHex(32).slice(2); 29 | const expectedHex = '0x' + (randomHex32.charAt(0) & 7) + randomHex32.slice(1); 30 | const expected = web3.utils.toBN(expectedHex); 31 | const result = await this.utils.bytesToUint256(expectedHex); 32 | expect(result).to.be.bignumber.equal(expected); 33 | }); 34 | it('throws an error on bytes length == 31 < 32', async function () { 35 | const randomHex32 = web3.utils.randomHex(31).slice(2); 36 | const expectedHex = '0x' + (randomHex32.charAt(0) & 7) + randomHex32.slice(1); 37 | await expectRevert(this.utils.bytesToUint256.call(expectedHex), "bytes length is not 32."); 38 | }); 39 | it('throws an error on bytes length == 33 > 32', async function () { 40 | const randomHex32 = web3.utils.randomHex(33).slice(2); 41 | const expectedHex = '0x' + (randomHex32.charAt(0) & 7) + randomHex32.slice(1); 42 | await expectRevert(this.utils.bytesToUint256.call(expectedHex), "bytes length is not 32."); 43 | }); 44 | }); 45 | describe('uint256ToBytes', function () { 46 | it('uint256ToBytes correctly', async function () { 47 | const randomHex32 = web3.utils.randomHex(32).slice(2); 48 | const expected = '0x' + (randomHex32.charAt(0) & 7) + randomHex32.slice(1); 49 | const expectedNum = web3.utils.toBN(expected); 50 | const result = await this.utils.uint256ToBytes.call(expectedNum); 51 | expect(result).to.be.equal(expected); 52 | }); 53 | it('throws an error on value exceeds the range', async function () { 54 | const randomHex32 = web3.utils.randomHex(32).slice(2); 55 | const expected = '0x' + '80' + randomHex32.slice(2); 56 | const expectedNum = web3.utils.toBN(expected); 57 | await expectRevert(this.utils.uint256ToBytes.call(expectedNum), "Value exceeds the range"); 58 | }); 59 | }); 60 | describe('hashLeaf', function () { 61 | // TODO: check 62 | it('hashLeaf correctly', async function () { 63 | const leafData =web3.utils.randomHex(100); 64 | const expected = web3.utils.soliditySha3('0x00'+leafData.slice(2)); 65 | const expected1 = web3.utils.sha3('0x00'+leafData.slice(2)); 66 | const expected2 = SHA256('0x00'+leafData.slice(2)).toString(); 67 | const expected3 = SHA3('0x00'+leafData.slice(2)).toString(); 68 | const result = await this.utils.hashLeaf.call(leafData); 69 | console.log('expected = ', expected); 70 | console.log('expected1 = ', expected1); 71 | console.log('expected2 = ', expected2); 72 | console.log('expected3 = ', expected3); 73 | console.log('result = ', result); 74 | // expect(result).to.be.equal(expected); 75 | }); 76 | 77 | }); 78 | describe('slice', function () { 79 | bs = '0xab036729af8b8f9b610af4e11b14fa30c348f40c2c230cce92ef6ef37726fee7'; 80 | bs2 = '0xab036729af'; 81 | 82 | it('slice correctly', async function () { 83 | 84 | const result = await this.utils.slice(bs, 0, 5); 85 | assert.equal(result, bs2); 86 | }); 87 | 88 | // it('throws an error on slice length greater than bytes length', async function () { 89 | 90 | // await assertRevert(this.utils.slice(bs, 0, 100)); 91 | // }); 92 | 93 | }); 94 | 95 | describe('addressToBytes and bytesToAddress correctly', function () { 96 | addr = web3.utils.randomHex(20); 97 | 98 | it('addressToBytes correctly', async function () { 99 | const b = await this.utils.addressToBytes(addr); 100 | assert.equal(b, addr); 101 | }); 102 | 103 | it('bytesToAddress correctly', async function () { 104 | const b = await this.utils.addressToBytes(addr); 105 | const a = await this.utils.bytesToAddress(b); 106 | assert.equal(a.toLowerCase(), addr); 107 | }); 108 | 109 | }); 110 | }); -------------------------------------------------------------------------------- /test/helpers/assertRevert.js: -------------------------------------------------------------------------------- 1 | module.exports = async promise => { 2 | try { 3 | await promise; 4 | assert.fail('Expected revert not received'); 5 | } catch (error) { 6 | const revertFound = error.message.search('revert') >= 0; 7 | assert(revertFound, `Expected "revert", got ${error} instead`); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | // const HDWalletProvider = require('truffle-hdwallet-provider'); 2 | // const infuraKey = "fj4jll3k....."; 3 | // 4 | // const fs = require('fs'); 5 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 6 | 7 | module.exports = { 8 | networks: { 9 | development: { 10 | host: "127.0.0.1", // Localhost (default: none) 11 | // host:"172.168.3.77", 12 | port: 8545, // Standard Ethereum port (default: none),// ganache-cli 13 | network_id: "*", // Any network (default: none) 14 | gas: 67219750000, 15 | gasPrice: 50, 16 | }, 17 | }, 18 | 19 | compilers: { 20 | solc: { 21 | version: "0.5.15", 22 | // version: ">=0.4.33 <0.6.0", // Fetch exact version from solc-bin (default: truffle's version) 23 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 24 | settings: { 25 | optimizer: { 26 | enabled: true, 27 | runs: 200, 28 | }, 29 | } 30 | } 31 | } 32 | } 33 | --------------------------------------------------------------------------------