From 40b3d6a5feff1e7a812b84d1d588f3241c8f3894 Mon Sep 17 00:00:00 2001 From: Kiryl Yermakou Date: Thu, 2 Nov 2023 19:14:40 -0400 Subject: [PATCH] refactor(Mocks): using mocks from CGP and SDK --- contracts/test/AxelarGasService.sol | 251 --------------------------- contracts/test/Imports.sol | 7 + contracts/test/MockAxelarGateway.sol | 123 ------------- scripts/deploy.js | 2 +- test/TokenService.js | 17 +- 5 files changed, 18 insertions(+), 382 deletions(-) delete mode 100644 contracts/test/AxelarGasService.sol create mode 100644 contracts/test/Imports.sol delete mode 100644 contracts/test/MockAxelarGateway.sol diff --git a/contracts/test/AxelarGasService.sol b/contracts/test/AxelarGasService.sol deleted file mode 100644 index 292254ec..00000000 --- a/contracts/test/AxelarGasService.sol +++ /dev/null @@ -1,251 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import { IERC20 } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IERC20.sol'; - -// This should be owned by the microservice that is paying for gas. -contract AxelarGasService { - error TransferFailed(); - error NothingReceived(); - error InvalidAddress(); - error InvalidAmounts(); - error NotCollector(); - - event GasPaidForContractCall( - address indexed sourceAddress, - string destinationChain, - string destinationAddress, - bytes32 indexed payloadHash, - address gasToken, - uint256 gasFeeAmount, - address refundAddress - ); - - event GasPaidForContractCallWithToken( - address indexed sourceAddress, - string destinationChain, - string destinationAddress, - bytes32 indexed payloadHash, - string symbol, - uint256 amount, - address gasToken, - uint256 gasFeeAmount, - address refundAddress - ); - - event NativeGasPaidForContractCall( - address indexed sourceAddress, - string destinationChain, - string destinationAddress, - bytes32 indexed payloadHash, - uint256 gasFeeAmount, - address refundAddress - ); - - event NativeGasPaidForContractCallWithToken( - address indexed sourceAddress, - string destinationChain, - string destinationAddress, - bytes32 indexed payloadHash, - string symbol, - uint256 amount, - uint256 gasFeeAmount, - address refundAddress - ); - - event GasPaidForExpressCallWithToken( - address indexed sourceAddress, - string destinationChain, - string destinationAddress, - bytes32 indexed payloadHash, - string symbol, - uint256 amount, - address gasToken, - uint256 gasFeeAmount, - address refundAddress - ); - - event NativeGasPaidForExpressCallWithToken( - address indexed sourceAddress, - string destinationChain, - string destinationAddress, - bytes32 indexed payloadHash, - string symbol, - uint256 amount, - uint256 gasFeeAmount, - address refundAddress - ); - - event GasAdded(bytes32 indexed txHash, uint256 indexed logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress); - - event NativeGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, uint256 gasFeeAmount, address refundAddress); - - event ExpressGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress); - - event NativeExpressGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, uint256 gasFeeAmount, address refundAddress); - - address public immutable gasCollector; - - constructor(address gasCollector_) { - gasCollector = gasCollector_; - } - - modifier onlyCollector() { - if (msg.sender != gasCollector) revert NotCollector(); - - _; - } - - // This is called on the source chain before calling the gateway to execute a remote contract. - function payGasForContractCall( - address sender, - string calldata destinationChain, - string calldata destinationAddress, - bytes calldata payload, - address gasToken, - uint256 gasFeeAmount, - address refundAddress - ) external { - _safeTransferFrom(gasToken, msg.sender, gasFeeAmount); - - emit GasPaidForContractCall( - sender, - destinationChain, - destinationAddress, - keccak256(payload), - gasToken, - gasFeeAmount, - refundAddress - ); - } - - // This is called on the source chain before calling the gateway to execute a remote contract. - function payGasForContractCallWithToken( - address sender, - string calldata destinationChain, - string calldata destinationAddress, - bytes calldata payload, - string memory symbol, - uint256 amount, - address gasToken, - uint256 gasFeeAmount, - address refundAddress - ) external { - _safeTransferFrom(gasToken, msg.sender, gasFeeAmount); - - emit GasPaidForContractCallWithToken( - sender, - destinationChain, - destinationAddress, - keccak256(payload), - symbol, - amount, - gasToken, - gasFeeAmount, - refundAddress - ); - } - - // This is called on the source chain before calling the gateway to execute a remote contract. - function payNativeGasForContractCall( - address sender, - string calldata destinationChain, - string calldata destinationAddress, - bytes calldata payload, - address refundAddress - ) external payable { - if (msg.value == 0) revert NothingReceived(); - - emit NativeGasPaidForContractCall(sender, destinationChain, destinationAddress, keccak256(payload), msg.value, refundAddress); - } - - // This is called on the source chain before calling the gateway to execute a remote contract. - function payNativeGasForContractCallWithToken( - address sender, - string calldata destinationChain, - string calldata destinationAddress, - bytes calldata payload, - string calldata symbol, - uint256 amount, - address refundAddress - ) external payable { - if (msg.value == 0) revert NothingReceived(); - - emit NativeGasPaidForContractCallWithToken( - sender, - destinationChain, - destinationAddress, - keccak256(payload), - symbol, - amount, - msg.value, - refundAddress - ); - } - - function addGas(bytes32 txHash, uint256 logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress) external { - _safeTransferFrom(gasToken, msg.sender, gasFeeAmount); - - emit GasAdded(txHash, logIndex, gasToken, gasFeeAmount, refundAddress); - } - - function addNativeGas(bytes32 txHash, uint256 logIndex, address refundAddress) external payable { - if (msg.value == 0) revert NothingReceived(); - - emit NativeGasAdded(txHash, logIndex, msg.value, refundAddress); - } - - function collectFees(address payable receiver, address[] calldata tokens, uint256[] calldata amounts) external onlyCollector { - if (receiver == address(0)) revert InvalidAddress(); - - uint256 tokensLength = tokens.length; - if (tokensLength != amounts.length) revert InvalidAmounts(); - - for (uint256 i; i < tokensLength; i++) { - address token = tokens[i]; - uint256 amount = amounts[i]; - if (amount == 0) revert InvalidAmounts(); - - if (token == address(0)) { - if (amount <= address(this).balance) receiver.transfer(amount); - } else { - if (amount <= IERC20(token).balanceOf(address(this))) _safeTransfer(token, receiver, amount); - } - } - } - - function refund(address payable receiver, address token, uint256 amount) external onlyCollector { - if (receiver == address(0)) revert InvalidAddress(); - - if (token == address(0)) { - receiver.transfer(amount); - } else { - _safeTransfer(token, receiver, amount); - } - } - - function _safeTransfer(address tokenAddress, address receiver, uint256 amount) internal { - if (amount == 0) revert NothingReceived(); - - (bool success, bytes memory returnData) = tokenAddress.call(abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount)); - bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool))); - - if (!transferred || tokenAddress.code.length == 0) revert TransferFailed(); - } - - function _safeTransferFrom(address tokenAddress, address from, uint256 amount) internal { - if (amount == 0) revert NothingReceived(); - - (bool success, bytes memory returnData) = tokenAddress.call( - abi.encodeWithSelector(IERC20.transferFrom.selector, from, address(this), amount) - ); - bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool))); - - if (!transferred || tokenAddress.code.length == 0) revert TransferFailed(); - } - - function contractId() external pure returns (bytes32) { - return keccak256('axelar-gas-service'); - } -} diff --git a/contracts/test/Imports.sol b/contracts/test/Imports.sol new file mode 100644 index 00000000..8281c493 --- /dev/null +++ b/contracts/test/Imports.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +// solhint-disable no-unused-import +import { MockGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/test/mocks/MockGateway.sol'; +import { AxelarGasService } from '@axelar-network/axelar-cgp-solidity/contracts/gas-service/AxelarGasService.sol'; diff --git a/contracts/test/MockAxelarGateway.sol b/contracts/test/MockAxelarGateway.sol deleted file mode 100644 index be7cfd20..00000000 --- a/contracts/test/MockAxelarGateway.sol +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import { IMockAxelarGateway } from '../interfaces/IMockAxelarGateway.sol'; - -contract MockAxelarGateway is IMockAxelarGateway { - mapping(bytes32 => address) private _addressStorage; - mapping(bytes32 => bool) private _boolStorage; - - bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed'); - bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address'); - bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type'); - bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved'); - bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint'); - - /******************\ - |* Public Methods *| - \******************/ - - function callContract(string calldata destinationChain, string calldata destinationContractAddress, bytes calldata payload) external { - emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload); - } - - function isContractCallApproved( - bytes32 commandId, - string calldata sourceChain, - string calldata sourceAddress, - address contractAddress, - bytes32 payloadHash - ) external view override returns (bool) { - return _boolStorage[_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash)]; - } - - function validateContractCall( - bytes32 commandId, - string calldata sourceChain, - string calldata sourceAddress, - bytes32 payloadHash - ) external override returns (bool valid) { - bytes32 key = _getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash); - valid = _boolStorage[key]; - if (valid) _boolStorage[key] = false; - } - - /***********\ - |* Getters *| - \***********/ - - function isCommandExecuted(bytes32 commandId) public view override returns (bool) { - return _boolStorage[_getIsCommandExecutedKey(commandId)]; - } - - function tokenAddresses(string calldata symbol) external view returns (address tokenAddress) { - tokenAddress = _addressStorage[_tokenAddressKey(symbol)]; - } - - /********************\ - |* Setter Functions *| - \********************/ - - function approveContractCall(bytes calldata params, bytes32 commandId) external { - ( - string memory sourceChain, - string memory sourceAddress, - address contractAddress, - bytes32 payloadHash, - bytes32 sourceTxHash, - uint256 sourceEventIndex - ) = abi.decode(params, (string, string, address, bytes32, bytes32, uint256)); - - _setContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash); - emit ContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, sourceTxHash, sourceEventIndex); - } - - function setTokenAddress(string calldata symbol, address tokenAddress) external { - _addressStorage[_tokenAddressKey(symbol)] = tokenAddress; - } - - function setCommandExecuted(bytes32 commandId, bool executed) external { - _setCommandExecuted(commandId, executed); - } - - /********************\ - |* Pure Key Getters *| - \********************/ - - function _getIsCommandExecutedKey(bytes32 commandId) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(PREFIX_COMMAND_EXECUTED, commandId)); - } - - function _getIsContractCallApprovedKey( - bytes32 commandId, - string memory sourceChain, - string memory sourceAddress, - address contractAddress, - bytes32 payloadHash - ) internal pure returns (bytes32) { - return keccak256(abi.encode(PREFIX_CONTRACT_CALL_APPROVED, commandId, sourceChain, sourceAddress, contractAddress, payloadHash)); - } - - function _tokenAddressKey(string memory symbol) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(PREFIX_TOKEN_ADDRESS, symbol)); - } - - /********************\ - |* Internal Setters *| - \********************/ - - function _setCommandExecuted(bytes32 commandId, bool executed) internal { - _boolStorage[_getIsCommandExecutedKey(commandId)] = executed; - } - - function _setContractCallApproved( - bytes32 commandId, - string memory sourceChain, - string memory sourceAddress, - address contractAddress, - bytes32 payloadHash - ) internal { - _boolStorage[_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash)] = true; - } -} diff --git a/scripts/deploy.js b/scripts/deploy.js index 2261e8ea..e1a2b03a 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -22,7 +22,7 @@ async function deployAddressTracker(wallet, chainName, interchainTokenServiceAdd } async function deployMockGateway(wallet) { - const gateway = await deployContract(wallet, 'MockAxelarGateway'); + const gateway = await deployContract(wallet, 'MockGateway'); return gateway; } diff --git a/test/TokenService.js b/test/TokenService.js index 7d6b0942..e0aa96f8 100644 --- a/test/TokenService.js +++ b/test/TokenService.js @@ -1627,7 +1627,6 @@ describe('Interchain Token Service', () => { ); const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - await gateway.setCommandExecuted(commandId, true).then((tx) => tx.wait()); await expectRevert( (gasOptions) => service.expressExecute(commandId, sourceChain, sourceAddress, payload, gasOptions), @@ -1664,9 +1663,10 @@ describe('Interchain Token Service', () => { ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256'], [SELECTOR_RECEIVE_TOKEN, tokenId, hexlify(wallet.address), destAddress, amount], ); - const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); + const commandId = getRandomBytes32(); await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer') @@ -1684,9 +1684,10 @@ describe('Interchain Token Service', () => { ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256'], [SELECTOR_RECEIVE_TOKEN, tokenId, hexlify(wallet.address), destAddress, amount], ); - const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); + const commandId = getRandomBytes32(); await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer') @@ -1704,9 +1705,10 @@ describe('Interchain Token Service', () => { ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256'], [SELECTOR_RECEIVE_TOKEN, tokenId, hexlify(wallet.address), destAddress, amount], ); - const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); + const commandId = getRandomBytes32(); await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer') @@ -1740,9 +1742,10 @@ describe('Interchain Token Service', () => { ['uint256', 'bytes32', 'bytes', 'bytes', 'uint256', 'bytes'], [SELECTOR_RECEIVE_TOKEN_WITH_DATA, tokenId, sourceAddressForService, destAddress, amount, data], ); - const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); + const commandId = getRandomBytes32(); await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); const tx = service.execute(commandId, sourceChain, sourceAddress, payload); await expect(tx) @@ -1765,9 +1768,9 @@ describe('Interchain Token Service', () => { [SELECTOR_RECEIVE_TOKEN_WITH_DATA, tokenId, sourceAddressForService, destAddress, amount, data], ); - const commandId = await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload); - + const commandId = getRandomBytes32(); await (await service.expressExecute(commandId, sourceChain, sourceAddress, payload)).wait(); + await approveContractCall(gateway, sourceChain, sourceAddress, service.address, payload, getRandomBytes32(), 0, commandId); await expect(service.execute(commandId, sourceChain, sourceAddress, payload)) .to.emit(token, 'Transfer')