Skip to content

Commit

Permalink
feat: add metadata for IBC tokens (#3104)
Browse files Browse the repository at this point in the history
Co-authored-by: Damian Nolan <[email protected]>
Co-authored-by: Carlos Rodriguez <[email protected]>
Co-authored-by: Jim Fasarakis-Hilliard <[email protected]>
Co-authored-by: Colin Axnér <[email protected]>
  • Loading branch information
5 people authored Sep 12, 2023
1 parent b53bfa5 commit 99c16eb
Show file tree
Hide file tree
Showing 10 changed files with 277 additions and 15 deletions.
4 changes: 4 additions & 0 deletions docs/migrations/v7-to-v8.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ TODO: https://github.com/cosmos/ibc-go/pull/3505 (extra parameter added to trans
)
```

### Transfer migration

An automatic migration handler (TODO: add link after https://github.com/cosmos/ibc-go/pull/3104 is merged) is configured in the transfer module to set the [denomination metadata](https://github.com/cosmos/cosmos-sdk/blob/95178ce036741ae6aa7af131fa9fccf3e13fff7a/proto/cosmos/bank/v1beta1/bank.proto#L96-L125) for the IBC denominations of all vouchers minted by the transfer module.

## IBC Apps

TODO:
Expand Down
1 change: 1 addition & 0 deletions modules/apps/transfer/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) {

for _, trace := range state.DenomTraces {
k.SetDenomTrace(ctx, trace)
k.setDenomMetadata(ctx, trace)
}

// Only try to bind to port if it is not already bound, since we may already own
Expand Down
11 changes: 8 additions & 3 deletions modules/apps/transfer/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (suite *KeeperTestSuite) TestGenesis() {
}

var (
traces types.Traces
denomTraces types.Traces
escrows sdk.Coins
pathsAndEscrowAmounts = []struct {
path string
Expand All @@ -35,7 +35,7 @@ func (suite *KeeperTestSuite) TestGenesis() {
BaseDenom: "uatom",
Path: pathAndEscrowAmount.path,
}
traces = append(types.Traces{denomTrace}, traces...)
denomTraces = append(types.Traces{denomTrace}, denomTraces...)
suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), denomTrace)

denom := denomTrace.IBCDenom()
Expand All @@ -48,10 +48,15 @@ func (suite *KeeperTestSuite) TestGenesis() {
genesis := suite.chainA.GetSimApp().TransferKeeper.ExportGenesis(suite.chainA.GetContext())

suite.Require().Equal(types.PortID, genesis.PortId)
suite.Require().Equal(traces.Sort(), genesis.DenomTraces)
suite.Require().Equal(denomTraces.Sort(), genesis.DenomTraces)
suite.Require().Equal(escrows.Sort(), genesis.TotalEscrowed)

suite.Require().NotPanics(func() {
suite.chainA.GetSimApp().TransferKeeper.InitGenesis(suite.chainA.GetContext(), *genesis)
})

for _, denomTrace := range denomTraces {
_, found := suite.chainA.GetSimApp().BankKeeper.GetDenomMetaData(suite.chainA.GetContext(), denomTrace.IBCDenom())
suite.Require().True(found)
}
}
23 changes: 23 additions & 0 deletions modules/apps/transfer/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"

tmbytes "github.com/cometbft/cometbft/libs/bytes"
Expand Down Expand Up @@ -190,6 +191,28 @@ func (k Keeper) IterateDenomTraces(ctx sdk.Context, cb func(denomTrace types.Den
}
}

// setDenomMetadata sets an IBC token's denomination metadata
func (k Keeper) setDenomMetadata(ctx sdk.Context, denomTrace types.DenomTrace) {
metadata := banktypes.Metadata{
Description: fmt.Sprintf("IBC token from %s", denomTrace.GetFullDenomPath()),
DenomUnits: []*banktypes.DenomUnit{
{
Denom: denomTrace.BaseDenom,
Exponent: 0,
},
},
// Setting base as IBC hash denom since bank keepers's SetDenomMetadata uses
// Base as key path and the IBC hash is what gives this token uniqueness
// on the executing chain
Base: denomTrace.IBCDenom(),
Display: denomTrace.GetFullDenomPath(),
Name: fmt.Sprintf("%s IBC token", denomTrace.GetFullDenomPath()),
Symbol: strings.ToUpper(denomTrace.BaseDenom),
}

k.bankKeeper.SetDenomMetaData(ctx, metadata)
}

// GetTotalEscrowForDenom gets the total amount of source chain tokens that
// are in escrow, keyed by the denomination.
//
Expand Down
16 changes: 16 additions & 0 deletions modules/apps/transfer/keeper/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func (m Migrator) MigrateTraces(ctx sdk.Context) error {
if !equalTraces(newTrace, dt) {
newTraces = append(newTraces, newTrace)
}

return false
})

Expand All @@ -65,6 +66,21 @@ func (m Migrator) MigrateTraces(ctx sdk.Context) error {
return nil
}

// MigrateDenomMetadata sets token metadata for all the IBC denom traces
func (m Migrator) MigrateDenomMetadata(ctx sdk.Context) error {
m.keeper.IterateDenomTraces(ctx,
func(dt types.DenomTrace) (stop bool) {
// check if the metadata for the given denom trace does not already exist
if !m.keeper.bankKeeper.HasDenomMetaData(ctx, dt.IBCDenom()) {
m.keeper.setDenomMetadata(ctx, dt)
}
return false
})

m.keeper.Logger(ctx).Info("successfully added metadata to IBC voucher denominations")
return nil
}

// MigrateTotalEscrowForDenom migrates the total amount of source chain tokens in escrow.
func (m Migrator) MigrateTotalEscrowForDenom(ctx sdk.Context) error {
var totalEscrowed sdk.Coins
Expand Down
183 changes: 183 additions & 0 deletions modules/apps/transfer/keeper/migrations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

transferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper"
transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
Expand Down Expand Up @@ -235,3 +236,185 @@ func (suite *KeeperTestSuite) TestMigrateTotalEscrowForDenom() {
})
}
}

func (suite *KeeperTestSuite) TestMigratorMigrateMetadata() {
var (
denomTraces []transfertypes.DenomTrace
expectedMetadata []banktypes.Metadata
)

testCases := []struct {
msg string
malleate func()
}{
{
"success with one denom trace with one hop",
func() {
denomTraces = []transfertypes.DenomTrace{
{
BaseDenom: "foo",
Path: "transfer/channel-0",
},
}

expectedMetadata = []banktypes.Metadata{
{
Description: "IBC token from transfer/channel-0/foo",
DenomUnits: []*banktypes.DenomUnit{
{
Denom: "foo",
Exponent: 0,
},
},
Base: denomTraces[0].IBCDenom(), // ibc/EB7094899ACFB7A6F2A67DB084DEE2E9A83DEFAA5DEF92D9A9814FFD9FF673FA
Display: "transfer/channel-0/foo",
Name: "transfer/channel-0/foo IBC token",
Symbol: "FOO",
},
}
},
},
{
"success with one denom trace with two hops",
func() {
denomTraces = []transfertypes.DenomTrace{
{
BaseDenom: "ubar",
Path: "transfer/channel-1/transfer/channel-2",
},
}

expectedMetadata = []banktypes.Metadata{
{
Description: "IBC token from transfer/channel-1/transfer/channel-2/ubar",
DenomUnits: []*banktypes.DenomUnit{
{
Denom: "ubar",
Exponent: 0,
},
},
Base: denomTraces[0].IBCDenom(), // ibc/8243B3EAA19BAB1DB3B0020B81C0C5A953E7B22C042CEE44E639A11A238BA57C
Display: "transfer/channel-1/transfer/channel-2/ubar",
Name: "transfer/channel-1/transfer/channel-2/ubar IBC token",
Symbol: "UBAR",
},
}
},
},
{
"success with two denom traces with one hop",
func() {
denomTraces = []transfertypes.DenomTrace{
{
BaseDenom: "foo",
Path: "transfer/channel-0",
},
{
BaseDenom: "bar",
Path: "transfer/channel-0",
},
}

expectedMetadata = []banktypes.Metadata{
{
Description: "IBC token from transfer/channel-0/foo",
DenomUnits: []*banktypes.DenomUnit{
{
Denom: "foo",
Exponent: 0,
},
},
Base: denomTraces[0].IBCDenom(), // ibc/EB7094899ACFB7A6F2A67DB084DEE2E9A83DEFAA5DEF92D9A9814FFD9FF673FA
Display: "transfer/channel-0/foo",
Name: "transfer/channel-0/foo IBC token",
Symbol: "FOO",
},
{
Description: "IBC token from transfer/channel-0/bar",
DenomUnits: []*banktypes.DenomUnit{
{
Denom: "bar",
Exponent: 0,
},
},
Base: denomTraces[1].IBCDenom(), // ibc/E1530E21F1848B6C29C9E89256D43E294976897611A61741CACBA55BE21736F5
Display: "transfer/channel-0/bar",
Name: "transfer/channel-0/bar IBC token",
Symbol: "BAR",
},
}
},
},
{
"success with two denom traces, metadata for one of them already exists",
func() {
denomTraces = []transfertypes.DenomTrace{
{
BaseDenom: "foo",
Path: "transfer/channel-0",
},
{
BaseDenom: "bar",
Path: "transfer/channel-0",
},
}

expectedMetadata = []banktypes.Metadata{
{
Description: "IBC token from transfer/channel-0/foo",
DenomUnits: []*banktypes.DenomUnit{
{
Denom: "foo",
Exponent: 0,
},
},
Base: denomTraces[0].IBCDenom(), // ibc/EB7094899ACFB7A6F2A67DB084DEE2E9A83DEFAA5DEF92D9A9814FFD9FF673FA
Display: "transfer/channel-0/foo",
Name: "transfer/channel-0/foo IBC token",
Symbol: "FOO",
},
{
Description: "IBC token from transfer/channel-0/bar",
DenomUnits: []*banktypes.DenomUnit{
{
Denom: "bar",
Exponent: 0,
},
},
Base: denomTraces[1].IBCDenom(), // ibc/E1530E21F1848B6C29C9E89256D43E294976897611A61741CACBA55BE21736F5
Display: "transfer/channel-0/bar",
Name: "transfer/channel-0/bar IBC token",
Symbol: "BAR",
},
}

// set metadata for one of the tokens, so that it exists already in state before doing the migration
suite.chainA.GetSimApp().BankKeeper.SetDenomMetaData(suite.chainA.GetContext(), expectedMetadata[1])
},
},
}

for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
ctx := suite.chainA.GetContext()

tc.malleate()

for _, denomTrace := range denomTraces {
suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace(ctx, denomTrace)
}

// run migration
migrator := transferkeeper.NewMigrator(suite.chainA.GetSimApp().TransferKeeper)
err := migrator.MigrateDenomMetadata(ctx)
suite.Require().NoError(err)

for _, expMetadata := range expectedMetadata {
denomMetadata, found := suite.chainA.GetSimApp().BankKeeper.GetDenomMetaData(ctx, expMetadata.Base)
suite.Require().True(found)
suite.Require().Equal(expMetadata, denomMetadata)
}
})
}
}
4 changes: 4 additions & 0 deletions modules/apps/transfer/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t
}

voucherDenom := denomTrace.IBCDenom()
if !k.bankKeeper.HasDenomMetaData(ctx, voucherDenom) {
k.setDenomMetadata(ctx, denomTrace)
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeDenomTrace,
Expand Down
Loading

0 comments on commit 99c16eb

Please sign in to comment.