├── .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 |
--------------------------------------------------------------------------------