@@ -21,6 +21,8 @@ import (
2121
2222// The code in this file is removed in ibc v9. It is copied from ibc v8 to here in order to support the migration to v9
2323
24+ // ReceiverChainIsSource returns true if the denomination originally came
25+ // from the receiving chain and false otherwise.
2426func ReceiverChainIsSource (sourcePort , sourceChannel , denom string ) bool {
2527 // The prefix passed in should contain the SourcePort and SourceChannel.
2628 // If the receiver chain originally sent the token to the sender chain
@@ -31,61 +33,89 @@ func ReceiverChainIsSource(sourcePort, sourceChannel, denom string) bool {
3133 return strings .HasPrefix (denom , voucherPrefix )
3234}
3335
36+ // GetDenomPrefix returns the receiving denomination prefix
3437func GetDenomPrefix (portID , channelID string ) string {
3538 return fmt .Sprintf ("%s/%s/" , portID , channelID )
3639}
3740
41+ // GetPrefixedDenom returns the denomination with the portID and channelID prefixed
3842func GetPrefixedDenom (portID , channelID , baseDenom string ) string {
3943 return fmt .Sprintf ("%s/%s/%s" , portID , channelID , baseDenom )
4044}
4145
46+ // DenomTrace contains the base denomination for ICS20 fungible tokens and the
47+ // source tracing information path.
4248type DenomTrace struct {
43- Path string
44- BaseDenom string
49+ // path defines the chain of port/channel identifiers used for tracing the
50+ // source of the fungible token.
51+ Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
52+ // base denomination of the relayed fungible token.
53+ BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty"`
4554}
4655
4756const DenomPrefix = "ibc"
4857
58+ // ParseDenomTrace parses a string with the ibc prefix (denom trace) and the base denomination
59+ // into a DenomTrace type.
60+ //
61+ // Examples:
62+ //
63+ // - "portidone/channel-0/uatom" => DenomTrace{Path: "portidone/channel-0", BaseDenom: "uatom"}
64+ // - "portidone/channel-0/portidtwo/channel-1/uatom" => DenomTrace{Path: "portidone/channel-0/portidtwo/channel-1", BaseDenom: "uatom"}
65+ // - "portidone/channel-0/gamm/pool/1" => DenomTrace{Path: "portidone/channel-0", BaseDenom: "gamm/pool/1"}
66+ // - "gamm/pool/1" => DenomTrace{Path: "", BaseDenom: "gamm/pool/1"}
67+ // - "uatom" => DenomTrace{Path: "", BaseDenom: "uatom"}
68+ func ParseDenomTrace (rawDenom string ) DenomTrace {
69+ denomSplit := strings .Split (rawDenom , "/" )
70+
71+ if denomSplit [0 ] == rawDenom {
72+ return DenomTrace {
73+ Path : "" ,
74+ BaseDenom : rawDenom ,
75+ }
76+ }
77+
78+ path , baseDenom := extractPathAndBaseFromFullDenom (denomSplit )
79+ return DenomTrace {
80+ Path : path ,
81+ BaseDenom : baseDenom ,
82+ }
83+ }
84+
85+ // Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields using the following formula:
86+ //
87+ // hash = sha256(tracePath + "/" + baseDenom)
4988func (dt DenomTrace ) Hash () tmbytes.HexBytes {
5089 hash := sha256 .Sum256 ([]byte (dt .GetFullDenomPath ()))
5190 return hash [:]
5291}
5392
93+ // GetPrefix returns the receiving denomination prefix composed by the trace info and a separator.
5494func (dt DenomTrace ) GetPrefix () string {
5595 return dt .Path + "/"
5696}
5797
58- func (dt DenomTrace ) GetFullDenomPath () string {
59- if dt .Path == "" {
60- return dt .BaseDenom
61- }
62- return dt .GetPrefix () + dt .BaseDenom
63- }
64-
98+ // IBCDenom a coin denomination for an ICS20 fungible token in the format
99+ // 'ibc/{hash(tracePath + baseDenom)}'. If the trace is empty, it will return the base denomination.
65100func (dt DenomTrace ) IBCDenom () string {
66101 if dt .Path != "" {
67102 return fmt .Sprintf ("%s/%s" , DenomPrefix , dt .Hash ())
68103 }
69104 return dt .BaseDenom
70105}
71106
72- func ParseDenomTrace (rawDenom string ) DenomTrace {
73- denomSplit := strings .Split (rawDenom , "/" )
74-
75- if denomSplit [0 ] == rawDenom {
76- return DenomTrace {
77- Path : "" ,
78- BaseDenom : rawDenom ,
79- }
80- }
81-
82- path , baseDenom := extractPathAndBaseFromFullDenom (denomSplit )
83- return DenomTrace {
84- Path : path ,
85- BaseDenom : baseDenom ,
107+ // GetFullDenomPath returns the full denomination according to the ICS20 specification:
108+ // tracePath + "/" + baseDenom
109+ // If there exists no trace then the base denomination is returned.
110+ func (dt DenomTrace ) GetFullDenomPath () string {
111+ if dt .Path == "" {
112+ return dt .BaseDenom
86113 }
114+ return dt .GetPrefix () + dt .BaseDenom
87115}
88116
117+ // extractPathAndBaseFromFullDenom returns the trace path and the base denom from
118+ // the elements that constitute the complete denom.
89119func extractPathAndBaseFromFullDenom (fullDenomItems []string ) (string , string ) {
90120 var (
91121 pathSlice []string
@@ -117,6 +147,10 @@ func extractPathAndBaseFromFullDenom(fullDenomItems []string) (string, string) {
117147 return path , baseDenom
118148}
119149
150+ // ValidateIBCDenom validates that the given denomination is either:
151+ //
152+ // - A valid base denomination (eg: 'uatom' or 'gamm/pool/1' as in https://github.com/cosmos/ibc-go/issues/894)
153+ // - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-001-coin-source-tracing.md
120154func ValidateIBCDenom (denom string ) error {
121155 if err := sdk .ValidateDenom (denom ); err != nil {
122156 return err
0 commit comments