Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' 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 f9734a0 + ba744ca commit e005136
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 179 deletions.
49 changes: 12 additions & 37 deletions contracts/InterchainTokenService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { Pausable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/util
import { InterchainAddressTracker } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/InterchainAddressTracker.sol';

import { IInterchainTokenService } from './interfaces/IInterchainTokenService.sol';
import { ITokenManagerProxy } from './interfaces/ITokenManagerProxy.sol';
import { ITokenHandler } from './interfaces/ITokenHandler.sol';
import { ITokenManagerDeployer } from './interfaces/ITokenManagerDeployer.sol';
import { IInterchainTokenDeployer } from './interfaces/IInterchainTokenDeployer.sol';
Expand Down Expand Up @@ -393,21 +392,11 @@ contract InterchainTokenService is

IERC20 token;
{
ITokenManager tokenManager_ = ITokenManager(tokenManagerAddress(tokenId));
token = IERC20(tokenManager_.tokenAddress());

(bool success, bytes memory returnData) = tokenHandler.delegatecall(
abi.encodeWithSelector(
ITokenHandler.transferTokenFrom.selector,
tokenManager_.implementationType(),
address(token),
msg.sender,
destinationAddress,
amount
)
abi.encodeWithSelector(ITokenHandler.transferTokenFrom.selector, tokenId, msg.sender, destinationAddress, amount)
);
if (!success) revert TokenHandlerFailed(returnData);
amount = abi.decode(returnData, (uint256));
(amount, token) = abi.decode(returnData, (uint256, IERC20));
}

// slither-disable-next-line reentrancy-events
Expand Down Expand Up @@ -929,8 +918,6 @@ contract InterchainTokenService is
) internal {
bytes32 payloadHash = keccak256(payload);

address expressExecutor = _getExpressExecutorAndEmitEvent(commandId, sourceChain, sourceAddress, payloadHash);

if (!gateway.validateContractCallAndMint(commandId, sourceChain, sourceAddress, payloadHash, tokenSymbol, amount))
revert NotApprovedByGateway();

Expand All @@ -941,6 +928,9 @@ contract InterchainTokenService is

_checkPayloadAgainstGatewayData(payload, tokenSymbol, amount);

// slither-disable-next-line reentrancy-events
address expressExecutor = _getExpressExecutorAndEmitEvent(commandId, sourceChain, sourceAddress, payloadHash);

_processInterchainTransferPayload(commandId, expressExecutor, sourceChain, payload);
}

Expand Down Expand Up @@ -1141,39 +1131,24 @@ contract InterchainTokenService is
* @dev Takes token from a sender via the token service. `tokenOnly` indicates if the caller should be restricted to the token only.
*/
function _takeToken(bytes32 tokenId, address from, uint256 amount, bool tokenOnly) internal returns (uint256, string memory symbol) {
address tokenManager_ = tokenManagerAddress(tokenId);
uint256 tokenManagerType;
address tokenAddress;

(tokenManagerType, tokenAddress) = ITokenManagerProxy(tokenManager_).getImplementationTypeAndTokenAddress();

if (tokenOnly && msg.sender != tokenAddress) revert NotToken(msg.sender, tokenAddress);

(bool success, bytes memory data) = tokenHandler.delegatecall(
abi.encodeWithSelector(ITokenHandler.takeToken.selector, tokenManagerType, tokenAddress, tokenManager_, from, amount)
abi.encodeWithSelector(ITokenHandler.takeToken.selector, tokenId, tokenOnly, from, amount)
);
if (!success) revert TakeTokenFailed(data);
amount = abi.decode(data, (uint256));
(amount, symbol) = abi.decode(data, (uint256, string));

if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) {
symbol = IERC20Named(tokenAddress).symbol();
}
return (amount, symbol);
}

/**
* @dev Gives token to recipient via the token service.
*/
function _giveToken(bytes32 tokenId, address to, uint256 amount) internal returns (uint256, address) {
address tokenManager_ = tokenManagerAddress(tokenId);

(uint256 tokenManagerType, address tokenAddress) = ITokenManagerProxy(tokenManager_).getImplementationTypeAndTokenAddress();

function _giveToken(bytes32 tokenId, address to, uint256 amount) internal returns (uint256, address tokenAddress) {
(bool success, bytes memory data) = tokenHandler.delegatecall(
abi.encodeWithSelector(ITokenHandler.giveToken.selector, tokenManagerType, tokenAddress, tokenManager_, to, amount)
abi.encodeWithSelector(ITokenHandler.giveToken.selector, tokenId, to, amount)
);
if (!success) revert GiveTokenFailed(data);
amount = abi.decode(data, (uint256));
(amount, tokenAddress) = abi.decode(data, (uint256, address));

return (amount, tokenAddress);
}
Expand All @@ -1196,8 +1171,8 @@ contract InterchainTokenService is

function _getExpressExecutorAndEmitEvent(
bytes32 commandId,
string memory sourceChain,
string memory sourceAddress,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) internal returns (address expressExecutor) {
expressExecutor = _popExpressExecutor(commandId, sourceChain, sourceAddress, payloadHash);
Expand Down
99 changes: 46 additions & 53 deletions contracts/TokenHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ 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 { Create3AddressFixed } from './utils/Create3AddressFixed.sol';

import { ITokenManagerType } from './interfaces/ITokenManagerType.sol';
import { ITokenManager } from './interfaces/ITokenManager.sol';
import { ITokenManagerProxy } from './interfaces/ITokenManagerProxy.sol';
import { IERC20MintableBurnable } from './interfaces/IERC20MintableBurnable.sol';
import { IERC20BurnableFrom } from './interfaces/IERC20BurnableFrom.sol';
import { IERC20Named } from './interfaces/IERC20Named.sol';

/**
* @title TokenHandler
* @notice This interface is responsible for handling tokens before initiating an interchain token transfer, or after receiving one.
*/
contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard {
contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard, Create3AddressFixed {
using SafeTokenTransferFrom for IERC20;
using SafeTokenCall for IERC20;
using SafeTokenTransfer for IERC20;
Expand All @@ -32,125 +35,115 @@ contract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard {

/**
* @notice This function gives token to a specified address from the token manager.
* @param tokenManagerType The token manager type.
* @param tokenAddress The address of the token to give.
* @param tokenManager The address of the token manager.
* @param tokenId The token id of the tokenManager.
* @param to The address to give tokens to.
* @param amount The amount of tokens to give.
* @return uint256 The amount of token actually given, which could be different for certain token type.
* @return address the address of the token.
*/
// slither-disable-next-line locked-ether
function giveToken(
uint256 tokenManagerType,
address tokenAddress,
address tokenManager,
address to,
uint256 amount
) external payable returns (uint256) {
function giveToken(bytes32 tokenId, address to, uint256 amount) external payable returns (uint256, address) {
address tokenManager = _create3Address(tokenId);

(uint256 tokenManagerType, address tokenAddress) = ITokenManagerProxy(tokenManager).getImplementationTypeAndTokenAddress();

/// @dev Track the flow amount being received via the message
ITokenManager(tokenManager).addFlowIn(amount);

if (tokenManagerType == uint256(TokenManagerType.MINT_BURN) || tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM)) {
_giveTokenMintBurn(tokenAddress, to, amount);
return amount;
return (amount, tokenAddress);
}

if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK)) {
_transferTokenFrom(tokenAddress, tokenManager, to, amount);
return amount;
return (amount, tokenAddress);
}

if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK_FEE)) {
amount = _transferTokenFromWithFee(tokenAddress, tokenManager, to, amount);
return amount;
return (amount, tokenAddress);
}

if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) {
_transferToken(tokenAddress, to, amount);
return amount;
return (amount, tokenAddress);
}

revert UnsupportedTokenManagerType(tokenManagerType);
}

/**
* @notice This function takes token from a specified address to the token manager.
* @param tokenManagerType The token manager type.
* @param tokenAddress The address of the token to give.
* @param tokenManager The address of the token manager.
* @param tokenId The tokenId for the token.
* @param tokenOnly can only be called from the token.
* @param from The address to take tokens from.
* @param amount The amount of token to take.
* @return uint256 The amount of token actually taken, which could be different for certain token type.
* @return symbol The symbol for the token, if not empty the token is a gateway token and a callContractWith token has to be made.
*/
// slither-disable-next-line locked-ether
function takeToken(
uint256 tokenManagerType,
address tokenAddress,
address tokenManager,
bytes32 tokenId,
bool tokenOnly,
address from,
uint256 amount
) external payable returns (uint256) {
/// @dev Track the flow amount being sent out as a message
ITokenManager(tokenManager).addFlowOut(amount);
) external payable returns (uint256, string memory symbol) {
address tokenManager = _create3Address(tokenId);

(uint256 tokenManagerType, address tokenAddress) = ITokenManagerProxy(tokenManager).getImplementationTypeAndTokenAddress();

if (tokenOnly && msg.sender != tokenAddress) revert NotToken(msg.sender, tokenAddress);

if (tokenManagerType == uint256(TokenManagerType.MINT_BURN)) {
_takeTokenMintBurn(tokenAddress, from, amount);
return amount;
}

if (tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM)) {
} else if (tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM)) {
_takeTokenMintBurnFrom(tokenAddress, from, amount);
return amount;
}

if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK)) {
} else if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK)) {
_transferTokenFrom(tokenAddress, from, tokenManager, amount);
return amount;
}

if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK_FEE)) {
} else if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK_FEE)) {
amount = _transferTokenFromWithFee(tokenAddress, from, tokenManager, amount);
return amount;
}

if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) {
} else if (tokenManagerType == uint256(TokenManagerType.GATEWAY)) {
symbol = IERC20Named(tokenAddress).symbol();
_transferTokenFrom(tokenAddress, from, address(this), amount);
return amount;
} else {
revert UnsupportedTokenManagerType(tokenManagerType);
}

revert UnsupportedTokenManagerType(tokenManagerType);
/// @dev Track the flow amount being sent out as a message
ITokenManager(tokenManager).addFlowOut(amount);

return (amount, symbol);
}

/**
* @notice This function transfers token from and to a specified address.
* @param tokenManagerType The token manager type.
* @param tokenAddress the address of the token to give.
* @param tokenId The token id of the token manager.
* @param from The address to transfer tokens from.
* @param to The address to transfer tokens to.
* @param amount The amount of token to transfer.
* @return uint256 The amount of token actually transferred, which could be different for certain token type.
* @return address The address of the token corresponding to the input tokenId.
*/
// slither-disable-next-line locked-ether
function transferTokenFrom(
uint256 tokenManagerType,
address tokenAddress,
address from,
address to,
uint256 amount
) external payable returns (uint256) {
function transferTokenFrom(bytes32 tokenId, address from, address to, uint256 amount) external payable returns (uint256, address) {
address tokenManager = _create3Address(tokenId);

(uint256 tokenManagerType, address tokenAddress) = ITokenManagerProxy(tokenManager).getImplementationTypeAndTokenAddress();

if (
tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK) ||
tokenManagerType == uint256(TokenManagerType.MINT_BURN) ||
tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM) ||
tokenManagerType == uint256(TokenManagerType.GATEWAY)
) {
_transferTokenFrom(tokenAddress, from, to, amount);
return amount;
return (amount, tokenAddress);
}

if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK_FEE)) {
amount = _transferTokenFromWithFee(tokenAddress, from, to, amount);
return amount;
return (amount, tokenAddress);
}

revert UnsupportedTokenManagerType(tokenManagerType);
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IInterchainTokenService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ interface IInterchainTokenService is
error InvalidChainName();
error NotRemoteService();
error TokenManagerDoesNotExist(bytes32 tokenId);
error NotToken(address caller, address token);
error ExecuteWithInterchainTokenFailed(address contractAddress);
error ExpressExecuteWithInterchainTokenFailed(address contractAddress);
error GatewayToken();
Expand All @@ -49,6 +48,7 @@ interface IInterchainTokenService is
error PostDeployFailed(bytes data);
error InvalidGatewayTokenTransfer(bytes32 tokenId, bytes payload, string tokenSymbol, uint256 amount);
error ZeroAmount();
error InvalidGatewayTokenTransfer(bytes32 tokenId, bytes payload, string tokenSymbol, uint256 amount);

event InterchainTransfer(
bytes32 indexed tokenId,
Expand Down
41 changes: 15 additions & 26 deletions contracts/interfaces/ITokenHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pragma solidity ^0.8.0;
interface ITokenHandler {
error UnsupportedTokenManagerType(uint256 tokenManagerType);
error AddressZero();
error NotToken(address caller, address token);

/**
* @notice Returns the address of the axelar gateway on this chain.
Expand All @@ -18,54 +19,42 @@ interface ITokenHandler {

/**
* @notice This function gives token to a specified address from the token manager.
* @param tokenManagerType The token manager type.
* @param tokenAddress The address of the token to give.
* @param tokenManager The address of the token manager.
* @param tokenId The token id of the tokenManager.
* @param to The address to give tokens to.
* @param amount The amount of tokens to give.
* @return uint256 The amount of token actually given, which could be different for certain token type.
* @return address the address of the token.
*/
function giveToken(
uint256 tokenManagerType,
address tokenAddress,
address tokenManager,
address to,
uint256 amount
) external payable returns (uint256);
function giveToken(bytes32 tokenId, address to, uint256 amount) external payable returns (uint256, address);

/**
* @notice This function takes token from a specified address to the token manager.
* @param tokenManagerType The token manager type.
* @param tokenAddress The address of the token to give.
* @param tokenManager The address of the token manager.
* @param tokenId The tokenId for the token.
* @param tokenOnly can only be called from the token.
* @param from The address to take tokens from.
* @param amount The amount of token to take.
* @return uint256 The amount of token actually taken, which could be different for certain token type.
* @return symbol The symbol for the token, if not empty the token is a gateway token and a callContractWith token has to be made.
*/
// slither-disable-next-line locked-ether
function takeToken(
uint256 tokenManagerType,
address tokenAddress,
address tokenManager,
bytes32 tokenId,
bool tokenOnly,
address from,
uint256 amount
) external payable returns (uint256);
) external payable returns (uint256, string memory symbol);

/**
* @notice This function transfers token from and to a specified address.
* @param tokenManagerType The token manager type.
* @param tokenAddress the address of the token to give.
* @param tokenId The token id of the token manager.
* @param from The address to transfer tokens from.
* @param to The address to transfer tokens to.
* @param amount The amount of token to transfer.
* @return uint256 The amount of token actually transferred, which could be different for certain token type.
* @return address The address of the token corresponding to the input tokenId.
*/
function transferTokenFrom(
uint256 tokenManagerType,
address tokenAddress,
address from,
address to,
uint256 amount
) external payable returns (uint256);
// slither-disable-next-line locked-ether
function transferTokenFrom(bytes32 tokenId, address from, address to, uint256 amount) external payable returns (uint256, address);

/**
* @notice This function prepares a token manager after it is deployed
Expand Down
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: 600, // Reduce runs to keep bytecode size under limit
},
},
};
Expand Down
Loading

0 comments on commit e005136

Please sign in to comment.