From 45bab22cfa5c8e523711db724a446f5a815396cf Mon Sep 17 00:00:00 2001 From: beer-1 Date: Thu, 12 Dec 2024 16:21:19 +0900 Subject: [PATCH] create account if nft receipient account is not existing --- x/ibc/nft-transfer/keeper/integration_test.go | 39 ++++++++++++++++++- x/ibc/nft-transfer/keeper/relay.go | 5 +++ x/ibc/nft-transfer/types/expected_keeper.go | 4 ++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/x/ibc/nft-transfer/keeper/integration_test.go b/x/ibc/nft-transfer/keeper/integration_test.go index 8bcf4444..91ff4615 100644 --- a/x/ibc/nft-transfer/keeper/integration_test.go +++ b/x/ibc/nft-transfer/keeper/integration_test.go @@ -1,10 +1,12 @@ package keeper_test import ( + "crypto/rand" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" - sdktypes "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/initia-labs/initia/x/ibc/nft-transfer/types" ibctesting "github.com/initia-labs/initia/x/ibc/testing" @@ -51,7 +53,7 @@ func (suite *KeeperTestSuite) CreateNftClass( func (suite *KeeperTestSuite) MintNft( endpoint *ibctesting.Endpoint, - receiver sdktypes.AccAddress, + receiver sdk.AccAddress, classId, className, tokenId, tokenUri, tokenData string, ) { classNameBz, err := vmtypes.SerializeString(className) @@ -224,6 +226,39 @@ func (suite *KeeperTestSuite) TestSendAndReceive() { suite.ConfirmClassId(pathA2B.EndpointA, classId, targetClassId) } }) + + // transfer from chainA to chainB (non-existing account) + suite.Run("transfer A->B (non-existing account)", func() { + { + sender := pathA2B.EndpointA.Chain.SenderAccount.GetAddress() + + // random receiver account + receiver := make(sdk.AccAddress, 20) + _, err := rand.Read(receiver) + suite.NoError(err) + + packet = suite.transferNft( + pathA2B.EndpointA, + pathA2B.EndpointB, + targetClassId, + nftId, + sender.String(), + receiver.String(), + ) + + targetClassId = suite.receiverNft( + pathA2B.EndpointA, + pathA2B.EndpointB, + packet, + ) + + suite.ConfirmClassId(pathA2B.EndpointB, classId, targetClassId) + + // receiver account should be created + suite.True(suite.chainB.App.GetAccountKeeper().HasAccount(suite.chainB.GetContext(), receiver)) + } + }) + } func (suite *KeeperTestSuite) transferNft( diff --git a/x/ibc/nft-transfer/keeper/relay.go b/x/ibc/nft-transfer/keeper/relay.go index b8483e21..9f64e266 100644 --- a/x/ibc/nft-transfer/keeper/relay.go +++ b/x/ibc/nft-transfer/keeper/relay.go @@ -269,6 +269,11 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return err } + // create account if receiver does not exist + if !k.authKeeper.HasAccount(ctx, receiver) { + k.authKeeper.SetAccount(ctx, k.authKeeper.NewAccountWithAddress(ctx, receiver)) + } + labels := []metrics.Label{ telemetry.NewLabel(coretypes.LabelSourcePort, packet.GetSourcePort()), telemetry.NewLabel(coretypes.LabelSourceChannel, packet.GetSourceChannel()), diff --git a/x/ibc/nft-transfer/types/expected_keeper.go b/x/ibc/nft-transfer/types/expected_keeper.go index 0e30a61f..b8d83b6c 100644 --- a/x/ibc/nft-transfer/types/expected_keeper.go +++ b/x/ibc/nft-transfer/types/expected_keeper.go @@ -18,6 +18,10 @@ type AccountKeeper interface { AddressCodec() address.Codec GetModuleAddress(name string) sdk.AccAddress GetModuleAccount(ctx context.Context, name string) sdk.ModuleAccountI + + SetAccount(ctx context.Context, acc sdk.AccountI) + HasAccount(ctx context.Context, addr sdk.AccAddress) bool + NewAccountWithAddress(ctx context.Context, addr sdk.AccAddress) sdk.AccountI } type NftKeeper interface {