transfer source realm
View source
IBC Transfer App
ICS-20 Fungible Token Transfer implementation for IBC v2 on Gno. Enables cross-chain token transfers between Gno and any IBC v2 compatible chain.
Transfer
Transfer is the single entry point for sending any token to another chain. The
token type is detected automatically from the denom argument:
| Token type | Denom format | Example | Mechanism |
|---|---|---|---|
| Native coin | plain string | ugnot |
Escrowed via banker.OriginSend (direct user-call only) |
| IBC voucher | ibc/{hash} |
ibc/CAEF9C... |
Burned from sender |
| GRC20 token | grc20reg key | gno.land/r/demo/foo.FOO |
Escrowed via TransferFrom |
Signature:
func Transfer(
cur realm,
clientID string, // IBC client on this chain (e.g. "07-tendermint-1")
receiver string, // recipient address on destination chain
denom string, // token denomination (see table above)
amount int64, // amount to transfer
timeoutTimestamp uint64, // unix seconds after which the packet times out
memo string, // arbitrary memo included in the IBC packet
) (packet types.MsgSendPacket, sequence uint64)
Native coin
The coin must be attached to the transaction via the -send flag and must match
denom and amount. Only direct user calls (gnokey maketx call) are
accepted: Transfer reads banker.OriginSend() guarded by
runtime.PreviousRealm().IsUserCall() to ensure the coins actually landed at
this realm. Calls from intermediate code realms or maketx run ephemeral
realms are rejected.
gnokey maketx call -pkgpath gno.land/r/aib/ibc/apps/transfer -func Transfer \
-send 100ugnot \
-args "07-tendermint-1" -args "atone1abc..." -args "ugnot" -args "100" \
-args "1719878400" -args "" \
-gas-fee 1000000ugnot -gas-wanted 90000000 \
-broadcast -chainid gnoland-1 ADDRESS
IBC voucher
IBC vouchers are GRC20 tokens minted when receiving tokens from another chain. They are burned on transfer back to the source chain.
gnokey maketx call -pkgpath gno.land/r/aib/ibc/apps/transfer -func Transfer \
-args "07-tendermint-1" -args "atone1abc..." \
-args "ibc/CAEF9CA8CE6C302D73A831A49E34E59149D3A9AD96CCEBDFBF62F6D5710D92D8" \
-args "100" -args "1719878400" -args "memo" \
-gas-fee 1000000ugnot -gas-wanted 90000000 \
-broadcast -chainid gnoland-1 ADDRESS
GRC20 token
The caller must first approve the transfer app realm to spend the tokens.
From Gno code (e.g. in a MsgRun script):
transferAddr := chain.PackageAddress("gno.land/r/aib/ibc/apps/transfer")
mytoken.Approve(cross, caller, transferAddr, amount)
Or via gnokey directly, where g1tp3gk4quumurav4858hjfdy6hxtyffwmnxyr00 is
the transfer app realm address:
gnokey maketx call -pkgpath gno.land/r/demo/foo -func Approve \
-args "g1caller..." -args "g1tp3gk4quumurav4858hjfdy6hxtyffwmnxyr00" -args "100" \
-gas-fee 1000000ugnot -gas-wanted 90000000 \
-broadcast -chainid gnoland-1 ADDRESS
Then call Transfer with the grc20reg key as denom:
gnokey maketx call -pkgpath gno.land/r/aib/ibc/apps/transfer -func Transfer \
-args "07-tendermint-1" -args "atone1abc..." \
-args "gno.land/r/demo/foo.FOO" -args "100" \
-args "1719878400" -args "" \
-gas-fee 1000000ugnot -gas-wanted 90000000 \
-broadcast -chainid gnoland-1 ADDRESS
Info
GRC20 denoms are encoded into slash-free aliases for IBC packets by replacing
/ with : (e.g. gno.land/r/demo/foo.FOO becomes
gno.land:r:demo:foo.FOO). The counterparty chain sees the aliased form, not
the original grc20reg key.
Query endpoints
All endpoints return JSON and are accessible via gnoweb or gnokey query vm/qrender.
| Path | Description |
|---|---|
denoms |
List all registered IBC denominations |
denoms/ibc/{hash} |
Details for a specific IBC denom (base, path, denom) |
total_escrow/{denom} |
Total escrowed amount for a native denom |
vouchers |
List all voucher tokens (paginated, includes grc20reg_key) |
voucher/ibc/{hash} |
Voucher token metadata (denom, grc20reg_key, name, symbol, decimals, total supply) |
voucher/ibc/{hash}/balance/{addr} |
Voucher balance for an address |
Example:
gnokey query vm/qrender -data "gno.land/r/aib/ibc/apps/transfer:total_escrow/ugnot"
1{"denom":"ugnot","amount":100}
Helper functions
VoucherBalanceOf
Query the balance of a voucher token for a given address. Returns 0 if the voucher does not exist.
balance := transfer.VoucherBalanceOf("ibc/CAEF9C...", addr)
VoucherSend
Send an IBC voucher token to another Gno address:
transfer.VoucherSend(cross, "ibc/CAEF9C...", recipient, 100)
gnokey maketx call -pkgpath gno.land/r/aib/ibc/apps/transfer -func VoucherSend \
-args "ibc/CAEF9CA8CE6C302D73A831A49E34E59149D3A9AD96CCEBDFBF62F6D5710D92D8" \
-args "g1recipient..." -args "100" \
-gas-fee 1000000ugnot -gas-wanted 90000000 \
-broadcast -chainid gnoland-1 ADDRESS
VoucherApprove
Set a spender allowance for an IBC voucher token:
transfer.VoucherApprove(cross, "ibc/CAEF9C...", spender, 100)
gnokey maketx call -pkgpath gno.land/r/aib/ibc/apps/transfer -func VoucherApprove \
-args "ibc/CAEF9CA8CE6C302D73A831A49E34E59149D3A9AD96CCEBDFBF62F6D5710D92D8" \
-args "g1spender..." -args "100" \
-gas-fee 1000000ugnot -gas-wanted 90000000 \
-broadcast -chainid gnoland-1 ADDRESS
GRC20Alias
Convert a grc20reg key to the slash-free alias used in IBC packets.
alias := transfer.GRC20Alias("gno.land/r/demo/foo.FOO")
// "gno.land:r:demo:foo.FOO"
NewDenom / NewHop
Construct a Denom to compute the expected IBC denom hash:
denom := transfer.NewDenom("uphoton", transfer.NewHop(transfer.PortID, "07-tendermint-1"))
ibcDenom := denom.IBCDenom()
// "ibc/CAEF9CA8CE6C302D73A831A49E34E59149D3A9AD96CCEBDFBF62F6D5710D92D8"
DEX integration for voucher tokens
Voucher tokens minted on RecvPacket are standard GRC20 tokens registered in
grc20reg. A DEX (e.g. Gnoswap) can discover and list them like any other
GRC20 token.
Discovery
Voucher tokens can be discovered in two ways:
-
From the transfer app — query the
vouchersrender endpoint to list all voucher tokens with their metadata. Each entry includes agrc20reg_keyfield with the token's grc20reg key, ready for direct lookup. Supports pagination. -
From
grc20reg— voucher tokens are registered with the keygno.land/r/aib/ibc/apps/transfer.{HASH}, where{HASH}is the uppercase hex SHA256 hash from theibc/{HASH}denom. Enumerate entries with thegno.land/r/aib/ibc/apps/transfer.prefix.
The token name is the base denomination (e.g. uatom) and the symbol is the
full IBC denom (e.g. ibc/CAEF9C...). For richer metadata (trace hops, total
supply), query the render endpoint voucher/ibc/{HASH}.
Trading
- A user receives voucher tokens via an IBC
RecvPacket. - The user approves the DEX realm address to spend their voucher tokens
(
Approve). - The DEX interacts with the voucher via the standard GRC20 teller interface
(
TransferFrom,BalanceOf, etc.).
Multiple vouchers for the same base denom
The same base denomination (e.g. uatom) arriving from different chains
produces distinct voucher tokens with different IBC hashes. A DEX should use the
full ibc/{HASH} denom (available as the token symbol) to distinguish them, and
query denoms/ibc/{HASH} to resolve the trace path for display purposes.
Events
ibc_transfer
Emitted in OnSendPacket for every outgoing transfer packet.
| Attribute | Description |
|---|---|
sender |
Sender address on source chain |
receiver |
Receiver address on destination chain |
denom |
Full denom path |
amount |
Transfer amount |
memo |
Memo text |
fungible_token_packet
Emitted on OnRecvPacket:
| Attribute | Description |
|---|---|
sender |
Sender address |
receiver |
Receiver address |
denom |
Full denom path |
amount |
Amount |
memo |
Memo text |
success |
"true" or "false" |
error |
Error message (on failure) |
Also emitted on OnAcknowledgementPacket:
| Attribute | Description |
|---|---|
sender |
Sender address |
receiver |
Receiver address |
denom |
Full denom path |
amount |
Amount |
memo |
Memo text |
acknowledgement |
Acknowledgement bytes |
denomination
Emitted when a new voucher denom is created during OnRecvPacket.
| Attribute | Description |
|---|---|
denom_hash |
Uppercase hex SHA256 hash |
denom |
JSON representation of the Denom |
timeout
Emitted on OnTimeoutPacket. Tokens are refunded to the original sender.
| Attribute | Description |
|---|---|
receiver |
Refund recipient (original sender) |
denom |
Full denom path |
amount |
Refunded amount |
memo |
Original memo |
IBC packet lifecycle
-
Transfer -- Caller invokes
Transfer. Tokens are escrowed (native/GRC20) or burned (voucher). An IBC packet is sent viacore.SendPacket. -
RecvPacket -- The destination chain receives the packet. If the token originated on the destination chain, the escrowed tokens are returned. Otherwise a voucher GRC20 token is minted and registered in
grc20reg. -
Acknowledgement -- On success, only a
fungible_token_packetevent is emitted. On failure, the sender is refunded (re-mint vouchers, unescrow native/GRC20). -
Timeout -- If the packet is not received before
timeoutTimestamp, the sender is refunded using the same mechanism as a failed acknowledgement.
2
const EventTypeTimeout, EventTypePacket, EventTypeTransfer, EventTypeDenom, AttributeKeySender, AttributeKeyReceiver, AttributeKeyDenom, AttributeKeyDenomHash, AttributeKeyAmount, AttributeKeyRefundReceiver, AttributeKeyRefundTokens, AttributeKeyAckSuccess, AttributeKeyAck, AttributeKeyAckError, AttributeKeyMemo
1const (
2 EventTypeTimeout = "timeout"
3 EventTypePacket = "fungible_token_packet"
4 EventTypeTransfer = "ibc_transfer"
5 EventTypeDenom = "denomination"
6
7 AttributeKeySender = "sender"
8 AttributeKeyReceiver = "receiver"
9 AttributeKeyDenom = "denom"
10 AttributeKeyDenomHash = "denom_hash"
11 AttributeKeyAmount = "amount"
12 AttributeKeyRefundReceiver = "refund_receiver"
13 AttributeKeyRefundTokens = "refund_tokens"
14 AttributeKeyAckSuccess = "success"
15 AttributeKeyAck = "acknowledgement"
16 AttributeKeyAckError = "error"
17 AttributeKeyMemo = "memo"
18)IBC transfer events
12
func GRC20Alias
ActionGRC20Alias returns a slash-free alias for a GRC20 denom (grc20reg key) by replacing "/" with ":". This is safe because grc20reg slugs are alphanumeric (enforced by grc20reg.Register), so colons never appear in grc20reg keys, making the replacement reversible. Examples:
func Render
func Transfer
crossing ActionTransfer is the entry point for sending tokens to another chain using the IBC protocol. It supports three token types, detected automatically from the denom argument:
- IBC voucher (denom starts with "ibc/"): burns the voucher GRC20 token.
- Non-IBC GRC20 token (registered in grc20reg): escrows via TransferFrom.
- Native coin (everything else): the coin must be sent with the transaction via the send field, and must match denom and amount.
memo is included in the IBC packet payload.
func VoucherApprove
crossing ActionVoucherApprove is a convenience helper to set a spender allowance for an IBC voucher token on behalf of the caller.
func VoucherBalanceOf
ActionVoucherBalanceOf returns the balance of a voucher token for a given address. Returns 0 if the token does not exist.
func VoucherSend
crossing ActionVoucherSend is a convenience helper to send an IBC voucher token from the caller to the provided recipient.
func VoucherSymbol
ActionVoucherSymbol returns the grc20 token symbol for an IBC voucher denom: the IBC hash truncated to grc20's MaxSymbolLen. The full voucherDenom ("ibc/<64-hex- hash>") can't be a symbol because v2 grc20 enforces MaxSymbolLen and [A-Za-z0-9_-] only. Since grc20reg keys tokens by rlmpath.symbol, this is also the symbol component of a voucher's registry key, so callers locate a voucher via grc20reg.Get(<this realm's pkgpath> + "." + VoucherSymbol(ibcDenom)).
func ExtractDenomFromPath
ActionExtractDenomFromPath returns the denom from the full path.
func NewDenom
ActionNewDenom creates a new Denom instance given the base denomination and a variable number of hops.
func NewFungibleTokenPacketData
ActionNewFungibleTokenPacketData constructs a new FungibleTokenPacketData instance
func NewHop
ActionNewHop creates a Hop with the given port ID and client ID.
func NewToken
ActionNewToken constructs a Token with the given native base denom and amount (no trace, no prefix hops). Provided so external callers — which cannot construct foreign-stamped composite literals under v2 borrow rule #1 — can still build Token values for tests and packet assembly.
5
type App
structMethods on App
func OnAcknowledgementPacket
crossing method on AppOnAcknowledgementPacket responds to the success or failure of a packet acknowledgment written on the receiving chain.
If the acknowledgement was a success then nothing occurs. Otherwise, if the acknowledgement failed, then the sender is refunded their tokens. Implements app.IBCApp
func OnRecvPacket
crossing method on AppImplements app.IBCApp
func OnSendPacket
crossing method on AppImplements app.IBCApp
func OnTimeoutPacket
crossing method on AppOnTimeoutPacket processes a transfer packet timeout by refunding the tokens to the sender Implements app.IBCApp
type Denom
structDenom holds the base denom of a Token and a trace of the chains it was sent through.
Methods on Denom
func HasPrefix
method on DenomHasPrefix returns true if the first element of the trace of the denom matches the provided portId and clientId.
func Hash
method on DenomHash returns the hex bytes of the SHA256 hash of the Denom fields using the following formula:
hash = sha256(trace + "/" + baseDenom)
func HashHex
method on Denomfunc IBCDenom
method on DenomIBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + baseDenom)}'. If the trace is empty, it will return the base denomination.
func IsNative
method on DenomIsNative returns true if the denomination is native, thus containing no trace history.
func MarshalJSON
method on Denomfunc Path
method on DenomPath returns the full denomination according to the ICS20 specification: trace + "/" + baseDenom If there exists no trace then the base denomination is returned.
func RenderJSON
method on DenomImplements jsonpage.JSONRenderer
func ValidateBasic
method on DenomValidateBasic performs a basic validation of the Denom fields.
type FungibleTokenPacketData
struct 1type FungibleTokenPacketData struct {
2 // the token denomination to be transferred
3 Denom string
4 // the token amount to be transferred
5 Amount string
6 // the sender address
7 Sender string
8 // the recipient address on the destination chain
9 Receiver string
10 // optional memo
11 Memo string
12}FungibleTokenPacketData defines a struct for the packet payload See FungibleTokenPacketData spec: https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures
Methods on FungibleTokenPacketData
func ProtoMarshal
method on FungibleTokenPacketDatafunc ProtoUnmarshal
method on FungibleTokenPacketDatafunc ValidateBasic
method on FungibleTokenPacketDataValidateBasic is used for validating the token transfer.
type Hop
structHop defines a port ID, client ID pair specifying a unique "hop" in a trace
type Token
structToken defines a struct which represents a token to be transferred.
Methods on Token
func AmountInt64
method on Tokenfunc ToCoin
method on TokenToCoin converts a Token to an chain.Coin.
The function parses the Token.Amount field and returns a new sdk.Coin with the IBCDenom of the Token's Denom field and the parsed Amount. If the Amount cannot be parsed, an error is returned with a wrapped error message.
26
- bytes stdlib
- chain stdlib
- chain/banker stdlib
- chain/runtime/unsafe stdlib
- crypto/sha256 stdlib
- encoding/hex stdlib
- errors stdlib
- gno.land/p/aib/encoding/proto package
- gno.land/p/aib/ibc/app package
- gno.land/p/aib/ibc/host package
- gno.land/p/aib/ibc/lightclient package
- gno.land/p/aib/ibc/types package
- gno.land/p/aib/jsonpage package
- gno.land/p/demo/tokens/grc20 package
- gno.land/p/moul/txlink package
- gno.land/p/nt/bptree/v0 package
- gno.land/p/nt/mux/v0 package
- gno.land/p/nt/seqid/v0 package
- gno.land/p/nt/ufmt/v0 package
- gno.land/p/onbloc/int256 package
- gno.land/p/onbloc/json package
- gno.land/r/aib/ibc/core realm
- gno.land/r/demo/defi/grc20reg realm
- strconv stdlib
- strings stdlib
- time stdlib