Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@axelar-network/axelar-cgp-solidity

Package Overview
Dependencies
Maintainers
6
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@axelar-network/axelar-cgp-solidity - npm Package Compare versions

Comparing version 4.5.0 to 5.0.0

.github/workflows/conventional-commits.yaml

6

.solhint.json

@@ -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"
}
}

27

hardhat.config.js

@@ -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": {

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc