概述
ICS20 预编译为跨链通信协议(IBC)提供了一个接口,使智能合约能够执行跨链代币转账。它支持将代币发送到其他启用 IBC 的链,并查询 IBC 面额相关信息。 预编译地址:0x0000000000000000000000000000000000000802
相关模块: x/ibc-transfer
Gas 消耗
Gas 消耗为近似值,可能会因转账复杂度和链配置不同而有所变化。
| 方法 | Gas 消耗 |
|---|---|
| Transfer | 50,000 + (100 × memo length) |
| 查询 | 1000 + (3 × 输入字节数) |
通道校验
发起转账前,请确保:
- 源通道存在且处于 OPEN 状态
- 该通道连接到预期的目标链
- 端口 ID 与预期值一致(通常为
transfer)
超时机制
IBC 转账包含两种超时选项,以防止代币被无限期锁定:- 高度超时:指定为
{revisionNumber, revisionHeight}。将两者都设为 0 可禁用。 - 时间戳超时:以纳秒为单位的 Unix 时间戳。设为 0 可禁用。
必须至少设置一种超时机制。推荐做法是使用当前时间起 1 小时后的时间戳超时。
地址格式要求
当前限制:接收方地址必须为 bech32 格式(例如
cosmos1...)。接收方参数目前不支持十六进制地址(例如 0x...),但该限制将在后续版本中移除。发送方参数会在内部自动从十六进制格式转换为 bech32 格式。EVM 回调支持
ICS20 预编译通过memo 字段支持 EVM 回调,使智能合约能够:
- 在接收跨链转账时自动执行
- 处理已发送转账的确认和超时
- 实现复杂的跨链合约交互
交易方法
transfer
使用 IBC 协议发起跨链代币转账。
接收方地址格式:当前接收方参数仅接受 bech32 地址(例如
cosmos1...)。对十六进制地址(例如 0x...)的支持将在后续版本中加入。// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ICS20Example {
address constant ICS20_PRECOMPILE = 0x0000000000000000000000000000000000000802;
struct Height {
uint64 revisionNumber;
uint64 revisionHeight;
}
event IBCTransferInitiated(
address indexed sender,
string indexed receiver,
string sourceChannel,
string denom,
uint256 amount,
uint64 sequence
);
function transfer(
string calldata sourceChannel,
string calldata denom,
uint256 amount,
string calldata receiver,
uint64 timeoutTimestamp,
string calldata memo
) external payable returns (uint64 sequence) {
require(bytes(sourceChannel).length > 0, "Source channel required");
require(bytes(denom).length > 0, "Denom required");
require(amount > 0, "Amount must be greater than 0");
require(bytes(receiver).length > 0, "Receiver address required");
require(timeoutTimestamp > 0, "Timeout timestamp required");
// Default port for ICS20 transfers
string memory sourcePort = "transfer";
// Disable height-based timeout (using timestamp instead)
Height memory timeoutHeight = Height({
revisionNumber: 0,
revisionHeight: 0
});
(bool success, bytes memory result) = ICS20_PRECOMPILE.call{value: msg.value}(
abi.encodeWithSignature(
"transfer(string,string,string,uint256,address,string,tuple(uint64,uint64),uint64,string)",
sourcePort,
sourceChannel,
denom,
amount,
msg.sender,
receiver,
timeoutHeight,
timeoutTimestamp,
memo
)
);
require(success, "IBC transfer failed");
sequence = abi.decode(result, (uint64));
emit IBCTransferInitiated(msg.sender, receiver, sourceChannel, denom, amount, sequence);
return sequence;
}
// Helper function to calculate timeout (1 hour from now)
function calculateTimeout(uint256 durationSeconds) external view returns (uint64) {
return uint64((block.timestamp + durationSeconds) * 1e9); // Convert to nanoseconds
}
// Quick transfer with 1-hour timeout
function quickTransfer(
string calldata sourceChannel,
string calldata denom,
uint256 amount,
string calldata receiver
) external payable returns (uint64) {
uint64 timeoutTimestamp = this.calculateTimeout(3600); // 1 hour
return this.transfer{value: msg.value}(
sourceChannel,
denom,
amount,
receiver,
timeoutTimestamp,
""
);
}
}
查询方法
denom
通过哈希查询 IBC 代币的面额信息。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ICS20DenomQuery {
address constant ICS20_PRECOMPILE = 0x0000000000000000000000000000000000000802;
struct Hop {
string portId;
string channelId;
}
struct Denom {
string base;
Hop[] trace;
}
function getDenom(string memory hash) external view returns (Denom memory denom) {
require(bytes(hash).length > 0, "Hash cannot be empty");
(bool success, bytes memory result) = ICS20_PRECOMPILE.staticcall(
abi.encodeWithSignature("denom(string)", hash)
);
require(success, "Failed to get denom");
denom = abi.decode(result, (Denom));
return denom;
}
// Helper function to check if a denom is native (no trace)
function isNativeDenom(string memory hash) external view returns (bool) {
Denom memory denom = this.getDenom(hash);
return denom.trace.length == 0;
}
// Helper function to get the base denomination
function getBaseDenom(string memory hash) external view returns (string memory) {
Denom memory denom = this.getDenom(hash);
return denom.base;
}
}
denoms
检索链上已注册的所有面额追踪信息的分页列表。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ICS20DenomsList {
address constant ICS20_PRECOMPILE = 0x0000000000000000000000000000000000000802;
struct PageRequest {
bytes key;
uint64 offset;
uint64 limit;
bool countTotal;
bool reverse;
}
struct PageResponse {
bytes nextKey;
uint64 total;
}
struct Hop {
string portId;
string channelId;
}
struct Denom {
string base;
Hop[] trace;
}
function getDenoms(PageRequest memory pageRequest)
external
view
returns (Denom[] memory denoms, PageResponse memory pageResponse)
{
(bool success, bytes memory result) = ICS20_PRECOMPILE.staticcall(
abi.encodeWithSignature(
"denoms((bytes,uint64,uint64,bool,bool))",
pageRequest
)
);
require(success, "Failed to get denoms");
(denoms, pageResponse) = abi.decode(result, (Denom[], PageResponse));
return (denoms, pageResponse);
}
// Helper function to get all IBC denoms (with trace)
function getIBCDenoms(uint64 limit) external view returns (Denom[] memory) {
PageRequest memory pageRequest = PageRequest({
key: "",
offset: 0,
limit: limit,
countTotal: false,
reverse: false
});
(Denom[] memory allDenoms,) = this.getDenoms(pageRequest);
// Count IBC denoms (those with trace)
uint256 ibcCount = 0;
for (uint i = 0; i < allDenoms.length; i++) {
if (allDenoms[i].trace.length > 0) {
ibcCount++;
}
}
// Filter IBC denoms
Denom[] memory ibcDenoms = new Denom[](ibcCount);
uint256 index = 0;
for (uint i = 0; i < allDenoms.length; i++) {
if (allDenoms[i].trace.length > 0) {
ibcDenoms[index++] = allDenoms[i];
}
}
return ibcDenoms;
}
}
denomHash
计算面额追踪路径的哈希值。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ICS20DenomHash {
address constant ICS20_PRECOMPILE = 0x0000000000000000000000000000000000000802;
function getDenomHash(string memory trace) external view returns (string memory hash) {
require(bytes(trace).length > 0, "Trace cannot be empty");
(bool success, bytes memory result) = ICS20_PRECOMPILE.staticcall(
abi.encodeWithSignature("denomHash(string)", trace)
);
require(success, "Failed to compute denom hash");
hash = abi.decode(result, (string));
return hash;
}
// Helper function to build and hash a trace path
function buildAndHashTrace(
string memory portId,
string memory channelId,
string memory baseDenom
) external view returns (string memory) {
// Build trace in format: "port/channel/denom"
string memory trace = string(abi.encodePacked(
portId,
"/",
channelId,
"/",
baseDenom
));
return this.getDenomHash(trace);
}
// Helper function to verify if a hash matches a trace
function verifyDenomHash(
string memory trace,
string memory expectedHash
) external view returns (bool) {
string memory actualHash = this.getDenomHash(trace);
return keccak256(bytes(actualHash)) == keccak256(bytes(expectedHash));
}
}
完整 Solidity 接口与 ABI
ICS20 Solidity 接口
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.18;
import "../common/Types.sol";
/// @dev The ICS20I contract's address.
address constant ICS20_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000802;
/// @dev The ICS20 contract's instance.
ICS20I constant ICS20_CONTRACT = ICS20I(ICS20_PRECOMPILE_ADDRESS);
/// @dev Denom contains the base denomination for ICS20 fungible tokens and the
/// source tracing information path.
struct Denom {
/// base denomination of the relayed fungible token.
string base;
/// trace contains a list of hops for multi-hop transfers.
Hop[] trace;
}
/// @dev Hop defines a port ID, channel ID pair specifying where
/// tokens must be forwarded next in a multi-hop transfer.
struct Hop {
string portId;
string channelId;
}
/// @author Evmos Team
/// @title ICS20 Transfer Precompiled Contract
/// @dev The interface through which solidity contracts will interact with IBC Transfer (ICS20)
/// @custom:address 0x0000000000000000000000000000000000000802
interface ICS20I {
/// @dev Emitted when an ICS-20 transfer is executed.
/// @param sender The address of the sender.
/// @param receiver The address of the receiver.
/// @param sourcePort The source port of the IBC transaction, For v2 packets, leave it empty.
/// @param sourceChannel The source channel of the IBC transaction, For v2 packets, set the client ID.
/// @param denom The denomination of the tokens transferred.
/// @param amount The amount of tokens transferred.
/// @param memo The IBC transaction memo.
event IBCTransfer(
address indexed sender,
string indexed receiver,
string sourcePort,
string sourceChannel,
string denom,
uint256 amount,
string memo
);
/// @dev Transfer defines a method for performing an IBC transfer.
/// @param sourcePort the port on which the packet will be sent
/// @param sourceChannel the channel by which the packet will be sent
/// @param denom the denomination of the Coin to be transferred to the receiver
/// @param amount the amount of the Coin to be transferred to the receiver
/// @param sender the hex address of the sender
/// @param receiver the bech32 address of the receiver (hex addresses not yet supported)
/// @param timeoutHeight the timeout height relative to the current block height.
/// The timeout is disabled when set to 0
/// @param timeoutTimestamp the timeout timestamp in absolute nanoseconds since unix epoch.
/// The timeout is disabled when set to 0
/// @param memo optional memo
/// @return nextSequence sequence number of the transfer packet sent
function transfer(
string memory sourcePort,
string memory sourceChannel,
string memory denom,
uint256 amount,
address sender,
string memory receiver,
Height memory timeoutHeight,
uint64 timeoutTimestamp,
string memory memo
) external returns (uint64 nextSequence);
/// @dev denoms Defines a method for returning all denoms.
/// @param pageRequest Defines the pagination parameters to for the request.
function denoms(
PageRequest memory pageRequest
)
external
view
returns (
Denom[] memory denoms,
PageResponse memory pageResponse
);
/// @dev Denom defines a method for returning a denom.
function denom(
string memory hash
) external view returns (Denom memory denom);
/// @dev DenomHash defines a method for returning a hash of the denomination info.
function denomHash(
string memory trace
) external view returns (string memory hash);
}
ICS20 ABI
{
"_format": "hh-sol-artifact-1",
"contractName": "ICS20I",
"sourceName": "solidity/precompiles/ics20/ICS20I.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"indexed": true,
"internalType": "string",
"name": "receiver",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "sourcePort",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "sourceChannel",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "memo",
"type": "string"
}
],
"name": "IBCTransfer",
"type": "event"
},
{
"inputs": [
{
"internalType": "string",
"name": "hash",
"type": "string"
}
],
"name": "denom",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "base",
"type": "string"
},
{
"components": [
{
"internalType": "string",
"name": "portId",
"type": "string"
},
{
"internalType": "string",
"name": "channelId",
"type": "string"
}
],
"internalType": "struct Hop[]",
"name": "trace",
"type": "tuple[]"
}
],
"internalType": "struct Denom",
"name": "denom",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "trace",
"type": "string"
}
],
"name": "denomHash",
"outputs": [
{
"internalType": "string",
"name": "hash",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "bytes",
"name": "key",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "offset",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "limit",
"type": "uint64"
},
{
"internalType": "bool",
"name": "countTotal",
"type": "bool"
},
{
"internalType": "bool",
"name": "reverse",
"type": "bool"
}
],
"internalType": "struct PageRequest",
"name": "pageRequest",
"type": "tuple"
}
],
"name": "denoms",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "base",
"type": "string"
},
{
"components": [
{
"internalType": "string",
"name": "portId",
"type": "string"
},
{
"internalType": "string",
"name": "channelId",
"type": "string"
}
],
"internalType": "struct Hop[]",
"name": "trace",
"type": "tuple[]"
}
],
"internalType": "struct Denom[]",
"name": "denoms",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "nextKey",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "total",
"type": "uint64"
}
],
"internalType": "struct PageResponse",
"name": "pageResponse",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "sourcePort",
"type": "string"
},
{
"internalType": "string",
"name": "sourceChannel",
"type": "string"
},
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "string",
"name": "receiver",
"type": "string"
},
{
"components": [
{
"internalType": "uint64",
"name": "revisionNumber",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "revisionHeight",
"type": "uint64"
}
],
"internalType": "struct Height",
"name": "timeoutHeight",
"type": "tuple"
},
{
"internalType": "uint64",
"name": "timeoutTimestamp",
"type": "uint64"
},
{
"internalType": "string",
"name": "memo",
"type": "string"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "uint64",
"name": "nextSequence",
"type": "uint64"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]
}
Overview
The ICS20 precompile provides an interface to the Inter-Blockchain Communication (IBC) protocol, allowing smart contracts to perform cross-chain token transfers. It enables sending tokens to other IBC-enabled chains and querying information about IBC denominations. Precompile Address:0x0000000000000000000000000000000000000802
Related Module: x/ibc-transfer
Gas Costs
Gas costs are approximated and may vary based on the transfer complexity and chain settings.
| Method | Gas Cost |
|---|---|
| Transfer | 50,000 + (100 × memo length) |
| Queries | 1000 + (3 × bytes of input) |
Channel Validation
Before initiating a transfer, ensure that:
- The source channel exists and is in an OPEN state
- The channel is connected to the intended destination chain
- The port ID matches the expected value (typically “transfer”)
Timeout Mechanism
IBC transfers include two timeout options to prevent tokens from being locked indefinitely:- Height Timeout: Specified as
{revisionNumber, revisionHeight}. Set both to 0 to disable. - Timestamp Timeout: Unix timestamp in nanoseconds. Set to 0 to disable.
At least one timeout mechanism must be set. Recommended practice is to use timestamp timeout set to 1 hour from the current time.
Address Format Requirements
Current Limitation: Receiver addresses must be in bech32 format (e.g.,
cosmos1...). Hex addresses (e.g., 0x...) are not currently supported for the receiver parameter, though this limitation will be removed in a future release.The sender parameter is automatically converted from hex to bech32 format internally.EVM Callbacks Support
The ICS20 precompile supports EVM callbacks through thememo field, enabling smart contracts to:
- Execute automatically when receiving cross-chain transfers
- Handle acknowledgments and timeouts for sent transfers
- Implement complex cross-chain contract interactions
For detailed callback implementation, see IBC Module and Callbacks Interface.
Transaction Methods
transfer
Initiates a cross-chain token transfer using the IBC protocol.
Receiver Address Format: Currently only accepts bech32 addresses (e.g.,
cosmos1...) for the receiver parameter. Hex address support (e.g., 0x...) will be added in a future release.// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ICS20Example {
address constant ICS20_PRECOMPILE = 0x0000000000000000000000000000000000000802;
struct Height {
uint64 revisionNumber;
uint64 revisionHeight;
}
event IBCTransferInitiated(
address indexed sender,
string indexed receiver,
string sourceChannel,
string denom,
uint256 amount,
uint64 sequence
);
function transfer(
string calldata sourceChannel,
string calldata denom,
uint256 amount,
string calldata receiver,
uint64 timeoutTimestamp,
string calldata memo
) external payable returns (uint64 sequence) {
require(bytes(sourceChannel).length > 0, "Source channel required");
require(bytes(denom).length > 0, "Denom required");
require(amount > 0, "Amount must be greater than 0");
require(bytes(receiver).length > 0, "Receiver address required");
require(timeoutTimestamp > 0, "Timeout timestamp required");
// Default port for ICS20 transfers
string memory sourcePort = "transfer";
// Disable height-based timeout (using timestamp instead)
Height memory timeoutHeight = Height({
revisionNumber: 0,
revisionHeight: 0
});
(bool success, bytes memory result) = ICS20_PRECOMPILE.call{value: msg.value}(
abi.encodeWithSignature(
"transfer(string,string,string,uint256,address,string,tuple(uint64,uint64),uint64,string)",
sourcePort,
sourceChannel,
denom,
amount,
msg.sender,
receiver,
timeoutHeight,
timeoutTimestamp,
memo
)
);
require(success, "IBC transfer failed");
sequence = abi.decode(result, (uint64));
emit IBCTransferInitiated(msg.sender, receiver, sourceChannel, denom, amount, sequence);
return sequence;
}
// Helper function to calculate timeout (1 hour from now)
function calculateTimeout(uint256 durationSeconds) external view returns (uint64) {
return uint64((block.timestamp + durationSeconds) * 1e9); // Convert to nanoseconds
}
// Quick transfer with 1-hour timeout
function quickTransfer(
string calldata sourceChannel,
string calldata denom,
uint256 amount,
string calldata receiver
) external payable returns (uint64) {
uint64 timeoutTimestamp = this.calculateTimeout(3600); // 1 hour
return this.transfer{value: msg.value}(
sourceChannel,
denom,
amount,
receiver,
timeoutTimestamp,
""
);
}
}
Query Methods
denom
Queries denomination information for an IBC token by its hash.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ICS20DenomQuery {
address constant ICS20_PRECOMPILE = 0x0000000000000000000000000000000000000802;
struct Hop {
string portId;
string channelId;
}
struct Denom {
string base;
Hop[] trace;
}
function getDenom(string memory hash) external view returns (Denom memory denom) {
require(bytes(hash).length > 0, "Hash cannot be empty");
(bool success, bytes memory result) = ICS20_PRECOMPILE.staticcall(
abi.encodeWithSignature("denom(string)", hash)
);
require(success, "Failed to get denom");
denom = abi.decode(result, (Denom));
return denom;
}
// Helper function to check if a denom is native (no trace)
function isNativeDenom(string memory hash) external view returns (bool) {
Denom memory denom = this.getDenom(hash);
return denom.trace.length == 0;
}
// Helper function to get the base denomination
function getBaseDenom(string memory hash) external view returns (string memory) {
Denom memory denom = this.getDenom(hash);
return denom.base;
}
}
denoms
Retrieves a paginated list of all denomination traces registered on the chain.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ICS20DenomsList {
address constant ICS20_PRECOMPILE = 0x0000000000000000000000000000000000000802;
struct PageRequest {
bytes key;
uint64 offset;
uint64 limit;
bool countTotal;
bool reverse;
}
struct PageResponse {
bytes nextKey;
uint64 total;
}
struct Hop {
string portId;
string channelId;
}
struct Denom {
string base;
Hop[] trace;
}
function getDenoms(PageRequest memory pageRequest)
external
view
returns (Denom[] memory denoms, PageResponse memory pageResponse)
{
(bool success, bytes memory result) = ICS20_PRECOMPILE.staticcall(
abi.encodeWithSignature(
"denoms((bytes,uint64,uint64,bool,bool))",
pageRequest
)
);
require(success, "Failed to get denoms");
(denoms, pageResponse) = abi.decode(result, (Denom[], PageResponse));
return (denoms, pageResponse);
}
// Helper function to get all IBC denoms (with trace)
function getIBCDenoms(uint64 limit) external view returns (Denom[] memory) {
PageRequest memory pageRequest = PageRequest({
key: "",
offset: 0,
limit: limit,
countTotal: false,
reverse: false
});
(Denom[] memory allDenoms,) = this.getDenoms(pageRequest);
// Count IBC denoms (those with trace)
uint256 ibcCount = 0;
for (uint i = 0; i < allDenoms.length; i++) {
if (allDenoms[i].trace.length > 0) {
ibcCount++;
}
}
// Filter IBC denoms
Denom[] memory ibcDenoms = new Denom[](ibcCount);
uint256 index = 0;
for (uint i = 0; i < allDenoms.length; i++) {
if (allDenoms[i].trace.length > 0) {
ibcDenoms[index++] = allDenoms[i];
}
}
return ibcDenoms;
}
}
denomHash
Computes the hash of a denomination trace path.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ICS20DenomHash {
address constant ICS20_PRECOMPILE = 0x0000000000000000000000000000000000000802;
function getDenomHash(string memory trace) external view returns (string memory hash) {
require(bytes(trace).length > 0, "Trace cannot be empty");
(bool success, bytes memory result) = ICS20_PRECOMPILE.staticcall(
abi.encodeWithSignature("denomHash(string)", trace)
);
require(success, "Failed to compute denom hash");
hash = abi.decode(result, (string));
return hash;
}
// Helper function to build and hash a trace path
function buildAndHashTrace(
string memory portId,
string memory channelId,
string memory baseDenom
) external view returns (string memory) {
// Build trace in format: "port/channel/denom"
string memory trace = string(abi.encodePacked(
portId,
"/",
channelId,
"/",
baseDenom
));
return this.getDenomHash(trace);
}
// Helper function to verify if a hash matches a trace
function verifyDenomHash(
string memory trace,
string memory expectedHash
) external view returns (bool) {
string memory actualHash = this.getDenomHash(trace);
return keccak256(bytes(actualHash)) == keccak256(bytes(expectedHash));
}
}
Full Solidity Interface & ABI
ICS20 Solidity Interface
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.18;
import "../common/Types.sol";
/// @dev The ICS20I contract's address.
address constant ICS20_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000802;
/// @dev The ICS20 contract's instance.
ICS20I constant ICS20_CONTRACT = ICS20I(ICS20_PRECOMPILE_ADDRESS);
/// @dev Denom contains the base denomination for ICS20 fungible tokens and the
/// source tracing information path.
struct Denom {
/// base denomination of the relayed fungible token.
string base;
/// trace contains a list of hops for multi-hop transfers.
Hop[] trace;
}
/// @dev Hop defines a port ID, channel ID pair specifying where
/// tokens must be forwarded next in a multi-hop transfer.
struct Hop {
string portId;
string channelId;
}
/// @author Evmos Team
/// @title ICS20 Transfer Precompiled Contract
/// @dev The interface through which solidity contracts will interact with IBC Transfer (ICS20)
/// @custom:address 0x0000000000000000000000000000000000000802
interface ICS20I {
/// @dev Emitted when an ICS-20 transfer is executed.
/// @param sender The address of the sender.
/// @param receiver The address of the receiver.
/// @param sourcePort The source port of the IBC transaction, For v2 packets, leave it empty.
/// @param sourceChannel The source channel of the IBC transaction, For v2 packets, set the client ID.
/// @param denom The denomination of the tokens transferred.
/// @param amount The amount of tokens transferred.
/// @param memo The IBC transaction memo.
event IBCTransfer(
address indexed sender,
string indexed receiver,
string sourcePort,
string sourceChannel,
string denom,
uint256 amount,
string memo
);
/// @dev Transfer defines a method for performing an IBC transfer.
/// @param sourcePort the port on which the packet will be sent
/// @param sourceChannel the channel by which the packet will be sent
/// @param denom the denomination of the Coin to be transferred to the receiver
/// @param amount the amount of the Coin to be transferred to the receiver
/// @param sender the hex address of the sender
/// @param receiver the bech32 address of the receiver (hex addresses not yet supported)
/// @param timeoutHeight the timeout height relative to the current block height.
/// The timeout is disabled when set to 0
/// @param timeoutTimestamp the timeout timestamp in absolute nanoseconds since unix epoch.
/// The timeout is disabled when set to 0
/// @param memo optional memo
/// @return nextSequence sequence number of the transfer packet sent
function transfer(
string memory sourcePort,
string memory sourceChannel,
string memory denom,
uint256 amount,
address sender,
string memory receiver,
Height memory timeoutHeight,
uint64 timeoutTimestamp,
string memory memo
) external returns (uint64 nextSequence);
/// @dev denoms Defines a method for returning all denoms.
/// @param pageRequest Defines the pagination parameters to for the request.
function denoms(
PageRequest memory pageRequest
)
external
view
returns (
Denom[] memory denoms,
PageResponse memory pageResponse
);
/// @dev Denom defines a method for returning a denom.
function denom(
string memory hash
) external view returns (Denom memory denom);
/// @dev DenomHash defines a method for returning a hash of the denomination info.
function denomHash(
string memory trace
) external view returns (string memory hash);
}
ICS20 ABI
{
"_format": "hh-sol-artifact-1",
"contractName": "ICS20I",
"sourceName": "solidity/precompiles/ics20/ICS20I.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"indexed": true,
"internalType": "string",
"name": "receiver",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "sourcePort",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "sourceChannel",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "memo",
"type": "string"
}
],
"name": "IBCTransfer",
"type": "event"
},
{
"inputs": [
{
"internalType": "string",
"name": "hash",
"type": "string"
}
],
"name": "denom",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "base",
"type": "string"
},
{
"components": [
{
"internalType": "string",
"name": "portId",
"type": "string"
},
{
"internalType": "string",
"name": "channelId",
"type": "string"
}
],
"internalType": "struct Hop[]",
"name": "trace",
"type": "tuple[]"
}
],
"internalType": "struct Denom",
"name": "denom",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "trace",
"type": "string"
}
],
"name": "denomHash",
"outputs": [
{
"internalType": "string",
"name": "hash",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "bytes",
"name": "key",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "offset",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "limit",
"type": "uint64"
},
{
"internalType": "bool",
"name": "countTotal",
"type": "bool"
},
{
"internalType": "bool",
"name": "reverse",
"type": "bool"
}
],
"internalType": "struct PageRequest",
"name": "pageRequest",
"type": "tuple"
}
],
"name": "denoms",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "base",
"type": "string"
},
{
"components": [
{
"internalType": "string",
"name": "portId",
"type": "string"
},
{
"internalType": "string",
"name": "channelId",
"type": "string"
}
],
"internalType": "struct Hop[]",
"name": "trace",
"type": "tuple[]"
}
],
"internalType": "struct Denom[]",
"name": "denoms",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "nextKey",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "total",
"type": "uint64"
}
],
"internalType": "struct PageResponse",
"name": "pageResponse",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "sourcePort",
"type": "string"
},
{
"internalType": "string",
"name": "sourceChannel",
"type": "string"
},
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "string",
"name": "receiver",
"type": "string"
},
{
"components": [
{
"internalType": "uint64",
"name": "revisionNumber",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "revisionHeight",
"type": "uint64"
}
],
"internalType": "struct Height",
"name": "timeoutHeight",
"type": "tuple"
},
{
"internalType": "uint64",
"name": "timeoutTimestamp",
"type": "uint64"
},
{
"internalType": "string",
"name": "memo",
"type": "string"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "uint64",
"name": "nextSequence",
"type": "uint64"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]
}