@axelar-network/axelar-cgp-solidity
Advanced tools
Comparing version 4.5.0 to 5.0.0
@@ -7,4 +7,8 @@ { | ||
"compiler-version": ["off"], | ||
"func-visibility": ["warn", {"ignoreConstructors": true}] | ||
"func-visibility": ["warn", { "ignoreConstructors": true }], | ||
"no-inline-assembly": "off", | ||
"no-empty-blocks": "off", | ||
"avoid-low-level-calls": "off", | ||
"not-rely-on-time": "off" | ||
} | ||
} |
@@ -1,3 +0,8 @@ | ||
require('@nomiclabs/hardhat-waffle'); | ||
require('hardhat-gas-reporter'); | ||
require('@nomicfoundation/hardhat-toolbox'); | ||
const env = process.env.ENV || 'testnet'; | ||
const { importNetworks, readJSON } = require('@axelar-network/axelar-contract-deployments/evm/utils'); | ||
const chains = require(`@axelar-network/axelar-contract-deployments/info/${env}.json`); | ||
const keys = readJSON(`${__dirname}/info/keys.json`); | ||
const { networks, etherscan } = importNetworks(chains, keys); | ||
require('solidity-coverage'); | ||
@@ -17,8 +22,8 @@ | ||
details: { | ||
peephole: true, | ||
inliner: true, | ||
peephole: process.env.COVERAGE === undefined, | ||
inliner: process.env.COVERAGE === undefined, | ||
jumpdestRemover: true, | ||
orderLiterals: true, | ||
deduplicate: true, | ||
cse: true, | ||
cse: process.env.COVERAGE === undefined, | ||
constantOptimizer: true, | ||
@@ -33,7 +38,11 @@ yul: true, | ||
}, | ||
networks: { | ||
hardhat: { | ||
chainId: 1, | ||
}, | ||
defaultNetwork: 'hardhat', | ||
networks: networks, | ||
etherscan: etherscan, | ||
mocha: { | ||
timeout: 1000000, | ||
}, | ||
gasReporter: { | ||
enabled: process.env.REPORT_GAS !== undefined, | ||
}, | ||
}; |
[ | ||
{ | ||
"name": "Ethereum", | ||
"id": "Ethereum", | ||
"chainId": 1, | ||
@@ -12,2 +13,5 @@ "rpc": "https://mainnet.infura.io/v3/a4812158fbab4a2aaa849e6f4a6dc605", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0x4F4495243837681061C4743b74B3eEdf548D56A5" | ||
}, | ||
"AxelarGasService": { | ||
@@ -27,2 +31,6 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://etherscan.io", | ||
"api": "https://api.etherscan.io/api" | ||
} | ||
@@ -32,2 +40,3 @@ }, | ||
"name": "Avalanche", | ||
"id": "Avalanche", | ||
"chainId": 43114, | ||
@@ -41,2 +50,5 @@ "rpc": "https://api.avax.network/ext/bc/C/rpc", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0x5029C0EFf6C34351a0CEc334542cDb22c7928f78" | ||
}, | ||
"AxelarGasService": { | ||
@@ -56,2 +68,6 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://snowtrace.io", | ||
"api": "https://api.snowtrace.io/api" | ||
} | ||
@@ -61,2 +77,3 @@ }, | ||
"name": "Fantom", | ||
"id": "Fantom", | ||
"chainId": 250, | ||
@@ -70,2 +87,5 @@ "gateway": "0x304acf330bbE08d1e512eefaa92F6a57871fD895", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0x304acf330bbE08d1e512eefaa92F6a57871fD895" | ||
}, | ||
"AxelarGasService": { | ||
@@ -85,2 +105,6 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://ftmscan.com", | ||
"api": "https://api.ftmscan.com/api" | ||
} | ||
@@ -90,2 +114,3 @@ }, | ||
"name": "Polygon", | ||
"id": "Polygon", | ||
"chainId": 137, | ||
@@ -99,2 +124,5 @@ "gateway": "0x6f015F16De9fC8791b234eF68D486d2bF203FBA8", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0x6f015F16De9fC8791b234eF68D486d2bF203FBA8" | ||
}, | ||
"AxelarGasService": { | ||
@@ -115,4 +143,8 @@ "salt": "AxelarGasService", | ||
}, | ||
"explorer": { | ||
"url": "https://polygonscan.com", | ||
"api": "https://api.polygonscan.com/api" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 6e6 | ||
"gasLimit": 6000000 | ||
} | ||
@@ -122,2 +154,3 @@ }, | ||
"name": "Moonbeam", | ||
"id": "Moonbeam", | ||
"chainId": 1284, | ||
@@ -131,2 +164,5 @@ "gateway": "0x4F4495243837681061C4743b74B3eEdf548D56A5", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0x4F4495243837681061C4743b74B3eEdf548D56A5" | ||
}, | ||
"AxelarGasService": { | ||
@@ -146,2 +182,6 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://moonbeam.moonscan.io", | ||
"api": "https://api-moonbeam.moonscan.io/api" | ||
} | ||
@@ -151,2 +191,3 @@ }, | ||
"name": "Binance", | ||
"id": "binance", | ||
"chainId": 56, | ||
@@ -160,2 +201,5 @@ "gateway": "0x304acf330bbE08d1e512eefaa92F6a57871fD895", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0x304acf330bbE08d1e512eefaa92F6a57871fD895" | ||
}, | ||
"AxelarGasService": { | ||
@@ -175,2 +219,6 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://bscscan.com", | ||
"api": "https://api.bscscan.com/api" | ||
} | ||
@@ -180,2 +228,3 @@ }, | ||
"name": "Aurora", | ||
"id": "aurora", | ||
"chainId": 1313161554, | ||
@@ -189,2 +238,5 @@ "gateway": "0x304acf330bbE08d1e512eefaa92F6a57871fD895", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0x304acf330bbE08d1e512eefaa92F6a57871fD895" | ||
}, | ||
"AxelarGasService": { | ||
@@ -204,2 +256,6 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://aurorascan.dev", | ||
"api": "https://api.aurorascan.dev/api" | ||
} | ||
@@ -209,2 +265,3 @@ }, | ||
"name": "Arbitrum", | ||
"id": "arbitrum", | ||
"chainId": 42161, | ||
@@ -217,2 +274,5 @@ "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31" | ||
}, | ||
"AxelarGasService": { | ||
@@ -233,4 +293,8 @@ "salt": "AxelarGasService", | ||
}, | ||
"explorer": { | ||
"url": "https://arbiscan.io", | ||
"api": "https://api.arbiscan.io/api" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 20e6 | ||
"gasLimit": 20000000 | ||
} | ||
@@ -240,2 +304,3 @@ }, | ||
"name": "Celo", | ||
"id": "celo", | ||
"chainId": 42220, | ||
@@ -248,2 +313,5 @@ "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31" | ||
}, | ||
"AxelarGasService": { | ||
@@ -263,2 +331,6 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://celoscan.io", | ||
"api": "https://api.celoscan.io/api" | ||
} | ||
@@ -268,2 +340,3 @@ }, | ||
"name": "Kava", | ||
"id": "kava", | ||
"chainId": 2222, | ||
@@ -276,2 +349,5 @@ "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31" | ||
}, | ||
"AxelarGasService": { | ||
@@ -291,4 +367,88 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://explorer.kava.io", | ||
"api": "https://explorer.kava.io/api" | ||
} | ||
}, | ||
{ | ||
"name": "Filecoin", | ||
"id": "filecoin", | ||
"chainId": 314, | ||
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"rpc": "https://rpc.ankr.com/filecoin", | ||
"constAddressDeployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e", | ||
"tokenName": "Filecoin", | ||
"tokenSymbol": "FIL", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"implementation": "0x05823c334150a48ACD5D325fBA16147c21bA3653", | ||
"authModule": "0x1a920B29eBD437074225cAeE44f78FC700B27a5d", | ||
"tokenDeployer": "0x8A156bCA562FB75385c4d41ea6903E270A34B727", | ||
"deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC" | ||
}, | ||
"AxelarGasService": { | ||
"salt": "AxelarGasService", | ||
"collector": "0x345662ABfE0E257E23552A434D02Ef274cCb6A90", | ||
"address": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"implementation": "0xfEF5c90d84a1C93804496f5e7fbf98ec0C85243C", | ||
"deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05" | ||
}, | ||
"AxelarDepositService": { | ||
"salt": "AxelarDepositService", | ||
"wrappedSymbol": "WFIL", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF", | ||
"address": "0xc1DCb196BA862B337Aa23eDA1Cb9503C0801b955", | ||
"implementation": "0xd883C8bA523253c93d97b6C7a5087a7B5ff23d79", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://www.filfox.info" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 500000000 | ||
} | ||
}, | ||
{ | ||
"name": "Optimism", | ||
"id": "optimism", | ||
"chainId": 10, | ||
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"rpc": "https://optimism-mainnet.public.blastapi.io", | ||
"constAddressDeployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e", | ||
"tokenName": "Eth", | ||
"tokenSymbol": "ETH", | ||
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"implementation": "0x05823c334150a48ACD5D325fBA16147c21bA3653", | ||
"authModule": "0x1a920B29eBD437074225cAeE44f78FC700B27a5d", | ||
"tokenDeployer": "0x8A156bCA562FB75385c4d41ea6903E270A34B727", | ||
"deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC" | ||
}, | ||
"AxelarGasService": { | ||
"salt": "AxelarGasService", | ||
"collector": "0x345662ABfE0E257E23552A434D02Ef274cCb6A90", | ||
"address": "0x2d5d7d31F671F86C782533cc367F14109a082712", | ||
"implementation": "0xfEF5c90d84a1C93804496f5e7fbf98ec0C85243C", | ||
"deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05" | ||
}, | ||
"AxelarDepositService": { | ||
"salt": "AxelarDepositService", | ||
"wrappedSymbol": "", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF", | ||
"address": "0xc1DCb196BA862B337Aa23eDA1Cb9503C0801b955", | ||
"implementation": "0xd883C8bA523253c93d97b6C7a5087a7B5ff23d79", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://optimistic.etherscan.io", | ||
"api": "https://api-optimistic.etherscan.io/api" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 5000000 | ||
}, | ||
"confirmations": 3 | ||
} | ||
] |
[ | ||
{ | ||
"name": "Ethereum", | ||
"id": "ethereum-2", | ||
"chainId": 5, | ||
@@ -11,2 +12,5 @@ "rpc": "https://goerli.infura.io/v3/a4812158fbab4a2aaa849e6f4a6dc605", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31" | ||
}, | ||
"AxelarGasService": { | ||
@@ -26,2 +30,6 @@ "salt": "AxelarGasService", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF" | ||
}, | ||
"explorer": { | ||
"url": "https://goerli.etherscan.io", | ||
"api": "https://api-goerli.etherscan.io/api" | ||
} | ||
@@ -31,2 +39,3 @@ }, | ||
"name": "Avalanche", | ||
"id": "Avalanche", | ||
"chainId": 43113, | ||
@@ -39,2 +48,5 @@ "rpc": "https://api.avax-test.network/ext/bc/C/rpc", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xC249632c2D40b9001FE907806902f63038B737Ab" | ||
}, | ||
"AxelarGasService": { | ||
@@ -54,2 +66,6 @@ "salt": "AxelarGasService", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF" | ||
}, | ||
"explorer": { | ||
"url": "https://testnet.snowtrace.io", | ||
"api": "https://api-testnet.snowtrace.io/api" | ||
} | ||
@@ -59,2 +75,3 @@ }, | ||
"name": "Fantom", | ||
"id": "Fantom", | ||
"chainId": 4002, | ||
@@ -67,2 +84,5 @@ "gateway": "0x97837985Ec0494E7b9C71f5D3f9250188477ae14", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0x97837985Ec0494E7b9C71f5D3f9250188477ae14" | ||
}, | ||
"AxelarGasService": { | ||
@@ -82,2 +102,9 @@ "salt": "AxelarGasService", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF" | ||
}, | ||
"explorer": { | ||
"url": "https://testnet.ftmscan.com", | ||
"api": "https://api-testnet.ftmscan.com/api" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 5000000 | ||
} | ||
@@ -87,2 +114,3 @@ }, | ||
"name": "Polygon", | ||
"id": "Polygon", | ||
"chainId": 80001, | ||
@@ -95,2 +123,5 @@ "gateway": "0xBF62ef1486468a6bd26Dd669C06db43dEd5B849B", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xBF62ef1486468a6bd26Dd669C06db43dEd5B849B" | ||
}, | ||
"AxelarGasService": { | ||
@@ -111,2 +142,6 @@ "salt": "AxelarGasService", | ||
}, | ||
"explorer": { | ||
"url": "https://mumbai.polygonscan.com", | ||
"api": "https://api-testnet.polygonscan.com/api" | ||
}, | ||
"gasOptions": { | ||
@@ -118,2 +153,3 @@ "gasLimit": 6000000 | ||
"name": "Moonbeam", | ||
"id": "Moonbeam", | ||
"chainId": 1287, | ||
@@ -126,2 +162,5 @@ "gateway": "0x5769D84DD62a6fD969856c75c7D321b84d455929", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0x5769D84DD62a6fD969856c75c7D321b84d455929" | ||
}, | ||
"AxelarGasService": { | ||
@@ -141,2 +180,6 @@ "salt": "AxelarGasService", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF" | ||
}, | ||
"explorer": { | ||
"url": "https://moonbase.moonscan.io", | ||
"api": "https://api-moonbase.moonscan.io/api" | ||
} | ||
@@ -146,2 +189,3 @@ }, | ||
"name": "Binance", | ||
"id": "binance", | ||
"chainId": 97, | ||
@@ -154,2 +198,5 @@ "gateway": "0x4D147dCb984e6affEEC47e44293DA442580A3Ec0", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0x4D147dCb984e6affEEC47e44293DA442580A3Ec0" | ||
}, | ||
"AxelarGasService": { | ||
@@ -169,2 +216,6 @@ "salt": "AxelarGasService", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF" | ||
}, | ||
"explorer": { | ||
"url": "https://testnet.bscscan.com", | ||
"api": "https://api-testnet.bscscan.com/api" | ||
} | ||
@@ -174,2 +225,3 @@ }, | ||
"name": "Aurora", | ||
"id": "aurora", | ||
"chainId": 1313161555, | ||
@@ -182,2 +234,5 @@ "gateway": "0x304acf330bbE08d1e512eefaa92F6a57871fD895", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0x304acf330bbE08d1e512eefaa92F6a57871fD895" | ||
}, | ||
"AxelarGasService": { | ||
@@ -197,2 +252,6 @@ "salt": "AxelarGasService", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF" | ||
}, | ||
"explorer": { | ||
"url": "https://testnet.aurorascan.dev", | ||
"api": "https://api-testnet.aurorascan.dev/api" | ||
} | ||
@@ -202,2 +261,3 @@ }, | ||
"name": "Arbitrum", | ||
"id": "arbitrum", | ||
"chainId": 421613, | ||
@@ -210,2 +270,5 @@ "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31" | ||
}, | ||
"AxelarGasService": { | ||
@@ -228,2 +291,6 @@ "salt": "AxelarGasService", | ||
"gasLimit": 20000000 | ||
}, | ||
"explorer": { | ||
"url": "https://goerli.arbiscan.io", | ||
"api": "https://api-goerli.arbiscan.io/api" | ||
} | ||
@@ -233,2 +300,3 @@ }, | ||
"name": "Celo", | ||
"id": "celo", | ||
"chainId": 44787, | ||
@@ -241,2 +309,5 @@ "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31" | ||
}, | ||
"AxelarGasService": { | ||
@@ -256,2 +327,9 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://alfajores.celoscan.io", | ||
"api": "https://api-alfajores.celoscan.io/api" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 5000000 | ||
} | ||
@@ -261,2 +339,3 @@ }, | ||
"name": "Kava", | ||
"id": "kava", | ||
"chainId": 2221, | ||
@@ -269,2 +348,5 @@ "gateway": "0xC8D18F85cB0Cee5C95eC29c69DeaF6cea972349c", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xC8D18F85cB0Cee5C95eC29c69DeaF6cea972349c" | ||
}, | ||
"AxelarGasService": { | ||
@@ -284,4 +366,186 @@ "salt": "AxelarGasService", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://explorer.evm-alpha.kava.io" | ||
} | ||
}, | ||
{ | ||
"name": "Optimism", | ||
"id": "optimism", | ||
"chainId": 420, | ||
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"rpc": "https://optimism-goerli.public.blastapi.io", | ||
"constAddressDeployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e", | ||
"tokenName": "Eth", | ||
"tokenSymbol": "ETH", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31" | ||
}, | ||
"AxelarGasService": { | ||
"salt": "AxelarGasService", | ||
"collector": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", | ||
"address": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"implementation": "0xCD6b34FaF1FD1056C728A27426AB6807f84BAa1b", | ||
"deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC" | ||
}, | ||
"AxelarDepositService": { | ||
"salt": "AxelarDepositService", | ||
"wrappedSymbol": "", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF", | ||
"address": "0xc1DCb196BA862B337Aa23eDA1Cb9503C0801b955", | ||
"implementation": "0xb6241272C569767072e0587098415DF6BA0aaEe9", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://goerli-optimism.etherscan.io", | ||
"api": "https://api-goerli-optimism.etherscan.io/api" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 5000000 | ||
}, | ||
"confirmations": 3 | ||
}, | ||
{ | ||
"name": "Base", | ||
"id": "base", | ||
"chainId": 84531, | ||
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"rpc": "https://goerli.base.org", | ||
"constAddressDeployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e", | ||
"tokenName": "Eth", | ||
"tokenSymbol": "ETH", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31" | ||
}, | ||
"AxelarGasService": { | ||
"salt": "AxelarGasService", | ||
"collector": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", | ||
"address": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"implementation": "0xCD6b34FaF1FD1056C728A27426AB6807f84BAa1b", | ||
"deployer": "0x5b593E7b1725dc6FcbbFe80b2415B19153F94A85" | ||
}, | ||
"AxelarDepositService": { | ||
"salt": "AxelarDepositService", | ||
"wrappedSymbol": "", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF", | ||
"address": "0xc1DCb196BA862B337Aa23eDA1Cb9503C0801b955", | ||
"implementation": "0xd883C8bA523253c93d97b6C7a5087a7B5ff23d79", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://goerli.basescan.org", | ||
"api": "https://api-goerli.basescan.org/api" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 5000000 | ||
} | ||
}, | ||
{ | ||
"name": "Filecoin", | ||
"id": "filecoin", | ||
"chainId": 3141, | ||
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"rpc": "https://rpc.ankr.com/filecoin_testnet", | ||
"constAddressDeployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e", | ||
"tokenName": "Filecoin", | ||
"tokenSymbol": "FIL", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"implementation": "0x05823c334150a48ACD5D325fBA16147c21bA3653", | ||
"authModule": "0x1a920B29eBD437074225cAeE44f78FC700B27a5d", | ||
"tokenDeployer": "0x8A156bCA562FB75385c4d41ea6903E270A34B727", | ||
"deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC" | ||
}, | ||
"AxelarGasService": { | ||
"salt": "AxelarGasService", | ||
"collector": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", | ||
"address": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"implementation": "0xCD6b34FaF1FD1056C728A27426AB6807f84BAa1b", | ||
"deployer": "0x5b593E7b1725dc6FcbbFe80b2415B19153F94A85" | ||
}, | ||
"AxelarDepositService": { | ||
"salt": "AxelarDepositService", | ||
"wrappedSymbol": "WFIL", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF", | ||
"address": "0xc1DCb196BA862B337Aa23eDA1Cb9503C0801b955", | ||
"implementation": "0xd883C8bA523253c93d97b6C7a5087a7B5ff23d79", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b" | ||
}, | ||
"explorer": { | ||
"url": "https://hyperspace.filfox.info" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 500000000 | ||
} | ||
}, | ||
{ | ||
"name": "Linea", | ||
"id": "linea", | ||
"chainId": 59140, | ||
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"rpc": "https://rpc.goerli.linea.build", | ||
"constAddressDeployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e", | ||
"tokenName": "Eth", | ||
"tokenSymbol": "ETH", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGateway": { | ||
"address": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"implementation": "0x05823c334150a48ACD5D325fBA16147c21bA3653", | ||
"authModule": "0x1a920B29eBD437074225cAeE44f78FC700B27a5d", | ||
"tokenDeployer": "0x8A156bCA562FB75385c4d41ea6903E270A34B727", | ||
"deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC" | ||
}, | ||
"AxelarGasService": { | ||
"salt": "AxelarGasService", | ||
"collector": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", | ||
"deployer": "0x5b593E7b1725dc6FcbbFe80b2415B19153F94A85", | ||
"address": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"implementation": "0xCD6b34FaF1FD1056C728A27426AB6807f84BAa1b" | ||
}, | ||
"AxelarDepositService": { | ||
"salt": "AxelarDepositService", | ||
"wrappedSymbol": "", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF", | ||
"deployer": "0xd55cd98cdE61c3CcE1286F9aF50cDbF16f5dba5b", | ||
"address": "0xc1DCb196BA862B337Aa23eDA1Cb9503C0801b955", | ||
"implementation": "0xd883C8bA523253c93d97b6C7a5087a7B5ff23d79" | ||
}, | ||
"explorer": { | ||
"url": "https://explorer.goerli.linea.build", | ||
"api": "https://explorer.goerli.linea.build/api" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 5000000 | ||
} | ||
}, | ||
{ | ||
"name": "zkEVM", | ||
"id": "polygon-zkevm", | ||
"chainId": 1442, | ||
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", | ||
"rpc": "https://rpc.public.zkevm-test.net", | ||
"constAddressDeployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e", | ||
"tokenName": "Eth", | ||
"tokenSymbol": "ETH", | ||
"gasReceiver": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", | ||
"AxelarGasService": { | ||
"salt": "AxelarGasService", | ||
"collector": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC" | ||
}, | ||
"AxelarDepositService": { | ||
"salt": "AxelarDepositService", | ||
"wrappedSymbol": "", | ||
"refundIssuer": "0x4f671f34d2d23fec3eE3087E3A0221f8D314D9dF" | ||
}, | ||
"explorer": { | ||
"url": "https://testnet-zkevm.polygonscan.com", | ||
"api": "https://api-testnet-zkevm.polygonscan.com/api" | ||
}, | ||
"gasOptions": { | ||
"gasLimit": 5000000 | ||
} | ||
} | ||
] |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
@@ -38,7 +38,2 @@ { | ||
"inputs": [], | ||
"name": "NativeTransferFailed", | ||
"type": "error" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "NotOwner", | ||
@@ -74,7 +69,2 @@ "type": "error" | ||
"inputs": [], | ||
"name": "TokenTransferFailed", | ||
"type": "error" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "UnwrapFailed", | ||
@@ -81,0 +71,0 @@ "type": "error" |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
@@ -57,5 +57,37 @@ { | ||
{ | ||
"inputs": [], | ||
"name": "TransferFailed", | ||
"type": "error" | ||
"anonymous": false, | ||
"inputs": [ | ||
{ | ||
"indexed": true, | ||
"internalType": "bytes32", | ||
"name": "txHash", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"indexed": true, | ||
"internalType": "uint256", | ||
"name": "logIndex", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "address", | ||
"name": "gasToken", | ||
"type": "address" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "uint256", | ||
"name": "gasFeeAmount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
} | ||
], | ||
"name": "ExpressGasAdded", | ||
"type": "event" | ||
}, | ||
@@ -214,3 +246,64 @@ { | ||
"indexed": true, | ||
"internalType": "address", | ||
"name": "sourceAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "string", | ||
"name": "destinationChain", | ||
"type": "string" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "string", | ||
"name": "destinationAddress", | ||
"type": "string" | ||
}, | ||
{ | ||
"indexed": true, | ||
"internalType": "bytes32", | ||
"name": "payloadHash", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "string", | ||
"name": "symbol", | ||
"type": "string" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "uint256", | ||
"name": "amount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "address", | ||
"name": "gasToken", | ||
"type": "address" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "uint256", | ||
"name": "gasFeeAmount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
} | ||
], | ||
"name": "GasPaidForExpressCallWithToken", | ||
"type": "event" | ||
}, | ||
{ | ||
"anonymous": false, | ||
"inputs": [ | ||
{ | ||
"indexed": true, | ||
"internalType": "bytes32", | ||
"name": "txHash", | ||
@@ -238,2 +331,33 @@ "type": "bytes32" | ||
], | ||
"name": "NativeExpressGasAdded", | ||
"type": "event" | ||
}, | ||
{ | ||
"anonymous": false, | ||
"inputs": [ | ||
{ | ||
"indexed": true, | ||
"internalType": "bytes32", | ||
"name": "txHash", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"indexed": true, | ||
"internalType": "uint256", | ||
"name": "logIndex", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "uint256", | ||
"name": "gasFeeAmount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
} | ||
], | ||
"name": "NativeGasAdded", | ||
@@ -346,2 +470,57 @@ "type": "event" | ||
"internalType": "address", | ||
"name": "sourceAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "string", | ||
"name": "destinationChain", | ||
"type": "string" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "string", | ||
"name": "destinationAddress", | ||
"type": "string" | ||
}, | ||
{ | ||
"indexed": true, | ||
"internalType": "bytes32", | ||
"name": "payloadHash", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "string", | ||
"name": "symbol", | ||
"type": "string" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "uint256", | ||
"name": "amount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "uint256", | ||
"name": "gasFeeAmount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
} | ||
], | ||
"name": "NativeGasPaidForExpressCallWithToken", | ||
"type": "event" | ||
}, | ||
{ | ||
"anonymous": false, | ||
"inputs": [ | ||
{ | ||
"indexed": true, | ||
"internalType": "address", | ||
"name": "newOwner", | ||
@@ -359,3 +538,40 @@ "type": "address" | ||
"indexed": true, | ||
"internalType": "bytes32", | ||
"name": "txHash", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"indexed": true, | ||
"internalType": "uint256", | ||
"name": "logIndex", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "address payable", | ||
"name": "receiver", | ||
"type": "address" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "address", | ||
"name": "token", | ||
"type": "address" | ||
}, | ||
{ | ||
"indexed": false, | ||
"internalType": "uint256", | ||
"name": "amount", | ||
"type": "uint256" | ||
} | ||
], | ||
"name": "Refunded", | ||
"type": "event" | ||
}, | ||
{ | ||
"anonymous": false, | ||
"inputs": [ | ||
{ | ||
"indexed": true, | ||
"internalType": "address", | ||
"name": "newImplementation", | ||
@@ -396,2 +612,35 @@ "type": "address" | ||
], | ||
"name": "addExpressGas", | ||
"outputs": [], | ||
"stateMutability": "nonpayable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "bytes32", | ||
"name": "txHash", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "txIndex", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "gasToken", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "gasFeeAmount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
} | ||
], | ||
"name": "addGas", | ||
@@ -420,2 +669,25 @@ "outputs": [], | ||
], | ||
"name": "addNativeExpressGas", | ||
"outputs": [], | ||
"stateMutability": "payable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "bytes32", | ||
"name": "txHash", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "logIndex", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
} | ||
], | ||
"name": "addNativeGas", | ||
@@ -620,3 +892,23 @@ "outputs": [], | ||
{ | ||
"internalType": "string", | ||
"name": "symbol", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "amount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "gasToken", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "gasFeeAmount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
@@ -626,2 +918,35 @@ "type": "address" | ||
], | ||
"name": "payGasForExpressCallWithToken", | ||
"outputs": [], | ||
"stateMutability": "nonpayable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "address", | ||
"name": "sender", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationChain", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationAddress", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "bytes", | ||
"name": "payload", | ||
"type": "bytes" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
} | ||
], | ||
"name": "payNativeGasForContractCall", | ||
@@ -678,2 +1003,45 @@ "outputs": [], | ||
{ | ||
"internalType": "address", | ||
"name": "sender", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationChain", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationAddress", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "bytes", | ||
"name": "payload", | ||
"type": "bytes" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "symbol", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "uint256", | ||
"name": "amount", | ||
"type": "uint256" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
} | ||
], | ||
"name": "payNativeGasForExpressCallWithToken", | ||
"outputs": [], | ||
"stateMutability": "payable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "address payable", | ||
@@ -680,0 +1048,0 @@ "name": "receiver", |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
@@ -23,7 +23,2 @@ { | ||
"inputs": [], | ||
"name": "NativeTransferFailed", | ||
"type": "error" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "NotRefundIssuer", | ||
@@ -44,7 +39,2 @@ "type": "error" | ||
"inputs": [], | ||
"name": "TokenTransferFailed", | ||
"type": "error" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "UnwrapFailed", | ||
@@ -51,0 +41,0 @@ "type": "error" |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/1bfbf2f54282808b0d5584fdc4c5b4e5.json" | ||
"buildInfo": "../../../build-info/09fa6ceec0d0da7eb4c97dad6c1dda7a.json" | ||
} |
{ | ||
"name": "@axelar-network/axelar-cgp-solidity", | ||
"version": "4.5.0", | ||
"version": "5.0.0", | ||
"description": "EVM Smart Contracts for Axelar Network", | ||
"main": "index.js", | ||
"scripts": { | ||
"build": "rm -rf artifacts && hardhat compile", | ||
"build": "hardhat clean && hardhat compile", | ||
"test": "hardhat test", | ||
@@ -12,3 +12,4 @@ "test-evm-versions": "bash test-evm-versions.bash", | ||
"prettier": "prettier --write 'contracts/**/*.sol' 'test/**/*.js' 'scripts/**/*.js' '*.js'", | ||
"flatten": "sh scripts/flatten-contracts.sh" | ||
"flatten": "sh scripts/flatten-contracts.sh", | ||
"coverage": "cross-env COVERAGE=true hardhat coverage" | ||
}, | ||
@@ -29,22 +30,22 @@ "repository": { | ||
"homepage": "https://github.com/axelarnetwork/axelar-cgp-solidity#readme", | ||
"dependencies": { | ||
"@axelar-network/axelar-gmp-sdk-solidity": "^4.0.0" | ||
}, | ||
"devDependencies": { | ||
"@nomiclabs/hardhat-ethers": "^2.0.6", | ||
"@nomiclabs/hardhat-waffle": "^2.0.3", | ||
"axelar-utils-solidity": "https://github.com/axelarnetwork/axelar-utils-solidity.git", | ||
"chai": "^4.3.6", | ||
"@axelar-network/axelar-contract-deployments": "git://github.com/axelarnetwork/axelar-contract-deployments.git#74b942fdf10875a27b532d9bd6dfe2bd6db8a094", | ||
"@nomicfoundation/hardhat-toolbox": "^2.0.2", | ||
"chai": "^4.3.7", | ||
"cross-env": "^7.0.3", | ||
"dotenv": "^16.0.1", | ||
"eslint": "^8.17.0", | ||
"eslint": "^8.36.0", | ||
"eslint-config-richardpringle": "^2.0.0", | ||
"ethereum-waffle": "^3.4.4", | ||
"ethers": "^5.6.8", | ||
"fs-extra": "^10.1.0", | ||
"hardhat": "^2.9.7", | ||
"hardhat-gas-reporter": "^1.0.8", | ||
"ethers": "^5.7.2", | ||
"fs-extra": "^11.1.1", | ||
"hardhat": "^2.13.0", | ||
"lodash": "^4.17.21", | ||
"mocha": "^10.0.0", | ||
"prettier": "^2.6.2", | ||
"prettier-plugin-solidity": "^1.0.0-beta.19", | ||
"mocha": "^10.2.0", | ||
"prettier": "^2.8.7", | ||
"prettier-plugin-solidity": "1.0.0-beta.19", | ||
"readline-sync": "^1.4.10", | ||
"solhint": "^3.3.7", | ||
"solidity-coverage": "^0.7.21" | ||
"solhint": "^3.4.1" | ||
}, | ||
@@ -51,0 +52,0 @@ "engines": { |
131
README.md
@@ -12,4 +12,6 @@ # Axelar cross-chain gateway protocol solidity implementation | ||
See [this doc](./DESIGN.md) for more design info. | ||
## Build | ||
###### node version | ||
We recommend using the current Node.js [LTS version](https://nodejs.org/en/about/releases/) for satisfying the hardhat compiler | ||
@@ -23,3 +25,3 @@ | ||
npm run test # Test with hardhat | ||
npm run test | ||
``` | ||
@@ -29,2 +31,4 @@ | ||
See Axelar [examples](https://github.com/axelarnetwork/axelar-examples) for concrete examples. | ||
### Token transfer | ||
@@ -74,119 +78,2 @@ | ||
### Cross-chain NFT transfer/minter | ||
See this [example](https://github.com/axelarnetwork/axelar-local-dev-sample/tree/main/examples/nft-linker) cross-chain NFT application. | ||
## Design Notes | ||
- `AxelarGateway.execute()` takes a signed batched of commands. | ||
Each command has a corresponding `commandID`. This is guaranteed to be unique from the Axelar network. `execute` intentionally allows retrying | ||
a `commandID` if the `command` failed to be processed; this is because commands are state dependent, and someone might submit command 2 before command 1 causing it to fail. | ||
- Axelar network supports sending any Cosmos/ERC-20 token to any other Cosmos/EVM chain. | ||
- Supported tokens have 3 different types: | ||
- `External`: An external ERC-20 token on it's native chain is registered as external, e.g. `USDC` on Ethereum. | ||
- `InternalBurnableFrom`: Axelar wrapped tokens that are minted by the Axelar network when transferring over the original token, e.g. `axlATOM`, `axlUSDC` on Avalanche. | ||
- `InternalBurnable`: `v1.0.0` version of Axelar wrapped tokens that used a different deposit address contract, e.g. `UST` (native to Terra) on Avalanche. | ||
New tokens cannot be of this type, and this is only present for legacy support. | ||
- Deploying gateway contract: | ||
- Deploy the `AxelarAuthWeighted` contract. | ||
- Deploy the `TokenDeployer` contract. | ||
- Deploy the `AxelarGateway` contract with the token deployer address. | ||
- Deploy the `AxelarGatewayProxy` contract with the implementation contract address (from above) and `setup` params obtained from the current network state. | ||
## Smart Contracts | ||
### Interfaces | ||
#### IAxelarGateway.sol | ||
#### IERC20.sol | ||
#### IERC20BurnFrom.sol | ||
#### IAxelarExecutable.sol | ||
This interface needs to be implemented by the application contract | ||
to receive cross-chain messages. See the | ||
[token swapper example](/contracts/test/gmp/DestinationChainSwapExecutable.sol) for an example. | ||
### Contracts | ||
#### AxelarGatewayProxy.sol | ||
Our gateway contracts implement the proxy pattern to allow upgrades. | ||
Calls are delegated to the implementation contract while using the proxy's storage. | ||
`setup` function is overridden to be an empty method on the proxy contract to prevent anyone besides the proxy contract | ||
from calling the implementation's `setup` on the proxy storage. | ||
#### AxelarGateway.sol | ||
The implementation contract that accepts commands signed by Axelar network's validators (see `execute`). | ||
The signature proof verification is performed by `AxelarAuthWeighted` contract. | ||
#### AxelarAuthWeighted.sol | ||
Weighted multisig authentication contract that is used by the gateway. | ||
It accepts a set of operators with corresponding weights. | ||
To verify the message weights of provided signatures are summed and need to meet the specified threshold | ||
#### AdminMultisigBase.sol | ||
Multisig governance contract. Upgrading the implementation is done via voting on the new implementation address from admin accounts. | ||
#### ERC20.sol | ||
Base ERC20 contract used to deploy wrapped version of tokens on other chains. | ||
#### ERC20Permit.sol | ||
Allow an account to issue a spending permit to another account. | ||
#### MintableCappedERC20.sol | ||
Mintable ERC20 token contract with an optional capped total supply (when `capacity != 0`). | ||
It also allows us the owner of the ERC20 contract to burn tokens for an account (`IERC20BurnFrom`). | ||
#### BurnableMintableCappedERC20.sol | ||
The main token contract that's deployed for Axelar wrapped version of tokens on non-native chains. | ||
This contract allows burning tokens from deposit addresses generated (`depositAddress`) by the Axelar network, where | ||
users send their deposits. `salt` needed to generate the address is provided in a signed burn command | ||
from the Axelar network validators. | ||
#### TokenDeployer.sol | ||
When the Axelar network submits a signed command to deploy a token, | ||
the token deployer contract is called to deploy the `BurnableMintableCappedERC20` token. | ||
This is done to reduce the bytecode size of the gateway contract to allow deploying on EVM chains | ||
with more restrictive gas limits. | ||
#### DepositHandler.sol | ||
The contract deployed at the deposit addresses that allows burning/locking of the tokens | ||
sent by the user. It prevents re-entrancy, and while it's methods are permisionless, | ||
the gateway deploys the deposit handler and burns/locks in the same call (see `_burnToken`). | ||
#### Ownable.sol | ||
Define ownership of a contract and modifiers for permissioned methods. | ||
#### EternalStorage.sol | ||
Storage contract for the proxy. | ||
#### ECDSA.sol | ||
Modified version of OpenZeppelin ECDSA signature authentication check. | ||
#### AxelarDepositService.sol | ||
This service is used to generate deposit addresses for an ERC20 token or native currency transfer. | ||
The third type of deposit address is for unwrapping native currency from a wrapped ECR20 token. | ||
#### AxelarGasService.sol | ||
This contract is used for cross-chain gas payment. | ||
It accepts payments for covering gas cost on the destination chain. | ||
Gas payment should happen with the same params right before calling `callContract` or `callContractWithToken` on the gateway. | ||
## References | ||
@@ -196,10 +83,8 @@ | ||
Token transfer app: https://satellite.money/ | ||
Deployed contracts: https://docs.axelar.dev/resources/mainnet | ||
General Message Passing Usage: https://docs.axelar.dev/dev/gmp | ||
Example token transfer flow: https://docs.axelar.dev/dev/cli/axl-to-evm | ||
Example cross-chain token swap app: https://app.squidrouter.com | ||
Deployed contracts: https://docs.axelar.dev/resources/mainnet | ||
EVM module of the Axelar network that prepares commands for the gateway: https://github.com/axelarnetwork/axelar-core/blob/main/x/evm/keeper/msg_server.go |
'use strict'; | ||
require('dotenv').config(); | ||
const _ = require('lodash/fp'); | ||
const { get, getOr, isEmpty } = require('lodash/fp'); | ||
const { | ||
Contract, | ||
Wallet, | ||
@@ -9,10 +10,15 @@ getDefaultProvider, | ||
} = require('ethers'); | ||
const { deployUpgradable, upgradeUpgradable, getProxy, predictProxyAddress } = require('./upgradable'); | ||
const readlineSync = require('readline-sync'); | ||
const { outputJsonSync } = require('fs-extra'); | ||
const { writeJSON } = require('./utils'); | ||
const { deployUpgradable, upgradeUpgradable, predictContractConstant } = require('@axelar-network/axelar-gmp-sdk-solidity'); | ||
const IUpgradable = require('@axelar-network/axelar-gmp-sdk-solidity/dist/IUpgradable.json'); | ||
function getImplementationArgs(contractName, chain) { | ||
function getProxy(wallet, proxyAddress) { | ||
return new Contract(proxyAddress, IUpgradable.abi, wallet); | ||
} | ||
async function getImplementationArgs(contractName, chain, wallet) { | ||
if (contractName === 'AxelarGasService') { | ||
const collector = _.get('AxelarGasService.collector', chain); | ||
if (!isAddress(collector)) throw new Error(`${chain.name} | Missing AxelarGasService.collector in the chain info.`); | ||
const collector = get('AxelarGasService.collector', chain); | ||
if (!isAddress(collector)) throw new Error(`Missing AxelarGasService.collector in the chain info.`); | ||
return [collector]; | ||
@@ -22,6 +28,6 @@ } | ||
if (contractName === 'AxelarDepositService') { | ||
const symbol = _.getOr('', 'AxelarDepositService.wrappedSymbol', chain); | ||
if (_.isEmpty(symbol)) console.log(`${chain.name} | AxelarDepositService.wrappedSymbol: wrapped token is disabled`); | ||
const symbol = getOr('', 'AxelarDepositService.wrappedSymbol', chain); | ||
if (isEmpty(symbol)) console.log(`${chain.name} | AxelarDepositService.wrappedSymbol: wrapped token is disabled`); | ||
const refundIssuer = _.get('AxelarDepositService.refundIssuer', chain); | ||
const refundIssuer = get('AxelarDepositService.refundIssuer', chain); | ||
if (!isAddress(refundIssuer)) throw new Error(`${chain.name} | Missing AxelarDepositService.refundIssuer in the chain info.`); | ||
@@ -48,9 +54,2 @@ | ||
async function deploy(env, chains, wallet, artifactPath, contractName, deployTo) { | ||
const setJSON = (data, name) => { | ||
outputJsonSync(name, data, { | ||
spaces: 2, | ||
EOL: '\n', | ||
}); | ||
}; | ||
const implementationPath = artifactPath + contractName + '.sol/' + contractName + '.json'; | ||
@@ -77,5 +76,5 @@ const proxyPath = artifactPath + contractName + 'Proxy.sol/' + contractName + 'Proxy.json'; | ||
const provider = getDefaultProvider(rpc); | ||
const args = getImplementationArgs(contractName, chain); | ||
console.log(`Implementation args for chain ${chain.name}: ${args}`) | ||
console.log(`Gas override for chain ${chain.name}:`, chain.gasOptions) | ||
const args = await getImplementationArgs(contractName, chain); | ||
console.log(`Implementation args for chain ${chain.name}: ${args}`); | ||
console.log(`Gas override for chain ${chain.name}:`, chain.gasOptions); | ||
@@ -90,3 +89,5 @@ if (chain[contractName] && chain[contractName].address) { | ||
if (wallet.address !== owner) { | ||
throw new Error(`${chain.name} | Signer ${wallet.address} does not match contract owner ${owner} for chain ${chain.name} in info.`); | ||
throw new Error( | ||
`${chain.name} | Signer ${wallet.address} does not match contract owner ${owner} for chain ${chain.name} in info.`, | ||
); | ||
} | ||
@@ -103,3 +104,3 @@ | ||
getUpgradeArgs(contractName, chain), | ||
chain.gasOptions, | ||
get('gasOptions.gasLimit', chain), | ||
); | ||
@@ -109,3 +110,3 @@ | ||
setJSON(chains, `../info/${env}.json`); | ||
writeJSON(chains, `../info/${env}.json`); | ||
console.log(`${chain.name} | New Implementation for ${contractName} is at ${chain[contractName]['implementation']}`); | ||
@@ -116,12 +117,7 @@ console.log(`${chain.name} | Upgraded.`); | ||
const setupArgs = getInitArgs(contractName, chain); | ||
console.log(`Proxy setup args: ${setupArgs}`) | ||
console.log(`Proxy deployment salt: '${key}'`) | ||
console.log(`Proxy setup args: ${setupArgs}`); | ||
console.log(`Proxy deployment salt: '${key}'`); | ||
const proxyAddress = await predictProxyAddress( | ||
chain.constAddressDeployer, | ||
wallet.connect(provider), | ||
proxyJson, | ||
key, | ||
); | ||
console.log(`Proxy will be deployed to ${proxyAddress}. Does this match any existing deployments?`); | ||
const proxyAddress = await predictContractConstant(chain.constAddressDeployer, wallet.connect(provider), proxyJson, key); | ||
console.log(`Proxy will be deployed to ${proxyAddress} Does this match any existing deployments?`); | ||
const anwser = readlineSync.question(`Proceed with deployment on ${chain.name}? (y/n) `); | ||
@@ -136,13 +132,14 @@ if (anwser !== 'y') return; | ||
args, | ||
[], | ||
setupArgs, | ||
key, | ||
chain.gasOptions, | ||
get('gasOptions.gasLimit', chain), | ||
); | ||
chain[contractName]["salt"] = key | ||
chain[contractName]["address"] = contract.address | ||
chain[contractName]["implementation"] = await contract.implementation() | ||
chain[contractName]["deployer"] = wallet.address | ||
chain[contractName]['salt'] = key; | ||
chain[contractName]['address'] = contract.address; | ||
chain[contractName]['implementation'] = await contract.implementation(); | ||
chain[contractName]['deployer'] = wallet.address; | ||
setJSON(chains, `../info/${env}.json`); | ||
writeJSON(chains, `../info/${env}.json`); | ||
console.log(`${chain.name} | ConstAddressDeployer is at ${chain.constAddressDeployer}`); | ||
@@ -158,3 +155,3 @@ console.log(`${chain.name} | Implementation for ${contractName} is at ${chain[contractName]['implementation']}`); | ||
if (env === null || (env !== 'local' && !env.includes('devnet') && env !== 'testnet' && env !== 'mainnet')) | ||
throw new Error('Need to specify teslocaltnet | devnet* | testnet | mainnet as an argument to this script.'); | ||
throw new Error('Need to specify local | devnet* | testnet | mainnet as an argument to this script.'); | ||
@@ -161,0 +158,0 @@ const chains = require(`../info/${env}.json`); |
@@ -6,2 +6,4 @@ 'use strict'; | ||
const { sortBy } = require('lodash'); | ||
const fs = require('fs'); | ||
const { outputJsonSync } = require('fs-extra'); | ||
const { | ||
@@ -11,2 +13,10 @@ utils: { computeAddress, parseUnits }, | ||
function printLog(log) { | ||
console.log(JSON.stringify({ log }, null, 2)); | ||
} | ||
function printObj(obj) { | ||
console.log(JSON.stringify(obj, null, 2)); | ||
} | ||
const getAddresses = (prefix, chain, role) => { | ||
@@ -31,10 +41,13 @@ const keyID = execSync(`${prefix} "axelard q tss key-id ${chain} ${role}"`, { | ||
const writeJSON = (data, name) => { | ||
outputJsonSync(name, data, { | ||
spaces: 2, | ||
EOL: '\n', | ||
}); | ||
}; | ||
module.exports = { | ||
printLog(log) { | ||
console.log(JSON.stringify({ log })); | ||
}, | ||
printLog, | ||
printObj(obj) { | ||
console.log(JSON.stringify(obj)); | ||
}, | ||
printObj, | ||
@@ -101,2 +114,7 @@ confirm(values, complete) { | ||
getProxy(prefix, chain) { | ||
const proxy = JSON.parse(execSync(`${prefix} "axelard q evm gateway-address ${chain} --output json"`)).address; | ||
return proxy; | ||
}, | ||
parseWei(str) { | ||
@@ -132,2 +150,4 @@ if (!str) { | ||
}, | ||
writeJSON, | ||
}; |
@@ -9,3 +9,2 @@ const { sortBy } = require('lodash'); | ||
const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000'; | ||
const OLD_KEY_RETENTION = 16; | ||
@@ -102,3 +101,3 @@ | ||
), | ||
).to.be.revertedWith('LowSignaturesWeight()'); | ||
).to.be.revertedWithCustomError(auth, 'LowSignaturesWeight'); | ||
}); | ||
@@ -122,3 +121,3 @@ | ||
), | ||
).to.be.revertedWith('MalformedSigners()'); | ||
).to.be.revertedWithCustomError(auth, 'MalformedSigners'); | ||
}); | ||
@@ -172,3 +171,3 @@ | ||
), | ||
).to.be.revertedWith('InvalidOperators()'); | ||
).to.be.revertedWithCustomError(auth, 'InvalidOperators'); | ||
}), | ||
@@ -240,7 +239,7 @@ ); | ||
it('should not allow transferring operatorship to address zero', async () => { | ||
const newOperators = [ADDRESS_ZERO, '0x6D4017D4b1DCd36e6EA88b7900e8eC64A1D1315b']; | ||
const newOperators = [ethers.constants.AddressZero, '0x6D4017D4b1DCd36e6EA88b7900e8eC64A1D1315b']; | ||
await expect(auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1], 2))).to.be.revertedWith( | ||
'InvalidOperators()', | ||
); | ||
await expect( | ||
auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1], 2)), | ||
).to.be.revertedWithCustomError(auth, 'InvalidOperators'); | ||
}); | ||
@@ -251,5 +250,5 @@ | ||
await expect(auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1], 2))).to.be.revertedWith( | ||
'InvalidOperators()', | ||
); | ||
await expect( | ||
auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1], 2)), | ||
).to.be.revertedWithCustomError(auth, 'InvalidOperators'); | ||
}); | ||
@@ -262,3 +261,3 @@ | ||
auth.transferOperatorship(defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [newOperators, [1, 1], 2])), | ||
).to.be.revertedWith('InvalidOperators()'); | ||
).to.be.revertedWithCustomError(auth, 'InvalidOperators'); | ||
}); | ||
@@ -295,3 +294,3 @@ | ||
), | ||
).to.be.revertedWith('DuplicateOperators()'); | ||
).to.be.revertedWithCustomError(auth, 'DuplicateOperators'); | ||
}); | ||
@@ -302,8 +301,8 @@ | ||
await expect(auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1], 0))).to.be.revertedWith( | ||
'InvalidThreshold()', | ||
); | ||
await expect(auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1], 3))).to.be.revertedWith( | ||
'InvalidThreshold()', | ||
); | ||
await expect( | ||
auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1], 0)), | ||
).to.be.revertedWithCustomError(auth, 'InvalidThreshold'); | ||
await expect( | ||
auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1], 3)), | ||
).to.be.revertedWithCustomError(auth, 'InvalidThreshold'); | ||
}); | ||
@@ -314,8 +313,8 @@ | ||
await expect(auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1], 0))).to.be.revertedWith( | ||
'InvalidWeights()', | ||
); | ||
await expect(auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1, 1], 3))).to.be.revertedWith( | ||
'InvalidWeights()', | ||
); | ||
await expect( | ||
auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1], 0)), | ||
).to.be.revertedWithCustomError(auth, 'InvalidWeights'); | ||
await expect( | ||
auth.transferOperatorship(getTransferWeightedOperatorshipCommand(newOperators, [1, 1, 1], 3)), | ||
).to.be.revertedWithCustomError(auth, 'InvalidWeights'); | ||
}); | ||
@@ -322,0 +321,0 @@ }); |
'use strict'; | ||
const chai = require('chai'); | ||
const { expect } = chai; | ||
const { ethers, network } = require('hardhat'); | ||
const { | ||
Contract, | ||
utils: { defaultAbiCoder, arrayify, solidityPack, formatBytes32String, keccak256, getCreate2Address }, | ||
} = require('ethers'); | ||
const { deployContract, MockProvider, solidity } = require('ethereum-waffle'); | ||
chai.use(solidity); | ||
const { expect } = chai; | ||
const { get } = require('lodash/fp'); | ||
} = ethers; | ||
const { getChainId, getEVMVersion, getGasOptions, getWeightedProxyDeployParams } = require('./utils'); | ||
const CHAIN_ID = 1; | ||
const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000'; | ||
const Auth = require('../artifacts/contracts/auth/AxelarAuthWeighted.sol/AxelarAuthWeighted.json'); | ||
const TokenDeployer = require('../artifacts/contracts/TokenDeployer.sol/TokenDeployer.json'); | ||
const AxelarGatewayProxy = require('../artifacts/contracts/AxelarGatewayProxy.sol/AxelarGatewayProxy.json'); | ||
const AxelarGateway = require('../artifacts/contracts/AxelarGateway.sol/AxelarGateway.json'); | ||
const TestWeth = require('../artifacts/contracts/test/TestWeth.sol/TestWeth.json'); | ||
const ConstAddressDeployer = require('axelar-utils-solidity/dist/ConstAddressDeployer.json'); | ||
const DepositReceiver = require('../artifacts/contracts/deposit-service/DepositReceiver.sol/DepositReceiver.json'); | ||
const ReceiverImplementation = require('../artifacts/contracts/deposit-service/ReceiverImplementation.sol/ReceiverImplementation.json'); | ||
const DepositService = require('../artifacts/contracts/deposit-service/AxelarDepositService.sol/AxelarDepositService.json'); | ||
const DepositServiceProxy = require('../artifacts/contracts/deposit-service/AxelarDepositServiceProxy.sol/AxelarDepositServiceProxy.json'); | ||
const { getWeightedAuthDeployParam, getSignedWeightedExecuteInput, getRandomID } = require('./utils'); | ||
const { deployUpgradable } = require('../scripts/upgradable'); | ||
describe('AxelarDepositService', () => { | ||
const [ownerWallet, operatorWallet, userWallet, adminWallet1, adminWallet2, adminWallet3, adminWallet4, adminWallet5, adminWallet6] = | ||
new MockProvider().getWallets(); | ||
const adminWallets = [adminWallet1, adminWallet2, adminWallet3, adminWallet4, adminWallet5, adminWallet6]; | ||
const threshold = 3; | ||
let ownerWallet, operatorWallet, userWallet, adminWallet1, adminWallet2; | ||
let authFactory; | ||
let tokenDeployerFactory; | ||
let gatewayImplementationFactory; | ||
let gatewayProxyFactory; | ||
let tokenFactory; | ||
let receiverImplementationFactory; | ||
let auth; | ||
let tokenDeployer; | ||
let gatewayImplementation; | ||
let gatewayProxy; | ||
let gateway; | ||
@@ -63,58 +56,83 @@ let token; | ||
beforeEach(async () => { | ||
const params = arrayify( | ||
defaultAbiCoder.encode(['address[]', 'uint8', 'bytes'], [adminWallets.map(get('address')), threshold, '0x']), | ||
); | ||
const constAddressDeployer = await deployContract(ownerWallet, ConstAddressDeployer); | ||
const auth = await deployContract(ownerWallet, Auth, [getWeightedAuthDeployParam([[operatorWallet.address]], [[1]], [1])]); | ||
const tokenDeployer = await deployContract(ownerWallet, TokenDeployer); | ||
const gatewayImplementation = await deployContract(ownerWallet, AxelarGateway, [auth.address, tokenDeployer.address]); | ||
const gatewayProxy = await deployContract(ownerWallet, AxelarGatewayProxy, [gatewayImplementation.address, params]); | ||
await auth.transferOwnership(gatewayProxy.address); | ||
gateway = new Contract(gatewayProxy.address, AxelarGateway.abi, ownerWallet); | ||
before(async () => { | ||
[adminWallet1, adminWallet2] = await ethers.getSigners(); | ||
operatorWallet = adminWallet2; | ||
ownerWallet = adminWallet1; | ||
userWallet = adminWallet2; | ||
token = await deployContract(ownerWallet, TestWeth, [tokenName, tokenSymbol, decimals, capacity]); | ||
wrongToken = await deployContract(ownerWallet, TestWeth, [wrongTokenName, wrongTokenSymbol, decimals, capacity]); | ||
authFactory = await ethers.getContractFactory('AxelarAuthWeighted', ownerWallet); | ||
tokenDeployerFactory = await ethers.getContractFactory('TokenDeployer', ownerWallet); | ||
gatewayProxyFactory = await ethers.getContractFactory('AxelarGatewayProxy', ownerWallet); | ||
tokenFactory = await ethers.getContractFactory('TestWeth', ownerWallet); | ||
gatewayImplementationFactory = await ethers.getContractFactory('AxelarGateway', ownerWallet); | ||
receiverImplementationFactory = await ethers.getContractFactory('ReceiverImplementation', ownerWallet); | ||
await token.deposit({ value: 1e9 }); | ||
await wrongToken.deposit({ value: 1e9 }); | ||
tokenDeployer = await tokenDeployerFactory.deploy().then((d) => d.deployed()); | ||
}); | ||
await gateway.execute( | ||
await getSignedWeightedExecuteInput( | ||
arrayify( | ||
defaultAbiCoder.encode( | ||
['uint256', 'bytes32[]', 'string[]', 'bytes[]'], | ||
[ | ||
CHAIN_ID, | ||
[getRandomID()], | ||
['deployToken'], | ||
[ | ||
defaultAbiCoder.encode( | ||
['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], | ||
[tokenName, tokenSymbol, decimals, capacity, token.address, 0], | ||
), | ||
], | ||
], | ||
describe('deposit service', () => { | ||
before(async () => { | ||
auth = await authFactory.deploy(getWeightedAuthDeployParam([[operatorWallet.address]], [[1]], [1])).then((d) => d.deployed()); | ||
gatewayImplementation = await gatewayImplementationFactory | ||
.deploy(auth.address, tokenDeployer.address) | ||
.then((d) => d.deployed()); | ||
const params = getWeightedProxyDeployParams(ownerWallet.address, ownerWallet.address, [], [], 1); | ||
gatewayProxy = await gatewayProxyFactory.deploy(gatewayImplementation.address, params).then((d) => d.deployed()); | ||
await auth.transferOwnership(gatewayProxy.address).then((tx) => tx.wait()); | ||
gateway = await gatewayImplementationFactory.attach(gatewayProxy.address); | ||
token = await tokenFactory.deploy(tokenName, tokenSymbol, decimals, capacity).then((d) => d.deployed()); | ||
wrongToken = await tokenFactory.deploy(wrongTokenName, wrongTokenSymbol, decimals, capacity).then((d) => d.deployed()); | ||
await token.deposit({ value: 1e9 }).then((tx) => tx.wait()); | ||
await wrongToken.deposit({ value: 1e9 }).then((tx) => tx.wait()); | ||
await gateway | ||
.execute( | ||
await getSignedWeightedExecuteInput( | ||
arrayify( | ||
defaultAbiCoder.encode( | ||
['uint256', 'bytes32[]', 'string[]', 'bytes[]'], | ||
[ | ||
await getChainId(), | ||
[getRandomID()], | ||
['deployToken'], | ||
[ | ||
defaultAbiCoder.encode( | ||
['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], | ||
[tokenName, tokenSymbol, decimals, capacity, token.address, 0], | ||
), | ||
], | ||
], | ||
), | ||
), | ||
[operatorWallet], | ||
[1], | ||
1, | ||
[operatorWallet], | ||
), | ||
), | ||
[operatorWallet], | ||
[1], | ||
1, | ||
[operatorWallet], | ||
), | ||
); | ||
getGasOptions(), | ||
) | ||
.then((tx) => tx.wait()); | ||
depositService = await deployUpgradable(constAddressDeployer.address, ownerWallet, DepositService, DepositServiceProxy, [ | ||
gateway.address, | ||
tokenSymbol, | ||
ownerWallet.address, | ||
]); | ||
const depositServiceFactory = await ethers.getContractFactory('AxelarDepositService', ownerWallet); | ||
const implementation = await depositServiceFactory.deploy(gateway.address, tokenSymbol, ownerWallet.address); | ||
await implementation.deployTransaction.wait(network.config.confirmations); | ||
receiverImplementation = new Contract(await depositService.receiverImplementation(), ReceiverImplementation.abi, ownerWallet); | ||
}); | ||
const depositServiceProxyFactory = await ethers.getContractFactory('AxelarDepositServiceProxy', ownerWallet); | ||
depositService = await depositServiceProxyFactory.deploy(); | ||
await depositService.deployTransaction.wait(network.config.confirmations); | ||
describe('deposit service', () => { | ||
await depositService.init(implementation.address, ownerWallet.address, '0x').then((tx) => tx.wait()); | ||
depositService = depositServiceFactory.attach(depositService.address); | ||
receiverImplementation = receiverImplementationFactory.attach(await depositService.receiverImplementation()); | ||
}); | ||
it('should send native token', async () => { | ||
const destinationAddress = userWallet.address.toString(); | ||
const amount = 1e6; | ||
const amount = 1e3; | ||
@@ -133,3 +151,3 @@ const tx = await depositService.sendNative(destinationChain, destinationAddress, { value: amount }); | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const amount = 1e3; | ||
@@ -157,3 +175,3 @@ const expectedDepositAddress = getDepositAddress( | ||
await token.transfer(depositAddress, amount); | ||
await token.transfer(depositAddress, amount).then((tx) => tx.wait()); | ||
@@ -172,3 +190,3 @@ const tx = await depositService.sendTokenDeposit(salt, refundAddress, destinationChain, destinationAddress, tokenSymbol); | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const amount = 1e3; | ||
@@ -183,4 +201,4 @@ const depositAddress = await depositService.addressForTokenDeposit( | ||
await token.transfer(depositAddress, amount); | ||
await wrongToken.transfer(depositAddress, amount * 2); | ||
await token.transfer(depositAddress, amount).then((tx) => tx.wait()); | ||
await wrongToken.transfer(depositAddress, amount * 2).then((tx) => tx.wait()); | ||
@@ -199,6 +217,8 @@ await expect( | ||
await ownerWallet.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}); | ||
await ownerWallet | ||
.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}) | ||
.then((tx) => tx.wait()); | ||
@@ -219,3 +239,3 @@ await expect( | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const amount = 1e3; | ||
@@ -236,6 +256,8 @@ const expectedDepositAddress = getDepositAddress( | ||
await ownerWallet.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}); | ||
await ownerWallet | ||
.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}) | ||
.then((tx) => tx.wait()); | ||
@@ -255,11 +277,13 @@ const tx = await depositService.sendNativeDeposit(salt, refundAddress, destinationChain, destinationAddress); | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const amount = 1e3; | ||
const depositAddress = await depositService.addressForNativeDeposit(salt, refundAddress, destinationChain, destinationAddress); | ||
await ownerWallet.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}); | ||
await wrongToken.transfer(depositAddress, amount * 2); | ||
await ownerWallet | ||
.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}) | ||
.then((tx) => tx.wait()); | ||
await wrongToken.transfer(depositAddress, amount * 2).then((tx) => tx.wait()); | ||
@@ -277,3 +301,3 @@ await expect( | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const amount = 1e3; | ||
@@ -290,3 +314,3 @@ const expectedDepositAddress = getDepositAddress( | ||
await token.transfer(depositAddress, amount); | ||
await token.transfer(depositAddress, amount).then((tx) => tx.wait()); | ||
@@ -304,8 +328,8 @@ const tx = await depositService.nativeUnwrap(salt, refundAddress, recipient); | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const amount = 1e3; | ||
const depositAddress = await depositService.addressForNativeUnwrap(salt, refundAddress, recipient); | ||
await token.transfer(depositAddress, amount); | ||
await wrongToken.transfer(depositAddress, amount * 2); | ||
await token.transfer(depositAddress, amount).then((tx) => tx.wait()); | ||
await wrongToken.transfer(depositAddress, amount * 2).then((tx) => tx.wait()); | ||
@@ -321,6 +345,8 @@ await expect( | ||
await ownerWallet.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}); | ||
await ownerWallet | ||
.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}) | ||
.then((tx) => tx.wait()); | ||
@@ -334,11 +360,11 @@ await expect(await depositService.refundNativeUnwrap(salt, refundAddress, recipient, [wrongToken.address])) | ||
it('should refund to the service when refundAddress is 0x0', async () => { | ||
const refundAddress = ADDRESS_ZERO; | ||
const refundAddress = ethers.constants.AddressZero; | ||
const recipient = userWallet.address; | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const amount = 1e3; | ||
const depositAddress = await depositService.addressForNativeUnwrap(salt, refundAddress, recipient); | ||
await token.transfer(depositAddress, amount); | ||
await wrongToken.transfer(depositAddress, amount * 2); | ||
await token.transfer(depositAddress, amount).then((tx) => tx.wait()); | ||
await wrongToken.transfer(depositAddress, amount * 2).then((tx) => tx.wait()); | ||
@@ -349,6 +375,8 @@ await expect( | ||
await ownerWallet.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}); | ||
await ownerWallet | ||
.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}) | ||
.then((tx) => tx.wait()); | ||
@@ -366,9 +394,35 @@ await expect(await depositService.refundNativeUnwrap(salt, refundAddress, recipient, [wrongToken.address])) | ||
await expect(depositService.connect(userWallet).refundLockedAsset(recipient, ADDRESS_ZERO, amount)).to.be.reverted; | ||
await expect(depositService.connect(userWallet).refundLockedAsset(recipient, ethers.constants.AddressZero, amount)).to.be | ||
.reverted; | ||
await expect( | ||
await depositService.connect(ownerWallet).refundLockedAsset(recipient, ADDRESS_ZERO, amount), | ||
await depositService.connect(ownerWallet).refundLockedAsset(recipient, ethers.constants.AddressZero, amount), | ||
).to.changeEtherBalance(userWallet, amount); | ||
}); | ||
}); | ||
describe('should preserve the bytecode [ @skip-on-coverage ]', () => { | ||
it('should have the same receiver bytecode preserved for each EVM', async () => { | ||
const expected = { | ||
istanbul: '0xc0fd88839756e97f51ab0395ce8e6164a5f924bd73a3342204340a14ad306fe1', | ||
berlin: '0xc0fd88839756e97f51ab0395ce8e6164a5f924bd73a3342204340a14ad306fe1', | ||
london: '0xc0fd88839756e97f51ab0395ce8e6164a5f924bd73a3342204340a14ad306fe1', | ||
}[getEVMVersion()]; | ||
expect(keccak256(DepositReceiver.bytecode)).to.be.equal(expected); | ||
}); | ||
it('should have the same proxy bytecode preserved for each EVM', async () => { | ||
const proxyBytecode = DepositServiceProxy.bytecode; | ||
const proxyBytecodeHash = keccak256(proxyBytecode); | ||
const expected = { | ||
istanbul: '0x1eaf54a0dcc8ed839ba94f1ab33a4c9f63f6bf73959eb0cdd61627e699972aef', | ||
berlin: '0x1d1dc288313dec7af9b83310f782bd9f24ab02030e6c7f67f6f510ee07a6d75b', | ||
london: '0xdec34d6bd2779b58de66dc79f2d80353e8cebb178d9afac4225bc3f652360aaa', | ||
}[getEVMVersion()]; | ||
expect(proxyBytecodeHash).to.be.equal(expected); | ||
}); | ||
}); | ||
}); |
'use strict'; | ||
const chai = require('chai'); | ||
const { ethers, network, config } = require('hardhat'); | ||
const { | ||
utils: { defaultAbiCoder, keccak256, parseEther }, | ||
} = require('ethers'); | ||
const { deployContract, MockProvider, solidity } = require('ethereum-waffle'); | ||
chai.use(solidity); | ||
utils: { defaultAbiCoder, keccak256, parseUnits, id }, | ||
constants: { AddressZero, HashZero }, | ||
} = ethers; | ||
const { expect } = chai; | ||
const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000'; | ||
const MintableCappedERC20 = require('../../artifacts/contracts/MintableCappedERC20.sol/MintableCappedERC20.json'); | ||
const EVM_VERSION = config.solidity.compilers[0].settings.evmVersion; | ||
const GasService = require('../../artifacts/contracts/gas-service/AxelarGasService.sol/AxelarGasService.json'); | ||
const GasServiceProxy = require('../../artifacts/contracts/gas-service/AxelarGasServiceProxy.sol/AxelarGasServiceProxy.json'); | ||
const ConstAddressDeployer = require('axelar-utils-solidity/dist/ConstAddressDeployer.json'); | ||
const { deployUpgradable, upgradeUpgradable } = require('../../scripts/upgradable'); | ||
const { upgradeUpgradable } = require('@axelar-network/axelar-gmp-sdk-solidity'); | ||
describe('AxelarGasService', () => { | ||
const [ownerWallet, userWallet] = new MockProvider().getWallets(); | ||
let testTokenFactory; | ||
@@ -26,7 +23,25 @@ let gasService; | ||
beforeEach(async () => { | ||
const constAddressDeployer = await deployContract(ownerWallet, ConstAddressDeployer); | ||
let ownerWallet; | ||
let userWallet; | ||
gasService = await deployUpgradable(constAddressDeployer.address, ownerWallet, GasService, GasServiceProxy, [ownerWallet.address]); | ||
const nativeGasFeeAmount = parseUnits('1000', 'wei'); | ||
before(async () => { | ||
[ownerWallet, userWallet] = await ethers.getSigners(); | ||
testTokenFactory = await ethers.getContractFactory('MintableCappedERC20', ownerWallet); | ||
}); | ||
before(async () => { | ||
const gasServiceFactory = await ethers.getContractFactory('AxelarGasService', ownerWallet); | ||
const implementation = await gasServiceFactory.deploy(ownerWallet.address); | ||
await implementation.deployTransaction.wait(network.config.confirmations); | ||
const gasServiceProxyFactory = await ethers.getContractFactory('AxelarGasServiceProxy', ownerWallet); | ||
gasService = await gasServiceProxyFactory.deploy(); | ||
await gasService.deployTransaction.wait(network.config.confirmations); | ||
await gasService.init(implementation.address, ownerWallet.address, '0x').then((tx) => tx.wait()); | ||
gasService = gasServiceFactory.attach(gasService.address); | ||
const name = 'testToken'; | ||
@@ -37,5 +52,6 @@ const symbol = 'testToken'; | ||
testToken = await deployContract(ownerWallet, MintableCappedERC20, [name, symbol, decimals, capacity]); | ||
testToken = await testTokenFactory.deploy(name, symbol, decimals, capacity); | ||
await testToken.deployTransaction.wait(network.config.confirmations); | ||
await testToken.mint(userWallet.address, 1e9); | ||
await testToken.mint(userWallet.address, 1e9).then((tx) => tx.wait()); | ||
}); | ||
@@ -53,5 +69,7 @@ | ||
const gasFeeAmount = 1000; | ||
const nativeGasFeeAmount = parseEther('1.0'); | ||
await testToken.connect(userWallet).approve(gasService.address, 1e6); | ||
await testToken | ||
.connect(userWallet) | ||
.approve(gasService.address, 1e6) | ||
.then((tx) => tx.wait()); | ||
@@ -143,4 +161,108 @@ await expect( | ||
.and.to.changeEtherBalance(gasService, nativeGasFeeAmount); | ||
await expect( | ||
gasService | ||
.connect(userWallet) | ||
.payGasForExpressCallWithToken( | ||
userWallet.address, | ||
destinationChain, | ||
destinationAddress, | ||
payload, | ||
symbol, | ||
amount, | ||
gasToken, | ||
gasFeeAmount, | ||
userWallet.address, | ||
), | ||
) | ||
.to.emit(gasService, 'GasPaidForExpressCallWithToken') | ||
.withArgs( | ||
userWallet.address, | ||
destinationChain, | ||
destinationAddress, | ||
payloadHash, | ||
symbol, | ||
amount, | ||
gasToken, | ||
gasFeeAmount, | ||
userWallet.address, | ||
) | ||
.and.to.emit(testToken, 'Transfer') | ||
.withArgs(userWallet.address, gasService.address, gasFeeAmount); | ||
await expect( | ||
await gasService | ||
.connect(userWallet) | ||
.payNativeGasForExpressCallWithToken( | ||
userWallet.address, | ||
destinationChain, | ||
destinationAddress, | ||
payload, | ||
symbol, | ||
amount, | ||
userWallet.address, | ||
{ value: nativeGasFeeAmount }, | ||
), | ||
) | ||
.to.emit(gasService, 'NativeGasPaidForExpressCallWithToken') | ||
.withArgs( | ||
userWallet.address, | ||
destinationChain, | ||
destinationAddress, | ||
payloadHash, | ||
symbol, | ||
amount, | ||
nativeGasFeeAmount, | ||
userWallet.address, | ||
) | ||
.and.to.changeEtherBalance(gasService, nativeGasFeeAmount); | ||
}); | ||
it('should revert when no ether is sent with native gas payment calls', async () => { | ||
const destinationChain = 'ethereum'; | ||
const destinationAddress = ownerWallet.address; | ||
const payload = defaultAbiCoder.encode(['address', 'address'], [ownerWallet.address, userWallet.address]); | ||
const symbol = 'USDC'; | ||
const amount = 100000; | ||
await testToken | ||
.connect(userWallet) | ||
.approve(gasService.address, 1e6) | ||
.then((tx) => tx.wait()); | ||
await expect( | ||
gasService | ||
.connect(userWallet) | ||
.payNativeGasForContractCall(userWallet.address, destinationChain, destinationAddress, payload, userWallet.address), | ||
).to.be.revertedWithCustomError(gasService, 'NothingReceived'); | ||
await expect( | ||
gasService | ||
.connect(userWallet) | ||
.payNativeGasForContractCallWithToken( | ||
userWallet.address, | ||
destinationChain, | ||
destinationAddress, | ||
payload, | ||
symbol, | ||
amount, | ||
userWallet.address, | ||
), | ||
).to.be.revertedWithCustomError(gasService, 'NothingReceived'); | ||
await expect( | ||
gasService | ||
.connect(userWallet) | ||
.payNativeGasForExpressCallWithToken( | ||
userWallet.address, | ||
destinationChain, | ||
destinationAddress, | ||
payload, | ||
symbol, | ||
amount, | ||
userWallet.address, | ||
), | ||
).to.be.revertedWithCustomError(gasService, 'NothingReceived'); | ||
}); | ||
it('should allow to collect accumulated payments and refund', async () => { | ||
@@ -154,5 +276,7 @@ const destinationChain = 'ethereum'; | ||
const gasFeeAmount = 1000; | ||
const nativeGasFeeAmount = parseEther('1.0'); | ||
await testToken.connect(userWallet).approve(gasService.address, 1e6); | ||
await testToken | ||
.connect(userWallet) | ||
.approve(gasService.address, 1e6) | ||
.then((tx) => tx.wait()); | ||
@@ -169,3 +293,4 @@ await gasService | ||
userWallet.address, | ||
); | ||
) | ||
.then((tx) => tx.wait()); | ||
@@ -184,3 +309,4 @@ await gasService | ||
userWallet.address, | ||
); | ||
) | ||
.then((tx) => tx.wait()); | ||
@@ -191,3 +317,4 @@ await gasService | ||
value: nativeGasFeeAmount, | ||
}); | ||
}) | ||
.then((tx) => tx.wait()); | ||
@@ -198,15 +325,35 @@ await gasService | ||
value: nativeGasFeeAmount, | ||
}); | ||
}) | ||
.then((tx) => tx.wait()); | ||
await expect(gasService.connect(userWallet).refund(userWallet.address, ADDRESS_ZERO, nativeGasFeeAmount)).to.be.reverted; | ||
await expect( | ||
gasService | ||
.connect(userWallet) | ||
.functions['refund(address,address,uint256)'](userWallet.address, AddressZero, nativeGasFeeAmount), | ||
).to.be.reverted; | ||
await expect( | ||
await gasService.connect(ownerWallet).refund(userWallet.address, ADDRESS_ZERO, nativeGasFeeAmount), | ||
).to.changeEtherBalance(userWallet, nativeGasFeeAmount); | ||
gasService | ||
.connect(ownerWallet) | ||
.functions['refund(address,address,uint256)'](userWallet.address, AddressZero, nativeGasFeeAmount), | ||
) | ||
.to.changeEtherBalance(userWallet, nativeGasFeeAmount) | ||
.and.to.emit(gasService, 'Refunded') | ||
.withArgs(HashZero, 0, userWallet.address, AddressZero, nativeGasFeeAmount); | ||
await expect(gasService.connect(userWallet).refund(userWallet.address, testToken.address, gasFeeAmount)).to.be.reverted; | ||
await expect( | ||
gasService | ||
.connect(userWallet) | ||
.functions['refund(address,address,uint256)'](userWallet.address, testToken.address, gasFeeAmount), | ||
).to.be.reverted; | ||
await expect(await gasService.connect(ownerWallet).refund(userWallet.address, testToken.address, gasFeeAmount)) | ||
await expect( | ||
gasService | ||
.connect(ownerWallet) | ||
.functions['refund(address,address,uint256)'](userWallet.address, testToken.address, gasFeeAmount), | ||
) | ||
.and.to.emit(testToken, 'Transfer') | ||
.withArgs(gasService.address, userWallet.address, gasFeeAmount); | ||
.withArgs(gasService.address, userWallet.address, gasFeeAmount) | ||
.and.to.emit(gasService, 'Refunded') | ||
.withArgs(HashZero, 0, userWallet.address, testToken.address, gasFeeAmount); | ||
@@ -216,9 +363,9 @@ await expect( | ||
.connect(userWallet) | ||
.collectFees(ownerWallet.address, [ADDRESS_ZERO, testToken.address], [nativeGasFeeAmount, gasFeeAmount]), | ||
.collectFees(ownerWallet.address, [AddressZero, testToken.address], [nativeGasFeeAmount, gasFeeAmount]), | ||
).to.be.reverted; | ||
await expect( | ||
await gasService | ||
gasService | ||
.connect(ownerWallet) | ||
.collectFees(ownerWallet.address, [ADDRESS_ZERO, testToken.address], [nativeGasFeeAmount, gasFeeAmount]), | ||
.collectFees(ownerWallet.address, [AddressZero, testToken.address], [nativeGasFeeAmount, gasFeeAmount]), | ||
) | ||
@@ -230,5 +377,135 @@ .to.changeEtherBalance(ownerWallet, nativeGasFeeAmount) | ||
it('should allow to collect accumulated payments and refund with the new method', async () => { | ||
const destinationChain = 'ethereum'; | ||
const destinationAddress = ownerWallet.address; | ||
const payload = defaultAbiCoder.encode(['address', 'address'], [ownerWallet.address, userWallet.address]); | ||
const symbol = 'USDC'; | ||
const amount = 100000; | ||
const gasToken = testToken.address; | ||
const gasFeeAmount = 1000; | ||
await testToken | ||
.connect(userWallet) | ||
.approve(gasService.address, 1e6) | ||
.then((tx) => tx.wait()); | ||
await gasService | ||
.connect(userWallet) | ||
.payGasForContractCall( | ||
userWallet.address, | ||
destinationChain, | ||
destinationAddress, | ||
payload, | ||
gasToken, | ||
gasFeeAmount, | ||
userWallet.address, | ||
) | ||
.then((tx) => tx.wait()); | ||
await gasService | ||
.connect(userWallet) | ||
.payGasForContractCallWithToken( | ||
userWallet.address, | ||
destinationChain, | ||
destinationAddress, | ||
payload, | ||
symbol, | ||
amount, | ||
gasToken, | ||
gasFeeAmount, | ||
userWallet.address, | ||
) | ||
.then((tx) => tx.wait()); | ||
await gasService | ||
.connect(userWallet) | ||
.payNativeGasForContractCall(userWallet.address, destinationChain, destinationAddress, payload, userWallet.address, { | ||
value: nativeGasFeeAmount, | ||
}) | ||
.then((tx) => tx.wait()); | ||
await gasService | ||
.connect(userWallet) | ||
.payNativeGasForContractCall(userWallet.address, destinationChain, destinationAddress, payload, userWallet.address, { | ||
value: nativeGasFeeAmount, | ||
}) | ||
.then((tx) => tx.wait()); | ||
const txHash = id('txHash'); | ||
const logIndex = 256; | ||
await expect( | ||
gasService | ||
.connect(userWallet) | ||
.functions['refund(bytes32,uint256,address,address,uint256)']( | ||
txHash, | ||
logIndex, | ||
userWallet.address, | ||
AddressZero, | ||
nativeGasFeeAmount, | ||
), | ||
).to.be.reverted; | ||
await expect( | ||
gasService | ||
.connect(ownerWallet) | ||
.functions['refund(bytes32,uint256,address,address,uint256)']( | ||
txHash, | ||
logIndex, | ||
userWallet.address, | ||
AddressZero, | ||
nativeGasFeeAmount, | ||
), | ||
) | ||
.to.changeEtherBalance(userWallet, nativeGasFeeAmount) | ||
.and.to.emit(gasService, 'Refunded') | ||
.withArgs(txHash, logIndex, userWallet.address, AddressZero, nativeGasFeeAmount); | ||
await expect( | ||
gasService | ||
.connect(userWallet) | ||
.functions['refund(bytes32,uint256,address,address,uint256)']( | ||
txHash, | ||
logIndex, | ||
userWallet.address, | ||
testToken.address, | ||
gasFeeAmount, | ||
), | ||
).to.be.reverted; | ||
await expect( | ||
gasService | ||
.connect(ownerWallet) | ||
.functions['refund(bytes32,uint256,address,address,uint256)']( | ||
txHash, | ||
logIndex, | ||
userWallet.address, | ||
testToken.address, | ||
gasFeeAmount, | ||
), | ||
) | ||
.to.emit(testToken, 'Transfer') | ||
.withArgs(gasService.address, userWallet.address, gasFeeAmount) | ||
.and.to.emit(gasService, 'Refunded') | ||
.withArgs(txHash, logIndex, userWallet.address, testToken.address, gasFeeAmount); | ||
await expect( | ||
gasService | ||
.connect(userWallet) | ||
.collectFees(ownerWallet.address, [AddressZero, testToken.address], [nativeGasFeeAmount, gasFeeAmount]), | ||
).to.be.reverted; | ||
await expect( | ||
gasService | ||
.connect(ownerWallet) | ||
.collectFees(ownerWallet.address, [AddressZero, testToken.address], [nativeGasFeeAmount, gasFeeAmount]), | ||
) | ||
.to.changeEtherBalance(ownerWallet, nativeGasFeeAmount) | ||
.and.to.emit(testToken, 'Transfer') | ||
.withArgs(gasService.address, ownerWallet.address, gasFeeAmount); | ||
}); | ||
it('should upgrade the gas receiver implementation', async () => { | ||
const prevImpl = await gasService.implementation(); | ||
await expect(upgradeUpgradable(ownerWallet, gasService.address, GasService, [ownerWallet.address])).to.emit( | ||
await expect(upgradeUpgradable(gasService.address, ownerWallet, GasService, [ownerWallet.address])).to.emit( | ||
gasService, | ||
@@ -246,3 +523,3 @@ 'Upgraded', | ||
await expect(await gasService.owner()).to.be.equal(userWallet.address); | ||
expect(await gasService.owner()).to.be.equal(userWallet.address); | ||
}); | ||
@@ -255,5 +532,7 @@ | ||
const gasFeeAmount = 1000; | ||
const nativeGasFeeAmount = parseEther('1.0'); | ||
await testToken.connect(userWallet).approve(gasService.address, 1e6); | ||
await testToken | ||
.connect(userWallet) | ||
.approve(gasService.address, 1e6) | ||
.then((tx) => tx.wait()); | ||
@@ -273,3 +552,56 @@ await expect(gasService.connect(userWallet).addGas(txHash, logIndex, gasToken, gasFeeAmount, userWallet.address)) | ||
}); | ||
it('should emit events when gas is added for express calls', async () => { | ||
const txHash = keccak256(defaultAbiCoder.encode(['string'], ['random tx hash'])); | ||
const logIndex = 13; | ||
const gasToken = testToken.address; | ||
const gasFeeAmount = 1000; | ||
await testToken | ||
.connect(userWallet) | ||
.approve(gasService.address, 1e6) | ||
.then((tx) => tx.wait()); | ||
await expect(gasService.connect(userWallet).addExpressGas(txHash, logIndex, gasToken, gasFeeAmount, userWallet.address)) | ||
.to.emit(gasService, 'ExpressGasAdded') | ||
.withArgs(txHash, logIndex, gasToken, gasFeeAmount, userWallet.address) | ||
.and.to.emit(testToken, 'Transfer') | ||
.withArgs(userWallet.address, gasService.address, gasFeeAmount); | ||
await expect( | ||
await gasService | ||
.connect(userWallet) | ||
.addNativeExpressGas(txHash, logIndex, userWallet.address, { value: nativeGasFeeAmount }), | ||
) | ||
.to.emit(gasService, 'NativeExpressGasAdded') | ||
.withArgs(txHash, logIndex, nativeGasFeeAmount, userWallet.address) | ||
.and.to.changeEtherBalance(gasService, nativeGasFeeAmount); | ||
}); | ||
it('should revert if no ether is sent with add native gas calls both normal and express', async () => { | ||
const txHash = keccak256(defaultAbiCoder.encode(['string'], ['random tx hash'])); | ||
const logIndex = 13; | ||
await expect(gasService.connect(userWallet).addNativeGas(txHash, logIndex, userWallet.address)).to.be.revertedWithCustomError( | ||
gasService, | ||
'NothingReceived', | ||
); | ||
await expect( | ||
gasService.connect(userWallet).addNativeExpressGas(txHash, logIndex, userWallet.address), | ||
).to.be.revertedWithCustomError(gasService, 'NothingReceived'); | ||
}); | ||
it('should preserve the bytecode [ @skip-on-coverage ]', async () => { | ||
const proxyBytecode = GasServiceProxy.bytecode; | ||
const proxyBytecodeHash = keccak256(proxyBytecode); | ||
const expected = { | ||
istanbul: '0x885390e8cdbd59403e862821e2cde97b65b8e0ff145ef131b7d1bb7b49ae575c', | ||
berlin: '0x102a9449688476eff53daa30db95211709f2b78555415593d9bf4a2deb2ee92c', | ||
london: '0x844ca3b3e4439c8473ba73c11d5c9b9bb69b6b528f8485a794797094724a4dbf', | ||
}[EVM_VERSION]; | ||
expect(proxyBytecodeHash).to.be.equal(expected); | ||
}); | ||
}); | ||
}); |
'use strict'; | ||
const chai = require('chai'); | ||
const { ethers } = require('hardhat'); | ||
const { | ||
Contract, | ||
utils: { defaultAbiCoder, arrayify, keccak256 }, | ||
} = require('ethers'); | ||
const { deployContract, MockProvider, solidity } = require('ethereum-waffle'); | ||
chai.use(solidity); | ||
} = ethers; | ||
const { expect } = chai; | ||
const { get } = require('lodash/fp'); | ||
const { deployUpgradable } = require('../../scripts/upgradable'); | ||
const { deployUpgradable } = require('@axelar-network/axelar-gmp-sdk-solidity'); | ||
const ConstAddressDeployer = require('@axelar-network/axelar-gmp-sdk-solidity/dist/ConstAddressDeployer.json'); | ||
const CHAIN_ID = 1; | ||
const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000'; | ||
const Auth = require('../../artifacts/contracts/auth/AxelarAuthWeighted.sol/AxelarAuthWeighted.json'); | ||
const TokenDeployer = require('../../artifacts/contracts/TokenDeployer.sol/TokenDeployer.json'); | ||
const AxelarGatewayProxy = require('../../artifacts/contracts/AxelarGatewayProxy.sol/AxelarGatewayProxy.json'); | ||
const AxelarGateway = require('../../artifacts/contracts/AxelarGateway.sol/AxelarGateway.json'); | ||
const MintableCappedERC20 = require('../../artifacts/contracts/MintableCappedERC20.sol/MintableCappedERC20.json'); | ||
const GasService = require('../../artifacts/contracts/gas-service/AxelarGasService.sol/AxelarGasService.json'); | ||
const GasServiceProxy = require('../../artifacts/contracts/gas-service/AxelarGasServiceProxy.sol/AxelarGasServiceProxy.json'); | ||
const SourceChainSwapCaller = require('../../artifacts/contracts/test/gmp/SourceChainSwapCaller.sol/SourceChainSwapCaller.json'); | ||
const DestinationChainSwapExecutable = require('../../artifacts/contracts/test/gmp/DestinationChainSwapExecutable.sol/DestinationChainSwapExecutable.json'); | ||
const DestinationChainSwapForecallable = require('../../artifacts/contracts/test/gmp/DestinationChainSwapForecallable.sol/DestinationChainSwapForecallable.json'); | ||
const DestinationChainTokenSwapper = require('../../artifacts/contracts/test/gmp/DestinationChainTokenSwapper.sol/DestinationChainTokenSwapper.json'); | ||
const ConstAddressDeployer = require('axelar-utils-solidity/dist/ConstAddressDeployer.json'); | ||
const { getWeightedAuthDeployParam, getSignedWeightedExecuteInput, getRandomID } = require('../utils'); | ||
const { | ||
getWeightedAuthDeployParam, | ||
getSignedWeightedExecuteInput, | ||
getRandomID, | ||
getAddresses, | ||
getChainId, | ||
getWeightedProxyDeployParams, | ||
} = require('../utils'); | ||
describe('GeneralMessagePassing', () => { | ||
const [ownerWallet, operatorWallet, userWallet, adminWallet1, adminWallet2, adminWallet3, adminWallet4, adminWallet5, adminWallet6] = | ||
new MockProvider().getWallets(); | ||
const adminWallets = [adminWallet1, adminWallet2, adminWallet3, adminWallet4, adminWallet5, adminWallet6]; | ||
const threshold = 3; | ||
let ownerWallet; | ||
let operatorWallet; | ||
let userWallet; | ||
@@ -43,3 +34,2 @@ let sourceChainGateway; | ||
let destinationChainSwapExecutable; | ||
let destinationChainSwapForecallable; | ||
let destinationChainTokenSwapper; | ||
@@ -49,2 +39,15 @@ let tokenA; | ||
let gatewayFactory; | ||
let authFactory; | ||
let tokenDeployerFactory; | ||
let gatewayProxyFactory; | ||
let mintableCappedERC20Factory; | ||
let sourceChainSwapCallerFactory; | ||
let destinationChainSwapExecutableFactory; | ||
let destinationChainTokenSwapperFactory; | ||
let auth; | ||
let tokenDeployer; | ||
let gateway; | ||
const sourceChain = 'chainA'; | ||
@@ -59,3 +62,3 @@ const destinationChain = 'chainB'; | ||
const getMintData = (symbol, address, amount) => | ||
const getMintData = async (symbol, address, amount) => | ||
arrayify( | ||
@@ -65,3 +68,3 @@ defaultAbiCoder.encode( | ||
[ | ||
CHAIN_ID, | ||
await getChainId(), | ||
[getRandomID()], | ||
@@ -74,16 +77,37 @@ ['mintToken'], | ||
before(async () => { | ||
[ownerWallet, operatorWallet, userWallet] = await ethers.getSigners(); | ||
gatewayFactory = await ethers.getContractFactory('AxelarGateway', ownerWallet); | ||
authFactory = await ethers.getContractFactory('AxelarAuthWeighted', ownerWallet); | ||
tokenDeployerFactory = await ethers.getContractFactory('TokenDeployer', ownerWallet); | ||
gatewayProxyFactory = await ethers.getContractFactory('AxelarGatewayProxy', ownerWallet); | ||
mintableCappedERC20Factory = await ethers.getContractFactory('MintableCappedERC20', ownerWallet); | ||
sourceChainSwapCallerFactory = await ethers.getContractFactory('SourceChainSwapCaller', ownerWallet); | ||
destinationChainSwapExecutableFactory = await ethers.getContractFactory('DestinationChainSwapExecutable', ownerWallet); | ||
destinationChainTokenSwapperFactory = await ethers.getContractFactory('DestinationChainTokenSwapper', ownerWallet); | ||
}); | ||
beforeEach(async () => { | ||
const deployGateway = async () => { | ||
const params = arrayify( | ||
defaultAbiCoder.encode(['address[]', 'uint8', 'bytes'], [adminWallets.map(get('address')), threshold, '0x']), | ||
); | ||
const auth = await deployContract(ownerWallet, Auth, [getWeightedAuthDeployParam([[operatorWallet.address]], [[1]], [1])]); | ||
const tokenDeployer = await deployContract(ownerWallet, TokenDeployer); | ||
const gateway = await deployContract(ownerWallet, AxelarGateway, [auth.address, tokenDeployer.address]); | ||
const proxy = await deployContract(ownerWallet, AxelarGatewayProxy, [gateway.address, params]); | ||
await auth.transferOwnership(proxy.address); | ||
return new Contract(proxy.address, AxelarGateway.abi, ownerWallet); | ||
const operatorAddresses = getAddresses([operatorWallet]); | ||
auth = await authFactory.deploy(getWeightedAuthDeployParam([operatorAddresses], [[1]], [1])).then((d) => d.deployed()); | ||
tokenDeployer = await tokenDeployerFactory.deploy().then((d) => d.deployed()); | ||
const gatewayImplementation = await gatewayFactory.deploy(auth.address, tokenDeployer.address).then((d) => d.deployed()); | ||
const params = getWeightedProxyDeployParams(ownerWallet.address, ownerWallet.address, [], [], 1); | ||
const proxy = await gatewayProxyFactory.deploy(gatewayImplementation.address, params).then((d) => d.deployed()); | ||
await auth.transferOwnership(proxy.address).then((tx) => tx.wait()); | ||
gateway = gatewayFactory.attach(proxy.address); | ||
return gateway; | ||
}; | ||
const getTokenDeployData = (withAddress) => | ||
const getTokenDeployData = async (withAddress) => | ||
arrayify( | ||
@@ -93,3 +117,3 @@ defaultAbiCoder.encode( | ||
[ | ||
CHAIN_ID, | ||
await getChainId(), | ||
[getRandomID(), getRandomID()], | ||
@@ -100,7 +124,7 @@ ['deployToken', 'deployToken'], | ||
['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], | ||
[nameA, symbolA, decimals, capacity, withAddress ? tokenA.address : ADDRESS_ZERO, 0], | ||
[nameA, symbolA, decimals, capacity, withAddress ? tokenA.address : ethers.constants.AddressZero, 0], | ||
), | ||
defaultAbiCoder.encode( | ||
['string', 'string', 'uint8', 'uint256', 'address', 'uint256'], | ||
[nameB, symbolB, decimals, capacity, withAddress ? tokenB.address : ADDRESS_ZERO, 0], | ||
[nameB, symbolB, decimals, capacity, withAddress ? tokenB.address : ethers.constants.AddressZero, 0], | ||
), | ||
@@ -114,3 +138,8 @@ ], | ||
destinationChainGateway = await deployGateway(); | ||
const constAddressDeployer = await deployContract(ownerWallet, ConstAddressDeployer); | ||
const constAddressDeployerFactory = await ethers.getContractFactory( | ||
ConstAddressDeployer.abi, | ||
ConstAddressDeployer.bytecode, | ||
ownerWallet, | ||
); | ||
const constAddressDeployer = await constAddressDeployerFactory.deploy().then((d) => d.deployed()); | ||
@@ -120,32 +149,23 @@ sourceChainGasService = await deployUpgradable(constAddressDeployer.address, ownerWallet, GasService, GasServiceProxy, [ | ||
]); | ||
tokenA = await deployContract(ownerWallet, MintableCappedERC20, [nameA, symbolA, decimals, capacity]); | ||
tokenB = await deployContract(ownerWallet, MintableCappedERC20, [nameB, symbolB, decimals, capacity]); | ||
tokenA = await mintableCappedERC20Factory.deploy(nameA, symbolA, decimals, capacity).then((d) => d.deployed()); | ||
tokenB = await mintableCappedERC20Factory.deploy(nameB, symbolB, decimals, capacity).then((d) => d.deployed()); | ||
await sourceChainGateway.execute( | ||
await getSignedWeightedExecuteInput(getTokenDeployData(false), [operatorWallet], [1], 1, [operatorWallet]), | ||
await getSignedWeightedExecuteInput(await getTokenDeployData(false), [operatorWallet], [1], 1, [operatorWallet]), | ||
); | ||
await destinationChainGateway.execute( | ||
await getSignedWeightedExecuteInput(getTokenDeployData(true), [operatorWallet], [1], 1, [operatorWallet]), | ||
await getSignedWeightedExecuteInput(await getTokenDeployData(true), [operatorWallet], [1], 1, [operatorWallet]), | ||
); | ||
destinationChainTokenSwapper = await deployContract(ownerWallet, DestinationChainTokenSwapper, [tokenA.address, tokenB.address]); | ||
destinationChainTokenSwapper = await destinationChainTokenSwapperFactory | ||
.deploy(tokenA.address, tokenB.address) | ||
.then((d) => d.deployed()); | ||
destinationChainSwapExecutable = await destinationChainSwapExecutableFactory | ||
.deploy(destinationChainGateway.address, destinationChainTokenSwapper.address) | ||
.then((d) => d.deployed()); | ||
sourceChainSwapCaller = await sourceChainSwapCallerFactory | ||
.deploy(sourceChainGateway.address, sourceChainGasService.address, destinationChain, destinationChainSwapExecutable.address) | ||
.then((d) => d.deployed()); | ||
destinationChainSwapExecutable = await deployContract(ownerWallet, DestinationChainSwapExecutable, [ | ||
destinationChainGateway.address, | ||
destinationChainTokenSwapper.address, | ||
]); | ||
destinationChainSwapForecallable = await deployContract(ownerWallet, DestinationChainSwapForecallable, [ | ||
destinationChainGateway.address, | ||
destinationChainTokenSwapper.address, | ||
]); | ||
sourceChainSwapCaller = await deployContract(ownerWallet, SourceChainSwapCaller, [ | ||
sourceChainGateway.address, | ||
sourceChainGasService.address, | ||
destinationChain, | ||
destinationChainSwapExecutable.address.toString(), | ||
]); | ||
await tokenA.mint(destinationChainGateway.address, 1e9); | ||
@@ -155,3 +175,5 @@ await tokenB.mint(destinationChainTokenSwapper.address, 1e9); | ||
await sourceChainGateway.execute( | ||
await getSignedWeightedExecuteInput(getMintData(symbolA, userWallet.address, 1e9), [operatorWallet], [1], 1, [operatorWallet]), | ||
await getSignedWeightedExecuteInput(await getMintData(symbolA, userWallet.address, 1e9), [operatorWallet], [1], 1, [ | ||
operatorWallet, | ||
]), | ||
); | ||
@@ -169,3 +191,5 @@ await tokenA.connect(ownerWallet).mint(userWallet.address, 1e9); | ||
const sourceChainTokenA = new Contract(await sourceChainGateway.tokenAddresses(symbolA), MintableCappedERC20.abi, userWallet); | ||
const sourceChainTokenA = mintableCappedERC20Factory | ||
.attach(await sourceChainGateway.tokenAddresses(symbolA)) | ||
.connect(userWallet); | ||
await sourceChainTokenA.approve(sourceChainSwapCaller.address, swapAmount + gasFeeAmount); | ||
@@ -176,5 +200,5 @@ | ||
.connect(userWallet) | ||
.swapToken(symbolA, symbolB, swapAmount, userWallet.address.toString(), gasFeeAmount), | ||
.swapToken(symbolA, symbolB, swapAmount, userWallet.address.toString(), { value: gasFeeAmount }), | ||
) | ||
.to.emit(sourceChainGasService, 'GasPaidForContractCallWithToken') | ||
.to.emit(sourceChainGasService, 'NativeGasPaidForContractCallWithToken') | ||
.withArgs( | ||
@@ -187,3 +211,2 @@ sourceChainSwapCaller.address, | ||
swapAmount, | ||
sourceChainTokenA.address, | ||
gasFeeAmount, | ||
@@ -211,3 +234,3 @@ userWallet.address, | ||
[ | ||
CHAIN_ID, | ||
await getChainId(), | ||
[approveCommandId], | ||
@@ -271,121 +294,3 @@ ['approveContractCallWithMint'], | ||
}); | ||
it('should forecall a swap on remote chain', async () => { | ||
const swapAmount = 1e6; | ||
const gasFeeAmount = 1e3; | ||
const convertedAmount = 2 * swapAmount; | ||
const payload = defaultAbiCoder.encode(['string', 'string'], [symbolB, userWallet.address.toString()]); | ||
const payloadHash = keccak256(payload); | ||
const sourceChainTokenA = new Contract(await sourceChainGateway.tokenAddresses(symbolA), MintableCappedERC20.abi, userWallet); | ||
await sourceChainTokenA.approve(sourceChainSwapCaller.address, swapAmount + gasFeeAmount); | ||
await expect( | ||
sourceChainSwapCaller | ||
.connect(userWallet) | ||
.swapToken(symbolA, symbolB, swapAmount, userWallet.address.toString(), gasFeeAmount), | ||
) | ||
.to.emit(sourceChainGasService, 'GasPaidForContractCallWithToken') | ||
.withArgs( | ||
sourceChainSwapCaller.address, | ||
destinationChain, | ||
destinationChainSwapExecutable.address.toString(), | ||
payloadHash, | ||
symbolA, | ||
swapAmount, | ||
sourceChainTokenA.address, | ||
gasFeeAmount, | ||
userWallet.address, | ||
) | ||
.and.to.emit(sourceChainGateway, 'ContractCallWithToken') | ||
.withArgs( | ||
sourceChainSwapCaller.address.toString(), | ||
destinationChain, | ||
destinationChainSwapExecutable.address.toString(), | ||
payloadHash, | ||
payload, | ||
symbolA, | ||
swapAmount, | ||
); | ||
await tokenA.connect(userWallet).approve(destinationChainSwapForecallable.address, swapAmount); | ||
await expect( | ||
destinationChainSwapForecallable | ||
.connect(userWallet) | ||
.forecallWithToken(sourceChain, sourceChainSwapCaller.address, payload, symbolA, swapAmount, userWallet.address), | ||
) | ||
.to.emit(tokenA, 'Transfer') | ||
.withArgs(userWallet.address, destinationChainSwapForecallable.address, swapAmount) | ||
.and.to.emit(tokenB, 'Transfer') | ||
.withArgs(destinationChainTokenSwapper.address, destinationChainSwapForecallable.address, convertedAmount) | ||
.and.to.emit(tokenB, 'Transfer') | ||
.withArgs(destinationChainSwapForecallable.address, destinationChainGateway.address, convertedAmount) | ||
.and.to.emit(destinationChainGateway, 'TokenSent') | ||
.withArgs(destinationChainSwapForecallable.address, sourceChain, userWallet.address.toString(), symbolB, convertedAmount); | ||
const approveCommandId = getRandomID(); | ||
const sourceTxHash = keccak256('0x123abc123abc'); | ||
const sourceEventIndex = 17; | ||
const approveWithMintData = arrayify( | ||
defaultAbiCoder.encode( | ||
['uint256', 'bytes32[]', 'string[]', 'bytes[]'], | ||
[ | ||
CHAIN_ID, | ||
[approveCommandId], | ||
['approveContractCallWithMint'], | ||
[ | ||
defaultAbiCoder.encode( | ||
['string', 'string', 'address', 'bytes32', 'string', 'uint256', 'bytes32', 'uint256'], | ||
[ | ||
sourceChain, | ||
sourceChainSwapCaller.address.toString(), | ||
destinationChainSwapForecallable.address, | ||
payloadHash, | ||
symbolA, | ||
swapAmount, | ||
sourceTxHash, | ||
sourceEventIndex, | ||
], | ||
), | ||
], | ||
], | ||
), | ||
); | ||
const approveExecute = await destinationChainGateway.execute( | ||
await getSignedWeightedExecuteInput(approveWithMintData, [operatorWallet], [1], 1, [operatorWallet]), | ||
); | ||
await expect(approveExecute) | ||
.to.emit(destinationChainGateway, 'ContractCallApprovedWithMint') | ||
.withArgs( | ||
approveCommandId, | ||
sourceChain, | ||
sourceChainSwapCaller.address.toString(), | ||
destinationChainSwapForecallable.address, | ||
payloadHash, | ||
symbolA, | ||
swapAmount, | ||
sourceTxHash, | ||
sourceEventIndex, | ||
); | ||
const swap = await destinationChainSwapForecallable.executeWithToken( | ||
approveCommandId, | ||
sourceChain, | ||
sourceChainSwapCaller.address.toString(), | ||
payload, | ||
symbolA, | ||
swapAmount, | ||
); | ||
await expect(swap) | ||
.to.emit(tokenA, 'Transfer') | ||
.withArgs(destinationChainGateway.address, destinationChainSwapForecallable.address, swapAmount) | ||
.and.to.emit(tokenA, 'Transfer') | ||
.withArgs(destinationChainSwapForecallable.address, userWallet.address, swapAmount); | ||
}); | ||
}); | ||
}); |
@@ -7,7 +7,6 @@ 'use strict'; | ||
utils: { splitSignature }, | ||
} = require('ethers'); | ||
} = ethers; | ||
const { expect } = chai; | ||
const { getChainId, isHardhat } = require('./utils'); | ||
const CHAIN_ID = 1; | ||
describe('MintableCappedERC20', () => { | ||
@@ -19,3 +18,6 @@ let owner; | ||
beforeEach(async () => { | ||
await ethers.provider.send('hardhat_reset'); | ||
if (isHardhat) { | ||
await ethers.provider.send('hardhat_reset'); | ||
} | ||
[owner, user] = await ethers.getSigners(); | ||
@@ -27,3 +29,3 @@ | ||
await token.mint(user.address, 1000000); | ||
await token.mint(user.address, 1000000).then((tx) => tx.wait()); | ||
}); | ||
@@ -34,2 +36,3 @@ | ||
const deadline = (1000 + Date.now() / 1000) | 0; | ||
const allowance = 10000; | ||
@@ -41,3 +44,3 @@ const signature = splitSignature( | ||
version: '1', | ||
chainId: CHAIN_ID, | ||
chainId: await getChainId(), | ||
verifyingContract: token.address, | ||
@@ -57,3 +60,3 @@ }, | ||
spender: owner.address, | ||
value: 10000, | ||
value: allowance, | ||
nonce: 0, | ||
@@ -65,7 +68,24 @@ deadline, | ||
await expect(token.permit(user.address, owner.address, 10000, deadline, signature.v, signature.r, signature.s)) | ||
await expect( | ||
token.connect(owner).permit(user.address, owner.address, allowance, deadline, signature.v, signature.r, signature.s), | ||
) | ||
.to.emit(token, 'Approval') | ||
.withArgs(user.address, owner.address, 10000); | ||
.withArgs(user.address, owner.address, allowance); | ||
expect(await token.nonces(user.address)).to.equal(1); | ||
await expect(token.connect(owner).transferFrom(user.address, owner.address, allowance)) | ||
.to.emit(token, 'Transfer') | ||
.withArgs(user.address, owner.address, allowance); | ||
}); | ||
}); | ||
describe('ERC20 Mint', () => { | ||
it('should allow owner to mint', async () => { | ||
const amount = 10000; | ||
await expect(token.connect(owner).mint(user.address, amount)) | ||
.to.emit(token, 'Transfer') | ||
.withArgs(ethers.constants.AddressZero, user.address, amount); | ||
}); | ||
}); | ||
}); |
'use strict'; | ||
const { config, ethers } = require('hardhat'); | ||
const { | ||
utils: { defaultAbiCoder, id, arrayify, keccak256 }, | ||
} = require('ethers'); | ||
} = ethers; | ||
const { network } = require('hardhat'); | ||
const { sortBy } = require('lodash'); | ||
@@ -12,2 +14,7 @@ | ||
const getRandomString = (length) => { | ||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
return Array.from({ length }, () => characters[Math.floor(Math.random() * characters.length)]).join(''); | ||
}; | ||
const getAddresses = (wallets) => wallets.map(({ address }) => address); | ||
@@ -34,3 +41,17 @@ | ||
const getGasOptions = () => { | ||
return network.config.blockGasLimit ? { gasLimit: network.config.blockGasLimit.toString() } : {}; | ||
}; | ||
const getEVMVersion = () => { | ||
return config.solidity.compilers[0].settings.evmVersion; | ||
}; | ||
module.exports = { | ||
getChainId: async () => await network.provider.send('eth_chainId'), | ||
getEVMVersion, | ||
getGasOptions, | ||
bigNumberToNumber: (bigNumber) => bigNumber.toNumber(), | ||
@@ -52,2 +73,6 @@ | ||
getRandomString, | ||
isHardhat: network.name === 'hardhat', | ||
tickBlockTime: (provider, seconds) => provider.send('evm_increaseTime', [seconds]), | ||
@@ -63,21 +88,9 @@ | ||
getMultisigProxyDeployParams: (admins, adminThreshold, operators, operatorThreshold) => | ||
getWeightedProxyDeployParams: (governance, mintLimiter, operators, weights, operatorThreshold) => | ||
arrayify( | ||
defaultAbiCoder.encode( | ||
['address[]', 'uint8', 'bytes'], | ||
['address', 'address', 'bytes'], | ||
[ | ||
admins, | ||
adminThreshold, | ||
operators.length ? defaultAbiCoder.encode(['address[]', 'uint256'], [operators, operatorThreshold]) : '0x', | ||
], | ||
), | ||
), | ||
getWeightedProxyDeployParams: (admins, adminThreshold, operators, weights, operatorThreshold) => | ||
arrayify( | ||
defaultAbiCoder.encode( | ||
['address[]', 'uint8', 'bytes'], | ||
[ | ||
admins, | ||
adminThreshold, | ||
governance, | ||
mintLimiter, | ||
operators.length | ||
@@ -121,10 +134,10 @@ ? defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [operators, weights, operatorThreshold]) | ||
buildCommandBatch: (chianId, commandIDs, commandNames, commands) => | ||
arrayify(defaultAbiCoder.encode(['uint256', 'bytes32[]', 'string[]', 'bytes[]'], [chianId, commandIDs, commandNames, commands])), | ||
buildCommandBatch: (chainId, commandIDs, commandNames, commands) => | ||
arrayify(defaultAbiCoder.encode(['uint256', 'bytes32[]', 'string[]', 'bytes[]'], [chainId, commandIDs, commandNames, commands])), | ||
buildCommandBatchWithRole: (chianId, role, commandIDs, commandNames, commands) => | ||
buildCommandBatchWithRole: (chainId, role, commandIDs, commandNames, commands) => | ||
arrayify( | ||
defaultAbiCoder.encode( | ||
['uint256', 'uint256', 'bytes32[]', 'string[]', 'bytes[]'], | ||
[chianId, role, commandIDs, commandNames, commands], | ||
[chainId, role, commandIDs, commandNames, commands], | ||
), | ||
@@ -131,0 +144,0 @@ ), |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
577965
16
145
11926
1
86
132