Skip to content

Commit

Permalink
Merge branch 'feat/reduce-codesize' into feat/wrap-payload
Browse files Browse the repository at this point in the history
  • Loading branch information
Foivos committed Apr 15, 2024
2 parents 5b0dd0f + 490b8c0 commit faddc28
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 57 deletions.
74 changes: 24 additions & 50 deletions contracts/InterchainTokenService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -814,29 +814,17 @@ contract InterchainTokenService is
destinationAddress = trustedAddress(destinationChain);
}

if (gasValue > 0) {
if (metadataVersion == MetadataVersion.CONTRACT_CALL) {
gasService.payNativeGasForContractCall{ value: gasValue }(
address(this),
destinationChain,
destinationAddress,
payload, // solhint-disable-next-line avoid-tx-origin
tx.origin
);
} else if (metadataVersion == MetadataVersion.EXPRESS_CALL) {
gasService.payNativeGasForExpressCall{ value: gasValue }(
address(this),
destinationChain,
destinationAddress,
payload, // solhint-disable-next-line avoid-tx-origin
tx.origin
);
} else {
revert InvalidMetadataVersion(uint32(metadataVersion));
}
}

gateway.callContract(destinationChain, destinationAddress, payload);
(bool success, ) = tokenHandler.delegatecall(
abi.encodeWithSelector(
ITokenHandler.callContract.selector,
destinationChain,
destinationAddress,
payload,
metadataVersion,
gasValue
)
);
if (!success) revert CallContractFailed();
}

/**
Expand All @@ -862,33 +850,19 @@ contract InterchainTokenService is
destinationAddress = trustedAddress(destinationChain);
}

if (gasValue > 0) {
if (metadataVersion == MetadataVersion.CONTRACT_CALL) {
gasService.payNativeGasForContractCallWithToken{ value: gasValue }(
address(this),
destinationChain,
destinationAddress,
payload,
symbol,
amount, // solhint-disable-next-line avoid-tx-origin
tx.origin
);
} else if (metadataVersion == MetadataVersion.EXPRESS_CALL) {
gasService.payNativeGasForExpressCallWithToken{ value: gasValue }(
address(this),
destinationChain,
destinationAddress,
payload,
symbol,
amount, // solhint-disable-next-line avoid-tx-origin
tx.origin
);
} else {
revert InvalidMetadataVersion(uint32(metadataVersion));
}
}

gateway.callContractWithToken(destinationChain, destinationAddress, payload, symbol, amount);
(bool success, ) = tokenHandler.delegatecall(
abi.encodeWithSelector(
ITokenHandler.callContractWithToken.selector,
destinationChain,
destinationAddress,
payload,
symbol,
amount,
metadataVersion,
gasValue
)
);
if (!success) revert CallContractFailed();
}

function _execute(
Expand Down
78 changes: 76 additions & 2 deletions contracts/TokenHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { ITokenHandler } from './interfaces/ITokenHandler.sol';
import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
import { SafeTokenTransfer, SafeTokenTransferFrom, SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
import { ReentrancyGuard } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/ReentrancyGuard.sol';
import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol';
import { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol';
import { Create3AddressFixed } from './utils/Create3AddressFixed.sol';

import { ITokenManagerType } from './interfaces/ITokenManagerType.sol';
Expand All @@ -25,12 +27,14 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard, Crea
using SafeTokenTransfer for IERC20;

address public immutable gateway;
address public immutable gasService;

uint256 internal constant UINT256_MAX = type(uint256).max;

constructor(address gateway_) {
if (gateway_ == address(0)) revert AddressZero();
constructor(address gateway_, address gasService_) {
if (gateway_ == address(0) || gasService_ == address(0)) revert AddressZero();
gateway = gateway_;
gasService = gasService_;
}

/**
Expand Down Expand Up @@ -173,6 +177,76 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard, Crea
}
}

function callContract(
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
MetadataVersion metadataVersion,
uint256 gasValue
) external payable {
if (gasValue > 0) {
if (metadataVersion == MetadataVersion.CONTRACT_CALL) {
IAxelarGasService(gasService).payNativeGasForContractCall{ value: gasValue }(
address(this),
destinationChain,
destinationAddress,
payload, // solhint-disable-next-line avoid-tx-origin
tx.origin
);
} else if (metadataVersion == MetadataVersion.EXPRESS_CALL) {
IAxelarGasService(gasService).payNativeGasForExpressCall{ value: gasValue }(
address(this),
destinationChain,
destinationAddress,
payload, // solhint-disable-next-line avoid-tx-origin
tx.origin
);
} else {
revert InvalidMetadataVersion(uint32(metadataVersion));
}
}

IAxelarGateway(gateway).callContract(destinationChain, destinationAddress, payload);
}

function callContractWithToken(
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
MetadataVersion metadataVersion,
uint256 gasValue
) external payable {
if (gasValue > 0) {
if (metadataVersion == MetadataVersion.CONTRACT_CALL) {
IAxelarGasService(gasService).payNativeGasForContractCallWithToken{ value: gasValue }(
address(this),
destinationChain,
destinationAddress,
payload,
symbol,
amount, // solhint-disable-next-line avoid-tx-origin
tx.origin
);
} else if (metadataVersion == MetadataVersion.EXPRESS_CALL) {
IAxelarGasService(gasService).payNativeGasForExpressCallWithToken{ value: gasValue }(
address(this),
destinationChain,
destinationAddress,
payload,
symbol,
amount, // solhint-disable-next-line avoid-tx-origin
tx.origin
);
} else {
revert InvalidMetadataVersion(uint32(metadataVersion));
}
}

IAxelarGateway(gateway).callContractWithToken(destinationChain, destinationAddress, payload, symbol, amount);
}

function _transferTokenFrom(address tokenAddress, address from, address to, uint256 amount) internal {
// slither-disable-next-line arbitrary-send-erc20
IERC20(tokenAddress).safeTransferFrom(from, to, amount);
Expand Down
1 change: 1 addition & 0 deletions contracts/interfaces/IInterchainTokenService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ interface IInterchainTokenService is
error ZeroAmount();
error CannotDeploy(TokenManagerType);
error InvalidGatewayTokenTransfer(bytes32 tokenId, bytes payload, string tokenSymbol, uint256 amount);
error CallContractFailed();

event InterchainTransfer(
bytes32 indexed tokenId,
Expand Down
42 changes: 42 additions & 0 deletions contracts/interfaces/ITokenHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ interface ITokenHandler {
error UnsupportedTokenManagerType(uint256 tokenManagerType);
error AddressZero();
error NotToken(address caller, address token);
error InvalidMetadataVersion(uint32 version);

enum MetadataVersion {
CONTRACT_CALL,
EXPRESS_CALL
}

/**
* @notice Returns the address of the axelar gateway on this chain.
Expand Down Expand Up @@ -62,4 +68,40 @@ interface ITokenHandler {
* @param tokenManager The address of the token manager.
*/
function postTokenManagerDeploy(uint256 tokenManagerType, address tokenManager) external payable;

