@axelar-network/axelar-cgp-solidity
Advanced tools
Comparing version 4.0.0 to 4.1.0
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
@@ -58,3 +58,3 @@ { | ||
"inputs": [], | ||
"name": "TokenSendFailed", | ||
"name": "TokenTransferFailed", | ||
"type": "error" | ||
@@ -99,11 +99,32 @@ }, | ||
{ | ||
"inputs": [], | ||
"name": "contractId", | ||
"outputs": [ | ||
"inputs": [ | ||
{ | ||
"internalType": "bytes32", | ||
"name": "", | ||
"name": "salt", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationChain", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationAddress", | ||
"type": "string" | ||
} | ||
], | ||
"name": "addressForNativeDeposit", | ||
"outputs": [ | ||
{ | ||
"internalType": "address", | ||
"name": "", | ||
"type": "address" | ||
} | ||
], | ||
"stateMutability": "view", | ||
@@ -120,13 +141,13 @@ "type": "function" | ||
{ | ||
"internalType": "string", | ||
"name": "destinationChain", | ||
"type": "string" | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationAddress", | ||
"type": "string" | ||
"internalType": "address", | ||
"name": "recipient", | ||
"type": "address" | ||
} | ||
], | ||
"name": "depositAddressForSendNative", | ||
"name": "addressForNativeUnwrap", | ||
"outputs": [ | ||
@@ -150,2 +171,7 @@ { | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "string", | ||
@@ -166,3 +192,3 @@ "name": "destinationChain", | ||
], | ||
"name": "depositAddressForSendToken", | ||
"name": "addressForTokenDeposit", | ||
"outputs": [ | ||
@@ -179,15 +205,30 @@ { | ||
{ | ||
"inputs": [ | ||
"inputs": [], | ||
"name": "contractId", | ||
"outputs": [ | ||
{ | ||
"internalType": "bytes32", | ||
"name": "salt", | ||
"name": "", | ||
"type": "bytes32" | ||
}, | ||
} | ||
], | ||
"stateMutability": "pure", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "gateway", | ||
"outputs": [ | ||
{ | ||
"internalType": "address", | ||
"name": "recipient", | ||
"name": "", | ||
"type": "address" | ||
} | ||
], | ||
"name": "depositAddressForWithdrawNative", | ||
"stateMutability": "nonpayable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "implementation", | ||
"outputs": [ | ||
@@ -204,2 +245,25 @@ { | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "bytes32", | ||
"name": "salt", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "address payable", | ||
"name": "recipient", | ||
"type": "address" | ||
} | ||
], | ||
"name": "nativeUnwrap", | ||
"outputs": [], | ||
"stateMutability": "nonpayable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [], | ||
@@ -225,2 +289,7 @@ "name": "owner", | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "string", | ||
@@ -234,6 +303,123 @@ "name": "destinationChain", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "address[]", | ||
"name": "refundTokens", | ||
"type": "address[]" | ||
} | ||
], | ||
"name": "refundNativeDeposit", | ||
"outputs": [], | ||
"stateMutability": "nonpayable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "bytes32", | ||
"name": "salt", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "address payable", | ||
"name": "recipient", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "address[]", | ||
"name": "refundTokens", | ||
"type": "address[]" | ||
} | ||
], | ||
"name": "refundNativeUnwrap", | ||
"outputs": [], | ||
"stateMutability": "nonpayable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "bytes32", | ||
"name": "salt", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationChain", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationAddress", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "tokenSymbol", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "address[]", | ||
"name": "refundTokens", | ||
"type": "address[]" | ||
} | ||
], | ||
"name": "refundTokenDeposit", | ||
"outputs": [], | ||
"stateMutability": "nonpayable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "string", | ||
"name": "destinationChain", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationAddress", | ||
"type": "string" | ||
} | ||
], | ||
"name": "sendNative", | ||
"outputs": [], | ||
"stateMutability": "payable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [ | ||
{ | ||
"internalType": "bytes32", | ||
"name": "salt", | ||
"type": "bytes32" | ||
}, | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationChain", | ||
"type": "string" | ||
}, | ||
{ | ||
"internalType": "string", | ||
"name": "destinationAddress", | ||
"type": "string" | ||
} | ||
], | ||
"name": "sendNativeDeposit", | ||
"outputs": [], | ||
"stateMutability": "nonpayable", | ||
@@ -250,2 +436,7 @@ "type": "function" | ||
{ | ||
"internalType": "address", | ||
"name": "refundAddress", | ||
"type": "address" | ||
}, | ||
{ | ||
"internalType": "string", | ||
@@ -266,3 +457,3 @@ "name": "destinationChain", | ||
], | ||
"name": "sendToken", | ||
"name": "sendTokenDeposit", | ||
"outputs": [], | ||
@@ -309,16 +500,24 @@ "stateMutability": "nonpayable", | ||
{ | ||
"inputs": [ | ||
"inputs": [], | ||
"name": "wrappedSymbol", | ||
"outputs": [ | ||
{ | ||
"internalType": "bytes32", | ||
"name": "salt", | ||
"type": "bytes32" | ||
}, | ||
"internalType": "string", | ||
"name": "", | ||
"type": "string" | ||
} | ||
], | ||
"stateMutability": "nonpayable", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "wrappedToken", | ||
"outputs": [ | ||
{ | ||
"internalType": "address payable", | ||
"name": "recipient", | ||
"internalType": "address", | ||
"name": "", | ||
"type": "address" | ||
} | ||
], | ||
"name": "withdrawNative", | ||
"outputs": [], | ||
"stateMutability": "nonpayable", | ||
@@ -325,0 +524,0 @@ "type": "function" |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
@@ -432,2 +432,15 @@ { | ||
], | ||
"stateMutability": "pure", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "implementation", | ||
"outputs": [ | ||
{ | ||
"internalType": "address", | ||
"name": "", | ||
"type": "address" | ||
} | ||
], | ||
"stateMutability": "view", | ||
@@ -434,0 +447,0 @@ "type": "function" |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
@@ -72,2 +72,15 @@ { | ||
], | ||
"stateMutability": "pure", | ||
"type": "function" | ||
}, | ||
{ | ||
"inputs": [], | ||
"name": "implementation", | ||
"outputs": [ | ||
{ | ||
"internalType": "address", | ||
"name": "", | ||
"type": "address" | ||
} | ||
], | ||
"stateMutability": "view", | ||
@@ -74,0 +87,0 @@ "type": "function" |
{ | ||
"_format": "hh-sol-dbg-1", | ||
"buildInfo": "../../../build-info/308766f20221baa152d8908fe868ab59.json" | ||
"buildInfo": "../../../build-info/3fbd7224c08399053ccde90bef5ec277.json" | ||
} |
{ | ||
"name": "@axelar-network/axelar-cgp-solidity", | ||
"version": "4.0.0", | ||
"version": "4.1.0", | ||
"description": "Ethereum Smart Contracts for Axelar Network", | ||
@@ -31,3 +31,5 @@ "main": "index.js", | ||
"@nomiclabs/hardhat-waffle": "^2.0.3", | ||
"axelar-utils-solidity": "https://github.com/axelarnetwork/axelar-utils-solidity.git", | ||
"chai": "^4.3.6", | ||
"dotenv": "^16.0.1", | ||
"eslint": "^8.17.0", | ||
@@ -37,2 +39,3 @@ "eslint-config-richardpringle": "^2.0.0", | ||
"ethers": "^5.6.8", | ||
"fs-extra": "^10.1.0", | ||
"hardhat": "^2.9.7", | ||
@@ -44,2 +47,3 @@ "hardhat-gas-reporter": "^1.0.8", | ||
"prettier-plugin-solidity": "^1.0.0-beta.19", | ||
"readline-sync": "^1.4.10", | ||
"solhint": "^3.3.7", | ||
@@ -46,0 +50,0 @@ "solidity-coverage": "^0.7.21" |
@@ -6,3 +6,3 @@ 'use strict'; | ||
Contract, | ||
utils: { defaultAbiCoder, arrayify, formatBytes32String, keccak256, getCreate2Address, toUtf8Bytes }, | ||
utils: { defaultAbiCoder, arrayify, solidityPack, formatBytes32String, keccak256, getCreate2Address }, | ||
} = require('ethers'); | ||
@@ -17,3 +17,3 @@ const { deployContract, MockProvider, solidity } = require('ethereum-waffle'); | ||
const Auth = require('../artifacts/contracts/AxelarAuthMultisig.sol/AxelarAuthMultisig.json'); | ||
const Auth = require('../artifacts/contracts/auth/AxelarAuthWeighted.sol/AxelarAuthWeighted.json'); | ||
const TokenDeployer = require('../artifacts/contracts/TokenDeployer.sol/TokenDeployer.json'); | ||
@@ -23,7 +23,10 @@ const AxelarGatewayProxy = require('../artifacts/contracts/AxelarGatewayProxy.sol/AxelarGatewayProxy.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 DepositService = require('../artifacts/contracts/deposit-service/AxelarDepositService.sol/AxelarDepositService.json'); | ||
const DepositServiceProxy = require('../artifacts/contracts/deposit-service/AxelarDepositServiceProxy.sol/AxelarDepositServiceProxy.json'); | ||
const DepositReceiver = require('../artifacts/contracts/deposit-service/DepositReceiver.sol/DepositReceiver.json'); | ||
const { getAuthDeployParam, getSignedMultisigExecuteInput, getRandomID } = require('./utils'); | ||
const { getWeightedAuthDeployParam, getSignedWeightedExecuteInput, getRandomID } = require('./utils'); | ||
const { deployUpgradable } = require('../scripts/upgradable'); | ||
@@ -38,2 +41,3 @@ describe('AxelarDepositService', () => { | ||
let token; | ||
let wrongToken; | ||
let depositService; | ||
@@ -44,2 +48,4 @@ | ||
const tokenSymbol = 'WETH'; | ||
const wrongTokenName = 'Wrapped Eth'; | ||
const wrongTokenSymbol = 'WETH'; | ||
const decimals = 16; | ||
@@ -52,3 +58,4 @@ const capacity = 0; | ||
); | ||
const auth = await deployContract(ownerWallet, Auth, [getAuthDeployParam([[operatorWallet.address]], [1])]); | ||
const constAddressDeployer = await deployContract(ownerWallet, ConstAddressDeployer); | ||
const auth = await deployContract(ownerWallet, Auth, [getWeightedAuthDeployParam([[operatorWallet.address]], [[1]], [1])]); | ||
const tokenDeployer = await deployContract(ownerWallet, TokenDeployer); | ||
@@ -61,7 +68,9 @@ const gatewayImplementation = await deployContract(ownerWallet, AxelarGateway, [auth.address, tokenDeployer.address]); | ||
token = await deployContract(ownerWallet, TestWeth, [tokenName, tokenSymbol, decimals, capacity]); | ||
wrongToken = await deployContract(ownerWallet, TestWeth, [wrongTokenName, wrongTokenSymbol, decimals, capacity]); | ||
await token.connect(ownerWallet).deposit({ value: 1e9 }); | ||
await token.deposit({ value: 1e9 }); | ||
await wrongToken.deposit({ value: 1e9 }); | ||
await gateway.execute( | ||
await getSignedMultisigExecuteInput( | ||
await getSignedWeightedExecuteInput( | ||
arrayify( | ||
@@ -85,2 +94,4 @@ defaultAbiCoder.encode( | ||
[operatorWallet], | ||
[1], | ||
1, | ||
[operatorWallet], | ||
@@ -90,13 +101,21 @@ ), | ||
const depositImplementation = await deployContract(ownerWallet, DepositService); | ||
const depositProxy = await deployContract(ownerWallet, DepositServiceProxy, [ | ||
depositImplementation.address, | ||
arrayify(defaultAbiCoder.encode(['address', 'string'], [gateway.address, tokenSymbol])), | ||
depositService = await deployUpgradable(constAddressDeployer.address, ownerWallet, DepositService, DepositServiceProxy, [ | ||
gateway.address, | ||
tokenSymbol, | ||
]); | ||
depositService = new Contract(depositProxy.address, DepositService.abi, ownerWallet); | ||
}); | ||
describe('deposit service', () => { | ||
it('should handle and send ERC20 token', async () => { | ||
it('should send native token', async () => { | ||
const destinationAddress = userWallet.address.toString(); | ||
const amount = 1e6; | ||
await expect(depositService.sendNative(destinationChain, destinationAddress, { value: amount })) | ||
.to.emit(gateway, 'TokenSent') | ||
.withArgs(depositService.address, destinationChain, destinationAddress, tokenSymbol, amount); | ||
}); | ||
it('should handle and transfer ERC20 token', async () => { | ||
const refundAddress = ownerWallet.address; | ||
const destinationAddress = userWallet.address.toString(); | ||
const salt = formatBytes32String(1); | ||
@@ -107,18 +126,36 @@ const amount = 1e6; | ||
depositService.address, | ||
salt, | ||
keccak256( | ||
defaultAbiCoder.encode( | ||
['bytes32', 'bytes32', 'string', 'string', 'string'], | ||
[keccak256(toUtf8Bytes('deposit-send-token')), salt, destinationChain, destinationAddress, tokenSymbol], | ||
solidityPack( | ||
['bytes', 'bytes'], | ||
[ | ||
DepositReceiver.bytecode, | ||
defaultAbiCoder.encode( | ||
['bytes'], | ||
[ | ||
depositService.interface.encodeFunctionData('receiveAndSendToken', [ | ||
refundAddress, | ||
destinationChain, | ||
destinationAddress, | ||
tokenSymbol, | ||
]), | ||
], | ||
), | ||
], | ||
), | ||
), | ||
keccak256(DepositReceiver.bytecode), | ||
); | ||
const depositAddress = await depositService.depositAddressForSendToken(salt, destinationChain, destinationAddress, tokenSymbol); | ||
const depositAddress = await depositService.addressForTokenDeposit( | ||
salt, | ||
refundAddress, | ||
destinationChain, | ||
destinationAddress, | ||
tokenSymbol, | ||
); | ||
expect(depositAddress).to.be.equal(expectedDepositAddress); | ||
await token.connect(ownerWallet).transfer(depositAddress, amount); | ||
await expect(depositService.sendToken(salt, destinationChain, destinationAddress, tokenSymbol)) | ||
await token.transfer(depositAddress, amount); | ||
await expect(depositService.sendTokenDeposit(salt, refundAddress, destinationChain, destinationAddress, tokenSymbol)) | ||
.to.emit(gateway, 'TokenSent') | ||
@@ -128,3 +165,4 @@ .withArgs(depositAddress, destinationChain, destinationAddress, tokenSymbol, amount); | ||
it('should wrap and send native currency', async () => { | ||
it('should refund from transfer token address', async () => { | ||
const refundAddress = ownerWallet.address; | ||
const destinationAddress = userWallet.address.toString(); | ||
@@ -134,14 +172,70 @@ const salt = formatBytes32String(1); | ||
const depositAddress = await depositService.addressForTokenDeposit( | ||
salt, | ||
refundAddress, | ||
destinationChain, | ||
destinationAddress, | ||
tokenSymbol, | ||
); | ||
await token.transfer(depositAddress, amount); | ||
await wrongToken.transfer(depositAddress, amount * 2); | ||
await expect( | ||
depositService | ||
.connect(userWallet) | ||
.refundTokenDeposit(salt, refundAddress, destinationChain, destinationAddress, tokenSymbol, [token.address]), | ||
).not.to.emit(token, 'Transfer'); | ||
await expect( | ||
depositService | ||
.connect(ownerWallet) | ||
.refundTokenDeposit(salt, refundAddress, destinationChain, destinationAddress, tokenSymbol, [token.address]), | ||
).to.emit(token, 'Transfer'); | ||
await ownerWallet.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}); | ||
await expect( | ||
await depositService.refundTokenDeposit(salt, refundAddress, destinationChain, destinationAddress, tokenSymbol, [ | ||
wrongToken.address, | ||
]), | ||
) | ||
.to.emit(wrongToken, 'Transfer') | ||
.withArgs(depositAddress, refundAddress, amount * 2) | ||
.to.changeEtherBalance(ownerWallet, amount); | ||
}); | ||
it('should wrap and transfer native currency', async () => { | ||
const refundAddress = ownerWallet.address; | ||
const destinationAddress = userWallet.address.toString(); | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const expectedDepositAddress = getCreate2Address( | ||
depositService.address, | ||
salt, | ||
keccak256( | ||
defaultAbiCoder.encode( | ||
['bytes32', 'bytes32', 'string', 'string'], | ||
[keccak256(toUtf8Bytes('deposit-send-native')), salt, destinationChain, destinationAddress], | ||
solidityPack( | ||
['bytes', 'bytes'], | ||
[ | ||
DepositReceiver.bytecode, | ||
defaultAbiCoder.encode( | ||
['bytes'], | ||
[ | ||
depositService.interface.encodeFunctionData('receiveAndSendNative', [ | ||
refundAddress, | ||
destinationChain, | ||
destinationAddress, | ||
]), | ||
], | ||
), | ||
], | ||
), | ||
), | ||
keccak256(DepositReceiver.bytecode), | ||
); | ||
const depositAddress = await depositService.depositAddressForSendNative(salt, destinationChain, destinationAddress); | ||
const depositAddress = await depositService.addressForNativeDeposit(salt, refundAddress, destinationChain, destinationAddress); | ||
@@ -155,3 +249,3 @@ expect(depositAddress).to.be.equal(expectedDepositAddress); | ||
await expect(await depositService.sendNative(salt, destinationChain, destinationAddress)) | ||
await expect(await depositService.sendNativeDeposit(salt, refundAddress, destinationChain, destinationAddress)) | ||
.to.emit(gateway, 'TokenSent') | ||
@@ -161,3 +255,25 @@ .withArgs(depositAddress, destinationChain, destinationAddress, tokenSymbol, amount); | ||
it('should refund from transfer native address', async () => { | ||
const refundAddress = ownerWallet.address; | ||
const destinationAddress = userWallet.address.toString(); | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const depositAddress = await depositService.addressForNativeDeposit(salt, refundAddress, destinationChain, destinationAddress); | ||
await ownerWallet.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}); | ||
await wrongToken.transfer(depositAddress, amount * 2); | ||
await expect( | ||
depositService.refundNativeDeposit(salt, refundAddress, destinationChain, destinationAddress, [wrongToken.address]), | ||
) | ||
.to.emit(wrongToken, 'Transfer') | ||
.withArgs(depositAddress, refundAddress, amount * 2); | ||
}); | ||
it('should unwrap native currency', async () => { | ||
const refundAddress = ownerWallet.address; | ||
const recipient = userWallet.address; | ||
@@ -169,20 +285,57 @@ const salt = formatBytes32String(1); | ||
depositService.address, | ||
salt, | ||
keccak256( | ||
defaultAbiCoder.encode( | ||
['bytes32', 'bytes32', 'address'], | ||
[keccak256(toUtf8Bytes('deposit-withdraw-native')), salt, recipient], | ||
solidityPack( | ||
['bytes', 'bytes'], | ||
[ | ||
DepositReceiver.bytecode, | ||
defaultAbiCoder.encode( | ||
['bytes'], | ||
[depositService.interface.encodeFunctionData('receiveAndUnwrapNative', [refundAddress, recipient])], | ||
), | ||
], | ||
), | ||
), | ||
keccak256(DepositReceiver.bytecode), | ||
); | ||
const depositAddress = await depositService.depositAddressForWithdrawNative(salt, recipient); | ||
const depositAddress = await depositService.addressForNativeUnwrap(salt, refundAddress, recipient); | ||
expect(depositAddress).to.be.equal(expectedDepositAddress); | ||
await token.connect(ownerWallet).transfer(depositAddress, amount); | ||
await token.transfer(depositAddress, amount); | ||
await expect(await depositService.withdrawNative(salt, recipient)).to.changeEtherBalance(userWallet, amount); | ||
await expect(await depositService.nativeUnwrap(salt, refundAddress, recipient)).to.changeEtherBalance(userWallet, amount); | ||
}); | ||
it('should refund from unwrap native address', async () => { | ||
const refundAddress = ownerWallet.address; | ||
const recipient = userWallet.address; | ||
const salt = formatBytes32String(1); | ||
const amount = 1e6; | ||
const depositAddress = await depositService.addressForNativeUnwrap(salt, refundAddress, recipient); | ||
await token.transfer(depositAddress, amount); | ||
await wrongToken.transfer(depositAddress, amount * 2); | ||
await expect( | ||
depositService.connect(userWallet).refundNativeUnwrap(salt, refundAddress, recipient, [token.address]), | ||
).not.to.emit(token, 'Transfer'); | ||
await expect(depositService.connect(ownerWallet).refundNativeUnwrap(salt, refundAddress, recipient, [token.address])).to.emit( | ||
token, | ||
'Transfer', | ||
); | ||
await ownerWallet.sendTransaction({ | ||
to: depositAddress, | ||
value: amount, | ||
}); | ||
await expect(await depositService.refundNativeUnwrap(salt, refundAddress, recipient, [wrongToken.address])) | ||
.to.emit(wrongToken, 'Transfer') | ||
.withArgs(depositAddress, refundAddress, amount * 2) | ||
.to.changeEtherBalance(ownerWallet, amount); | ||
}); | ||
}); | ||
}); |
@@ -15,3 +15,3 @@ const { sortBy } = require('lodash'); | ||
bigNumberToNumber, | ||
getSignedMultisigExecuteInput, | ||
getSignedWeightedExecuteInput, | ||
getRandomInt, | ||
@@ -23,3 +23,2 @@ getRandomID, | ||
getBurnCommand, | ||
getTransferMultiOperatorshipCommand, | ||
buildCommandBatch, | ||
@@ -31,5 +30,9 @@ buildCommandBatchWithRole, | ||
tickBlockTime, | ||
getAuthDeployParam, | ||
getWeightedAuthDeployParam, | ||
getTransferWeightedOperatorshipCommand, | ||
getWeightedProxyDeployParams, | ||
} = require('./utils'); | ||
const getWeights = ({ length }, weight = 1) => Array(length).fill(weight); | ||
describe('AxelarGatewayMultisig', () => { | ||
@@ -62,3 +65,3 @@ const threshold = 3; | ||
gatewayFactory = await ethers.getContractFactory('AxelarGateway', owner); | ||
authFactory = await ethers.getContractFactory('AxelarAuthMultisig', owner); | ||
authFactory = await ethers.getContractFactory('AxelarAuthWeighted', owner); | ||
tokenDeployerFactory = await ethers.getContractFactory('TokenDeployer', owner); | ||
@@ -77,3 +80,5 @@ gatewayProxyFactory = await ethers.getContractFactory('AxelarGatewayProxy', owner); | ||
auth = await authFactory.deploy(getAuthDeployParam([operatorAddresses], [threshold])).then((d) => d.deployed()); | ||
auth = await authFactory | ||
.deploy(getWeightedAuthDeployParam([operatorAddresses], [getWeights(operatorAddresses)], [threshold])) | ||
.then((d) => d.deployed()); | ||
tokenDeployer = await tokenDeployerFactory.deploy().then((d) => d.deployed()); | ||
@@ -105,3 +110,5 @@ const gatewayImplementation = await gatewayFactory.deploy(auth.address, tokenDeployer.address).then((d) => d.deployed()); | ||
return getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)).then((input) => gateway.execute(input)); | ||
return getSignedWeightedExecuteInput(data, operators, getWeights(operators), threshold, operators.slice(0, threshold)).then( | ||
(input) => gateway.execute(input), | ||
); | ||
}); | ||
@@ -142,3 +149,3 @@ | ||
const params = getMultisigProxyDeployParams(newAdminAddresses, 2, newOperatorAddresses, 2); | ||
const params = getWeightedProxyDeployParams(newAdminAddresses, 2, newOperatorAddresses, getWeights(newOperatorAddresses), 2); | ||
@@ -194,4 +201,5 @@ await Promise.all( | ||
[ | ||
getTransferMultiOperatorshipCommand( | ||
getTransferWeightedOperatorshipCommand( | ||
['0xb7900E8Ec64A1D1315B6D4017d4b1dcd36E6Ea88', '0x6D4017D4b1DCd36e6EA88b7900e8eC64A1D1315b'], | ||
[1, 1], | ||
2, | ||
@@ -202,3 +210,9 @@ ), | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -229,3 +243,9 @@ await expect(gateway.execute(input)).to.be.reverted; | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(input)) | ||
@@ -258,3 +278,9 @@ .to.emit(gateway, 'TokenDeployed') | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(input)).to.emit(gateway, 'TokenDeployed'); | ||
@@ -273,3 +299,9 @@ }); | ||
const firstInput = await getSignedMultisigExecuteInput(firstData, operators, operators.slice(0, threshold)); | ||
const firstInput = await getSignedWeightedExecuteInput( | ||
firstData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(firstInput)) | ||
@@ -289,3 +321,9 @@ .to.emit(gateway, 'TokenDeployed') | ||
const secondInput = await getSignedMultisigExecuteInput(secondData, operators, operators.slice(0, threshold)); | ||
const secondInput = await getSignedWeightedExecuteInput( | ||
secondData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(secondInput)) | ||
@@ -314,3 +352,9 @@ .to.not.emit(gateway, 'TokenDeployed') | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await gateway.execute(input); | ||
@@ -332,3 +376,9 @@ | ||
const firstMintInput = await getSignedMultisigExecuteInput(firstMintData, operators, operators.slice(0, threshold)); | ||
const firstMintInput = await getSignedWeightedExecuteInput( | ||
firstMintData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(firstMintInput)).to.emit(gateway, 'Executed'); | ||
@@ -344,3 +394,9 @@ | ||
const secondMintInput = getSignedMultisigExecuteInput(secondMintData, operators, operators.slice(0, threshold)); | ||
const secondMintInput = getSignedWeightedExecuteInput( | ||
secondMintData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -362,3 +418,9 @@ await expect(gateway.execute(secondMintInput)).to.emit(gateway, 'Executed'); | ||
return getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)).then((input) => | ||
return getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
).then((input) => | ||
expect(gateway.execute(input)) | ||
@@ -382,3 +444,9 @@ .to.emit(token, 'Transfer') | ||
); | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -399,3 +467,9 @@ await expect(gateway.execute(input)).to.not.emit(gateway, 'Executed'); | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -415,3 +489,9 @@ await expect(gateway.execute(input)) | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -430,2 +510,4 @@ await expect(gateway.execute(input)) | ||
const symbol = 'AAT'; | ||
const externalName = 'An External Token'; | ||
const externalSymbol = 'AET'; | ||
const decimals = 18; | ||
@@ -436,12 +518,26 @@ const cap = 1e8; | ||
let token; | ||
let externalToken; | ||
beforeEach(async () => { | ||
externalToken = await mintableCappedERC20Factory.deploy(externalName, externalSymbol, decimals, cap).then((d) => d.deployed()); | ||
await externalToken.mint(owner.address, amount); | ||
const data = buildCommandBatch( | ||
CHAIN_ID, | ||
[getRandomID(), getRandomID()], | ||
['deployToken', 'mintToken'], | ||
[getDeployCommand(name, symbol, decimals, cap, ADDRESS_ZERO, 0), getMintCommand(symbol, owner.address, amount)], | ||
[getRandomID(), getRandomID(), getRandomID()], | ||
['deployToken', 'deployToken', 'mintToken'], | ||
[ | ||
getDeployCommand(externalName, externalSymbol, decimals, cap, externalToken.address, 0), | ||
getDeployCommand(name, symbol, decimals, cap, ADDRESS_ZERO, 0), | ||
getMintCommand(symbol, owner.address, amount), | ||
], | ||
); | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await gateway.execute(input); | ||
@@ -453,3 +549,3 @@ | ||
it('should allow the owners to burn tokens', async () => { | ||
it('should allow the operators to burn internal tokens', async () => { | ||
const destinationBtcAddress = '1KDeqnsTRzFeXRaENA6XLN1EwdTujchr4L'; | ||
@@ -464,3 +560,9 @@ const salt = id(`${destinationBtcAddress}-${owner.address}-${Date.now()}`); | ||
const firstInput = await getSignedMultisigExecuteInput(dataFirstBurn, operators, operators.slice(0, threshold)); | ||
const firstInput = await getSignedWeightedExecuteInput( | ||
dataFirstBurn, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -473,5 +575,13 @@ await expect(gateway.execute(firstInput)).to.emit(token, 'Transfer').withArgs(depositHandlerAddress, ADDRESS_ZERO, burnAmount); | ||
const secondInput = await getSignedMultisigExecuteInput(dataSecondBurn, operators, operators.slice(0, threshold)); | ||
const secondInput = await getSignedWeightedExecuteInput( | ||
dataSecondBurn, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(secondInput)).to.emit(token, 'Transfer').withArgs(depositHandlerAddress, ADDRESS_ZERO, burnAmount); | ||
await expect(await gateway.execute(secondInput)) | ||
.to.emit(token, 'Transfer') | ||
.withArgs(depositHandlerAddress, ADDRESS_ZERO, burnAmount); | ||
@@ -481,3 +591,3 @@ expect(await token.balanceOf(depositHandlerAddress).then(bigNumberToNumber)).to.eq(0); | ||
it('should allow the operators to burn tokens', async () => { | ||
it('should allow the operators to burn external tokens', async () => { | ||
const destinationBtcAddress = '1KDeqnsTRzFeXRaENA6XLN1EwdTujchr4L'; | ||
@@ -488,3 +598,3 @@ const salt = id(`${destinationBtcAddress}-${owner.address}-${Date.now()}`); | ||
const burnAmount = amount / 2; | ||
await token.transfer(depositHandlerAddress, burnAmount); | ||
await externalToken.transfer(depositHandlerAddress, burnAmount); | ||
@@ -496,18 +606,34 @@ const dataFirstBurn = buildCommandBatchWithRole( | ||
['burnToken'], | ||
[getBurnCommand(symbol, salt)], | ||
[getBurnCommand(externalSymbol, salt)], | ||
); | ||
const firstInput = await getSignedMultisigExecuteInput(dataFirstBurn, operators, operators.slice(0, threshold)); | ||
const firstInput = await getSignedWeightedExecuteInput( | ||
dataFirstBurn, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(firstInput)).to.emit(token, 'Transfer').withArgs(depositHandlerAddress, ADDRESS_ZERO, burnAmount); | ||
await expect(gateway.execute(firstInput)) | ||
.to.emit(externalToken, 'Transfer') | ||
.withArgs(depositHandlerAddress, gateway.address, burnAmount); | ||
await token.transfer(depositHandlerAddress, burnAmount); | ||
await externalToken.transfer(depositHandlerAddress, burnAmount); | ||
const dataSecondBurn = buildCommandBatch(CHAIN_ID, [getRandomID()], ['burnToken'], [getBurnCommand(symbol, salt)]); | ||
const dataSecondBurn = buildCommandBatch(CHAIN_ID, [getRandomID()], ['burnToken'], [getBurnCommand(externalSymbol, salt)]); | ||
const secondInput = await getSignedMultisigExecuteInput(dataSecondBurn, operators, operators.slice(0, threshold)); | ||
const secondInput = await getSignedWeightedExecuteInput( | ||
dataSecondBurn, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(secondInput)).to.emit(token, 'Transfer').withArgs(depositHandlerAddress, ADDRESS_ZERO, burnAmount); | ||
await expect(await gateway.execute(secondInput)) | ||
.to.emit(externalToken, 'Transfer') | ||
.withArgs(depositHandlerAddress, gateway.address, burnAmount); | ||
expect(await token.balanceOf(depositHandlerAddress).then(bigNumberToNumber)).to.eq(0); | ||
expect(await externalToken.balanceOf(depositHandlerAddress).then(bigNumberToNumber)).to.eq(0); | ||
}); | ||
@@ -524,10 +650,16 @@ }); | ||
['transferOperatorship'], | ||
[getTransferMultiOperatorshipCommand(newOperators, 2)], | ||
[getTransferWeightedOperatorshipCommand(newOperators, getWeights(newOperators), 2)], | ||
); | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(input)) | ||
.to.emit(gateway, 'OperatorshipTransferred') | ||
.withArgs(getTransferMultiOperatorshipCommand(newOperators, 2)); | ||
.withArgs(getTransferWeightedOperatorshipCommand(newOperators, getWeights(newOperators), 2)); | ||
}); | ||
@@ -542,6 +674,12 @@ | ||
['transferOperatorship'], | ||
[getTransferMultiOperatorshipCommand(newOperators, 2)], | ||
[getTransferWeightedOperatorshipCommand(newOperators, getWeights(newOperators), 2)], | ||
); | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -558,8 +696,10 @@ await expect(gateway.execute(input)).not.to.emit(gateway, 'OperatorshipTransferred'); | ||
['transferOperatorship'], | ||
[getTransferMultiOperatorshipCommand(newOperators, 2)], | ||
[getTransferWeightedOperatorshipCommand(newOperators, getWeights(newOperators), 2)], | ||
); | ||
const transferOwnershipInput = await getSignedMultisigExecuteInput( | ||
const transferOwnershipInput = await getSignedWeightedExecuteInput( | ||
transferOwnershipData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
@@ -570,3 +710,3 @@ ); | ||
.to.emit(gateway, 'OperatorshipTransferred') | ||
.withArgs(getTransferMultiOperatorshipCommand(newOperators, 2)); | ||
.withArgs(getTransferWeightedOperatorshipCommand(newOperators, getWeights(newOperators), 2)); | ||
@@ -585,3 +725,9 @@ const name = 'An Awesome Token'; | ||
const deployAndMintInput = await getSignedMultisigExecuteInput(deployData, operators, operators.slice(0, threshold)); | ||
const deployAndMintInput = await getSignedWeightedExecuteInput( | ||
deployData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(deployAndMintInput)).to.emit(gateway, 'TokenDeployed'); | ||
@@ -596,3 +742,9 @@ | ||
const mintInput = await getSignedMultisigExecuteInput(mintData, operators, operators.slice(0, threshold)); | ||
const mintInput = await getSignedWeightedExecuteInput( | ||
mintData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -613,3 +765,9 @@ await expect(gateway.execute(mintInput)) | ||
await token.transfer(depositHandlerAddress, amount); | ||
const burnInput = await getSignedMultisigExecuteInput(burnData, operators, operators.slice(0, threshold)); | ||
const burnInput = await getSignedWeightedExecuteInput( | ||
burnData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -627,6 +785,12 @@ await expect(gateway.execute(burnInput)).to.emit(token, 'Transfer').withArgs(depositHandlerAddress, ADDRESS_ZERO, amount); | ||
['transferOperatorship'], | ||
[getTransferMultiOperatorshipCommand(newOperators, newOperators.length)], | ||
[getTransferWeightedOperatorshipCommand(newOperators, getWeights(newOperators), newOperators.length)], | ||
); | ||
let input = await getSignedMultisigExecuteInput(buildTransferData(), operators, operators.slice(0, threshold)); | ||
let input = await getSignedWeightedExecuteInput( | ||
buildTransferData(), | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(input)).to.emit(gateway, 'OperatorshipTransferred'); | ||
@@ -636,3 +800,9 @@ | ||
input = await getSignedMultisigExecuteInput(buildTransferData(), operators, operators.slice(0, threshold)); | ||
input = await getSignedWeightedExecuteInput( | ||
buildTransferData(), | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -650,6 +820,12 @@ await expect(gateway.execute(input)).not.to.emit(gateway, 'OperatorshipTransferred'); | ||
['transferOperatorship'], | ||
[getTransferMultiOperatorshipCommand(newOperators, newThreshold)], | ||
[getTransferWeightedOperatorshipCommand(newOperators, getWeights(newOperators), newThreshold)], | ||
); | ||
let input = await getSignedMultisigExecuteInput(buildTransferData(updatedOperators), operators, operators.slice(0, threshold)); | ||
let input = await getSignedWeightedExecuteInput( | ||
buildTransferData(updatedOperators), | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(input)).to.emit(gateway, 'OperatorshipTransferred'); | ||
@@ -659,5 +835,7 @@ | ||
input = await getSignedMultisigExecuteInput( | ||
input = await getSignedWeightedExecuteInput( | ||
buildTransferData(oldOperators, threshold), | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
@@ -684,3 +862,9 @@ ); | ||
const input = await getSignedMultisigExecuteInput(deployAndMintData, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
deployAndMintData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await gateway.execute(input); | ||
@@ -717,3 +901,9 @@ | ||
const input = await getSignedMultisigExecuteInput(deployData, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
deployData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await gateway.execute(input); | ||
@@ -756,3 +946,9 @@ | ||
const deployInput = await getSignedMultisigExecuteInput(deployData, operators, operators.slice(0, threshold)); | ||
const deployInput = await getSignedWeightedExecuteInput( | ||
deployData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -767,3 +963,9 @@ await expect(gateway.execute(deployInput)).to.emit(gateway, 'TokenDeployed').withArgs(symbol, token.address); | ||
const burnInput = await getSignedMultisigExecuteInput(burnData, operators, operators.slice(0, threshold)); | ||
const burnInput = await getSignedWeightedExecuteInput( | ||
burnData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -779,3 +981,9 @@ await expect(gateway.execute(burnInput)).to.emit(token, 'Transfer').withArgs(depositHandlerAddress, gateway.address, amount); | ||
const mintInput = await getSignedMultisigExecuteInput(mintData, operators, operators.slice(0, threshold)); | ||
const mintInput = await getSignedWeightedExecuteInput( | ||
mintData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -804,12 +1012,15 @@ await expect(gateway.execute(mintInput)).to.emit(token, 'Transfer').withArgs(gateway.address, wallets[1].address, amount); | ||
getMintCommand(symbol, wallets[1].address, amount2), | ||
getTransferMultiOperatorshipCommand(newOperators, 2), | ||
getTransferWeightedOperatorshipCommand(newOperators, getWeights(newOperators), 2), | ||
], | ||
); | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await expect(gateway.execute(input)) | ||
.to.emit(gateway, 'TokenDeployed') | ||
.and.to.emit(gateway, 'OperatorshipTransferred') | ||
.withArgs(getTransferMultiOperatorshipCommand(newOperators, 2)); | ||
await expect(gateway.execute(input)).to.emit(gateway, 'TokenDeployed').and.to.emit(gateway, 'OperatorshipTransferred'); | ||
@@ -853,3 +1064,9 @@ const tokenAddress = await gateway.tokenAddresses(symbol); | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await gateway.execute(input); | ||
@@ -873,3 +1090,9 @@ | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await gateway.execute(input); | ||
@@ -908,3 +1131,9 @@ | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
await gateway.execute(input); | ||
@@ -943,3 +1172,9 @@ | ||
const input = await getSignedMultisigExecuteInput(data, operators, operators.slice(0, threshold)); | ||
const input = await getSignedWeightedExecuteInput( | ||
data, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -982,3 +1217,9 @@ await gateway.execute(input); | ||
const approveInput = await getSignedMultisigExecuteInput(approveData, operators, operators.slice(0, threshold)); | ||
const approveInput = await getSignedWeightedExecuteInput( | ||
approveData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -1023,3 +1264,9 @@ await expect(gateway.execute(approveInput)) | ||
const deployTokenInput = await getSignedMultisigExecuteInput(deployTokenData, operators, operators.slice(0, threshold)); | ||
const deployTokenInput = await getSignedWeightedExecuteInput( | ||
deployTokenData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -1055,3 +1302,9 @@ await expect(gateway.execute(deployTokenInput)).to.emit(gateway, 'TokenDeployed').withArgs(symbolA, tokenA.address); | ||
const approveWithMintInput = await getSignedMultisigExecuteInput(approveWithMintData, operators, operators.slice(0, threshold)); | ||
const approveWithMintInput = await getSignedWeightedExecuteInput( | ||
approveWithMintData, | ||
operators, | ||
getWeights(operators), | ||
threshold, | ||
operators.slice(0, threshold), | ||
); | ||
@@ -1058,0 +1311,0 @@ await expect(gateway.execute(approveWithMintInput)) |
@@ -5,4 +5,3 @@ 'use strict'; | ||
const { | ||
Contract, | ||
utils: { defaultAbiCoder, arrayify, keccak256, parseEther }, | ||
utils: { defaultAbiCoder, keccak256, parseEther }, | ||
} = require('ethers'); | ||
@@ -19,2 +18,5 @@ const { deployContract, MockProvider, solidity } = require('ethereum-waffle'); | ||
const ConstAddressDeployer = require('axelar-utils-solidity/dist/ConstAddressDeployer.json'); | ||
const { deployUpgradable, upgradeUpgradable } = require('../../scripts/upgradable'); | ||
describe('AxelarGasService', () => { | ||
@@ -27,6 +29,5 @@ const [ownerWallet, userWallet] = new MockProvider().getWallets(); | ||
beforeEach(async () => { | ||
const gasImplementation = await deployContract(ownerWallet, GasService); | ||
const gasProxy = await deployContract(ownerWallet, GasServiceProxy, [gasImplementation.address, arrayify([])]); | ||
const constAddressDeployer = await deployContract(ownerWallet, ConstAddressDeployer); | ||
gasService = new Contract(gasProxy.address, GasService.abi, userWallet); | ||
gasService = await deployUpgradable(constAddressDeployer.address, ownerWallet, GasService, GasServiceProxy); | ||
@@ -215,20 +216,9 @@ const name = 'testToken'; | ||
it('should upgrade the gas receiver implementation', async () => { | ||
const receiverImplementation = await deployContract(ownerWallet, GasService); | ||
const newImplementationCode = await receiverImplementation.provider.getCode(receiverImplementation.address); | ||
const newImplementationCodeHash = keccak256(newImplementationCode); | ||
const prevImpl = await gasService.implementation(); | ||
await expect(upgradeUpgradable(gasService.address, GasService, '0x', ownerWallet)).to.emit(gasService, 'Upgraded'); | ||
await expect(await gasService.owner()).to.be.equal(ownerWallet.address); | ||
const newImpl = await gasService.implementation(); | ||
expect(await gasService.owner()).to.be.equal(ownerWallet.address); | ||
expect(prevImpl).to.not.equal(newImpl); | ||
await expect( | ||
gasService | ||
.connect(ownerWallet) | ||
.upgrade( | ||
receiverImplementation.address, | ||
newImplementationCodeHash, | ||
arrayify(defaultAbiCoder.encode(['address'], [userWallet.address])), | ||
), | ||
) | ||
.to.emit(gasService, 'Upgraded') | ||
.withArgs(receiverImplementation.address); | ||
await expect(gasService.connect(ownerWallet).transferOwnership(userWallet.address)) | ||
@@ -240,24 +230,26 @@ .and.to.emit(gasService, 'OwnershipTransferred') | ||
}); | ||
}); | ||
it('should emit events when gas is added', async () => { | ||
const txHash = keccak256(defaultAbiCoder.encode(['string'], ['random tx hash'])); | ||
const logIndex = 13; | ||
const gasToken = testToken.address; | ||
const gasFeeAmount = 1000; | ||
const nativeGasFeeAmount = parseEther('1.0'); | ||
it('should emit events when gas is added', async () => { | ||
const txHash = keccak256(defaultAbiCoder.encode(['string'], ['random tx hash'])); | ||
const logIndex = 13; | ||
const gasToken = testToken.address; | ||
const gasFeeAmount = 1000; | ||
const nativeGasFeeAmount = parseEther('1.0'); | ||
await testToken.connect(userWallet).approve(gasService.address, 1e6); | ||
await testToken.connect(userWallet).approve(gasService.address, 1e6); | ||
await expect(gasService.connect(userWallet).addGas(txHash, logIndex, gasToken, gasFeeAmount, userWallet.address)) | ||
.to.emit(gasService, 'GasAdded') | ||
.withArgs(txHash, logIndex, gasToken, gasFeeAmount, userWallet.address) | ||
.and.to.emit(testToken, 'Transfer') | ||
.withArgs(userWallet.address, gasService.address, gasFeeAmount); | ||
await expect(gasService.connect(userWallet).addGas(txHash, logIndex, gasToken, gasFeeAmount, userWallet.address)) | ||
.to.emit(gasService, 'GasAdded') | ||
.withArgs(txHash, logIndex, gasToken, gasFeeAmount, userWallet.address) | ||
.and.to.emit(testToken, 'Transfer') | ||
.withArgs(userWallet.address, gasService.address, gasFeeAmount); | ||
await expect(await gasService.connect(userWallet).addNativeGas(txHash, logIndex, userWallet.address, { value: nativeGasFeeAmount })) | ||
.to.emit(gasService, 'NativeGasAdded') | ||
.withArgs(txHash, logIndex, nativeGasFeeAmount, userWallet.address) | ||
.and.to.changeEtherBalance(gasService, nativeGasFeeAmount); | ||
await expect( | ||
await gasService.connect(userWallet).addNativeGas(txHash, logIndex, userWallet.address, { value: nativeGasFeeAmount }), | ||
) | ||
.to.emit(gasService, 'NativeGasAdded') | ||
.withArgs(txHash, logIndex, nativeGasFeeAmount, userWallet.address) | ||
.and.to.changeEtherBalance(gasService, nativeGasFeeAmount); | ||
}); | ||
}); | ||
}); |
@@ -12,2 +12,3 @@ 'use strict'; | ||
const { get } = require('lodash/fp'); | ||
const { deployUpgradable } = require('../../scripts/upgradable'); | ||
@@ -18,3 +19,3 @@ const CHAIN_ID = 1; | ||
const Auth = require('../../artifacts/contracts/AxelarAuthMultisig.sol/AxelarAuthMultisig.json'); | ||
const Auth = require('../../artifacts/contracts/auth/AxelarAuthWeighted.sol/AxelarAuthWeighted.json'); | ||
const TokenDeployer = require('../../artifacts/contracts/TokenDeployer.sol/TokenDeployer.json'); | ||
@@ -30,4 +31,6 @@ const AxelarGatewayProxy = require('../../artifacts/contracts/AxelarGatewayProxy.sol/AxelarGatewayProxy.json'); | ||
const DestinationChainTokenSwapper = require('../../artifacts/contracts/test/gmp/DestinationChainTokenSwapper.sol/DestinationChainTokenSwapper.json'); | ||
const { getAuthDeployParam, getSignedMultisigExecuteInput, getRandomID } = require('../utils'); | ||
const ConstAddressDeployer = require('axelar-utils-solidity/dist/ConstAddressDeployer.json'); | ||
const { getWeightedAuthDeployParam, getSignedWeightedExecuteInput, getRandomID } = require('../utils'); | ||
describe('GeneralMessagePassing', () => { | ||
@@ -77,3 +80,3 @@ const [ownerWallet, operatorWallet, userWallet, adminWallet1, adminWallet2, adminWallet3, adminWallet4, adminWallet5, adminWallet6] = | ||
); | ||
const auth = await deployContract(ownerWallet, Auth, [getAuthDeployParam([[operatorWallet.address]], [1])]); | ||
const auth = await deployContract(ownerWallet, Auth, [getWeightedAuthDeployParam([[operatorWallet.address]], [[1]], [1])]); | ||
const tokenDeployer = await deployContract(ownerWallet, TokenDeployer); | ||
@@ -111,7 +114,5 @@ const gateway = await deployContract(ownerWallet, AxelarGateway, [auth.address, tokenDeployer.address]); | ||
destinationChainGateway = await deployGateway(); | ||
const constAddressDeployer = await deployContract(ownerWallet, ConstAddressDeployer); | ||
const gasImplementation = await deployContract(ownerWallet, GasService); | ||
const gasProxy = await deployContract(ownerWallet, GasServiceProxy, [gasImplementation.address, arrayify([])]); | ||
sourceChainGasService = new Contract(gasProxy.address, GasService.abi, ownerWallet); | ||
sourceChainGasService = await deployUpgradable(constAddressDeployer.address, ownerWallet, GasService, GasServiceProxy); | ||
tokenA = await deployContract(ownerWallet, MintableCappedERC20, [nameA, symbolA, decimals, capacity]); | ||
@@ -122,6 +123,6 @@ | ||
await sourceChainGateway.execute( | ||
await getSignedMultisigExecuteInput(getTokenDeployData(false), [operatorWallet], [operatorWallet]), | ||
await getSignedWeightedExecuteInput(getTokenDeployData(false), [operatorWallet], [1], 1, [operatorWallet]), | ||
); | ||
await destinationChainGateway.execute( | ||
await getSignedMultisigExecuteInput(getTokenDeployData(true), [operatorWallet], [operatorWallet]), | ||
await getSignedWeightedExecuteInput(getTokenDeployData(true), [operatorWallet], [1], 1, [operatorWallet]), | ||
); | ||
@@ -152,3 +153,3 @@ | ||
await sourceChainGateway.execute( | ||
await getSignedMultisigExecuteInput(getMintData(symbolA, userWallet.address, 1e9), [operatorWallet], [operatorWallet]), | ||
await getSignedWeightedExecuteInput(getMintData(symbolA, userWallet.address, 1e9), [operatorWallet], [1], 1, [operatorWallet]), | ||
); | ||
@@ -229,3 +230,3 @@ await tokenA.connect(ownerWallet).mint(userWallet.address, 1e9); | ||
const approveExecute = await destinationChainGateway.execute( | ||
await getSignedMultisigExecuteInput(approveWithMintData, [operatorWallet], [operatorWallet]), | ||
await getSignedWeightedExecuteInput(approveWithMintData, [operatorWallet], [1], 1, [operatorWallet]), | ||
); | ||
@@ -353,3 +354,3 @@ | ||
const approveExecute = await destinationChainGateway.execute( | ||
await getSignedMultisigExecuteInput(approveWithMintData, [operatorWallet], [operatorWallet]), | ||
await getSignedWeightedExecuteInput(approveWithMintData, [operatorWallet], [1], 1, [operatorWallet]), | ||
); | ||
@@ -356,0 +357,0 @@ |
@@ -22,2 +22,13 @@ 'use strict'; | ||
const getWeightedSignaturesProof = async (data, operators, weights, threshold, signers) => { | ||
const hash = arrayify(keccak256(data)); | ||
const signatures = await Promise.all( | ||
sortBy(signers, (wallet) => wallet.address.toLowerCase()).map((wallet) => wallet.signMessage(hash)), | ||
); | ||
return defaultAbiCoder.encode( | ||
['address[]', 'uint256[]', 'uint256', 'bytes[]'], | ||
[getAddresses(operators), weights, threshold, signatures], | ||
); | ||
}; | ||
module.exports = { | ||
@@ -28,5 +39,10 @@ bigNumberToNumber: (bigNumber) => bigNumber.toNumber(), | ||
getWeightedSignaturesProof, | ||
getSignedMultisigExecuteInput: async (data, operators, signers) => | ||
defaultAbiCoder.encode(['bytes', 'bytes'], [data, await getSignaturesProof(data, operators, signers)]), | ||
getSignedWeightedExecuteInput: async (data, operators, weights, threshold, signers) => | ||
defaultAbiCoder.encode(['bytes', 'bytes'], [data, await getWeightedSignaturesProof(data, operators, weights, threshold, signers)]), | ||
getRandomInt, | ||
@@ -38,5 +54,10 @@ | ||
getAuthDeployParam: (operatorsSets, operatorThresholds) => | ||
operatorsSets.map((operators, i) => defaultAbiCoder.encode(['address[]', 'uint256'], [operators, operatorThresholds[i]])), | ||
getAuthDeployParam: (operatorSets, operatorThresholds) => | ||
operatorSets.map((operators, i) => defaultAbiCoder.encode(['address[]', 'uint256'], [operators, operatorThresholds[i]])), | ||
getWeightedAuthDeployParam: (operatorSets, weightSets, operatorThresholds) => | ||
operatorSets.map((operators, i) => | ||
defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [operators, weightSets[i], operatorThresholds[i]]), | ||
), | ||
getMultisigProxyDeployParams: (admins, adminThreshold, operators, operatorThreshold) => | ||
@@ -54,2 +75,16 @@ arrayify( | ||
getWeightedProxyDeployParams: (admins, adminThreshold, operators, weights, operatorThreshold) => | ||
arrayify( | ||
defaultAbiCoder.encode( | ||
['address[]', 'uint8', 'bytes'], | ||
[ | ||
admins, | ||
adminThreshold, | ||
operators.length | ||
? defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [operators, weights, operatorThreshold]) | ||
: '0x', | ||
], | ||
), | ||
), | ||
getDeployCommand: (name, symbol, decimals, cap, tokenAddress, dailyMintLimit) => | ||
@@ -68,2 +103,8 @@ defaultAbiCoder.encode( | ||
getTransferWeightedOperatorshipCommand: (newOperators, newWeights, threshold) => | ||
defaultAbiCoder.encode( | ||
['address[]', 'uint256[]', 'uint256'], | ||
[sortBy(newOperators, (address) => address.toLowerCase()), newWeights, threshold], | ||
), | ||
getApproveContractCall: (sourceChain, source, destination, payloadHash, sourceTxHash, sourceEventIndex) => | ||
@@ -70,0 +111,0 @@ defaultAbiCoder.encode( |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 9 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
378008
114
7485
1
19
82