/**
* @notice This function pays gas to the gas service and calls the gateway to transmit a CallContract.
* @param destinationChain The destination chain.
* @param destinationAddress The destination address.
* @param payload The payload to transmit.
* @param metadataVersion The metadata version is used to determine how to pay for gas.
* @param gasValue how much gas to pay.
*/
function callContract(
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
MetadataVersion metadataVersion,
uint256 gasValue
) external payable;

/**
* @notice This function pays gas to the gas service and calls the gateway to transmit a CallContractWithToken.
* @param destinationChain The destination chain.
* @param destinationAddress The destination address.
* @param payload The payload to transmit.
* @param metadataVersion The metadata version is used to determine how to pay for gas.
* @param symbol The gateway symbol.
* @param amount The amount of token to send.
* @param gasValue how much gas to pay.
*/
function callContractWithToken(
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
MetadataVersion metadataVersion,
uint256 gasValue
) external payable;
}
2 changes: 1 addition & 1 deletion hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const itsCompilerSettings = {
evmVersion: process.env.EVM_VERSION || 'london',
optimizer: {
...optimizerSettings,
runs: 1, // Reduce runs to keep bytecode size under limit
runs: 1000, // Reduce runs to keep bytecode size under limit
},
},
};
Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ async function deployAll(
const interchainToken = await deployContract(wallet, 'InterchainToken', [interchainTokenServiceAddress]);
const interchainTokenDeployer = await deployContract(wallet, 'InterchainTokenDeployer', [interchainToken.address]);
const tokenManager = await deployContract(wallet, 'TokenManager', [interchainTokenServiceAddress]);
const tokenHandler = await deployContract(wallet, 'TokenHandler', [gateway.address]);
const tokenHandler = await deployContract(wallet, 'TokenHandler', [gateway.address, gasService.address]);

const interchainTokenFactoryAddress = await getCreate3Address(create3Deployer.address, wallet, factoryDeploymentKey);

Expand Down
10 changes: 8 additions & 2 deletions test/InterchainTokenService.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,15 @@ describe('Interchain Token Service', () => {
});

describe('Interchain Token Service Deployment', () => {
it('Should revert on token handler deployment with invalid gateway address', async () => {
it('Should revert on token handler deployment with invalid gateway or gas service address', async () => {
await expectRevert(
(gasOptions) => deployContract(wallet, 'TokenHandler', [AddressZero, gasOptions]),
(gasOptions) => deployContract(wallet, 'TokenHandler', [AddressZero, gasService.address, gasOptions]),
tokenHandler,
'AddressZero',
);

await expectRevert(
(gasOptions) => deployContract(wallet, 'TokenHandler', [gateway.address, AddressZero, gasOptions]),
tokenHandler,
'AddressZero',
);
Expand Down
2 changes: 1 addition & 1 deletion test/InterchainTokenServiceUpgradeFlow.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('Interchain Token Service Upgrade Flow', () => {
tokenManagerDeployer = await deployContract(wallet, 'TokenManagerDeployer', []);
interchainTokenDeployer = await deployContract(wallet, 'InterchainTokenDeployer', [interchainToken.address]);
tokenManager = await deployContract(wallet, 'TokenManager', [interchainTokenServiceAddress]);
tokenHandler = await deployContract(wallet, 'TokenHandler', [gateway.address]);
tokenHandler = await deployContract(wallet, 'TokenHandler', [gateway.address, gasService.address]);
interchainTokenFactoryAddress = await getCreate3Address(create3Deployer.address, wallet, deploymentKey + 'Factory');

axelarServiceGovernanceFactory = await ethers.getContractFactory(
Expand Down

0 comments on commit faddc28

Please sign in to comment.