Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add tests for v2 transfer vesting account #7688

Merged
merged 3 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Testing

* [\#7430](https://github.com/cosmos/ibc-go/pull/7430) Update the block proposer in test chains for each block.
* [\#7688](https://github.com/cosmos/ibc-go/pull/7688) Added `SendMsgsWithSender` to `TestChain`.

### Dependencies

Expand Down
108 changes: 102 additions & 6 deletions modules/apps/transfer/v2/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import (

sdkmath "cosmossdk.io/math"

"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

transfertypes "github.com/cosmos/ibc-go/v9/modules/apps/transfer/types"
clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types"
Expand All @@ -22,8 +25,12 @@ import (

// TestMsgSendPacketTransfer tests the MsgSendPacket rpc handler for the transfer v2 application.
func (suite *KeeperTestSuite) TestMsgSendPacketTransfer() {
var payload channeltypesv2.Payload
var path *ibctesting.Path
var (
payload channeltypesv2.Payload
path *ibctesting.Path
expEscrowAmounts []transfertypes.Token // total amounts in escrow for each token
sender ibctesting.SenderAccount
)

testCases := []struct {
name string
Expand Down Expand Up @@ -60,6 +67,94 @@ func (suite *KeeperTestSuite) TestMsgSendPacketTransfer() {
},
nil,
},
{
"successful transfer of entire spendable balance with vesting account",
func() {
// create vesting account
vestingAccPrivKey := secp256k1.GenPrivKey()
vestingAccAddress := sdk.AccAddress(vestingAccPrivKey.PubKey().Address())

vestingCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, ibctesting.DefaultCoinAmount))
_, err := suite.chainA.SendMsgs(vestingtypes.NewMsgCreateVestingAccount(
suite.chainA.SenderAccount.GetAddress(),
vestingAccAddress,
vestingCoins,
suite.chainA.GetContext().BlockTime().Add(time.Hour).Unix(),
false,
))
suite.Require().NoError(err)

// transfer some spendable coins to vesting account
spendableAmount := sdkmath.NewInt(42)
transferCoins := sdk.NewCoins(sdk.NewCoin(vestingCoins[0].Denom, spendableAmount))
_, err = suite.chainA.SendMsgs(banktypes.NewMsgSend(suite.chainA.SenderAccount.GetAddress(), vestingAccAddress, transferCoins))
suite.Require().NoError(err)

// just to prove that the vesting account has a balance (but only spendableAmount is spendable)
vestingAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), vestingAccAddress, vestingCoins[0].Denom)
suite.Require().Equal(vestingCoins[0].Amount.Uint64()+spendableAmount.Uint64(), vestingAccBalance.Amount.Uint64())
vestinSpendableBalance := suite.chainA.GetSimApp().BankKeeper.SpendableCoins(suite.chainA.GetContext(), vestingAccAddress)
suite.Require().Equal(spendableAmount.Uint64(), vestinSpendableBalance.AmountOf(vestingCoins[0].Denom).Uint64())

bz, err := ics20lib.EncodeFungibleTokenPacketData(ics20lib.ICS20LibFungibleTokenPacketData{
Denom: sdk.DefaultBondDenom,
Amount: transfertypes.UnboundedSpendLimit().BigInt(),
Sender: vestingAccAddress.String(),
Receiver: suite.chainB.SenderAccount.GetAddress().String(),
Memo: "",
})
suite.Require().NoError(err)
payload = channeltypesv2.NewPayload(transfertypes.ModuleName, transfertypes.ModuleName, transfertypes.V1, transfertypes.EncodingABI, bz)

sender = suite.chainA.GetSenderAccount(vestingAccPrivKey)

expEscrowAmounts = []transfertypes.Token{
{
Denom: transfertypes.NewDenom(sdk.DefaultBondDenom),
Amount: spendableAmount.String(), // The only spendable amount
},
}
},
nil,
},
{
"failure: no spendable coins for vesting account",
func() {
// create vesting account
vestingAccPrivKey := secp256k1.GenPrivKey()
vestingAccAddress := sdk.AccAddress(vestingAccPrivKey.PubKey().Address())

vestingCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, ibctesting.DefaultCoinAmount))
_, err := suite.chainA.SendMsgs(vestingtypes.NewMsgCreateVestingAccount(
suite.chainA.SenderAccount.GetAddress(),
vestingAccAddress,
vestingCoins,
suite.chainA.GetContext().BlockTime().Add(time.Hour).Unix(),
false,
))
suite.Require().NoError(err)

// just to prove that the vesting account has a balance (but not spendable)
vestingAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), vestingAccAddress, vestingCoins[0].Denom)
suite.Require().Equal(vestingCoins[0].Amount.Uint64(), vestingAccBalance.Amount.Uint64())
vestinSpendableBalance := suite.chainA.GetSimApp().BankKeeper.SpendableCoins(suite.chainA.GetContext(), vestingAccAddress)
suite.Require().Zero(vestinSpendableBalance.AmountOf(vestingCoins[0].Denom).Uint64())

// try to transfer the entire spendable balance (which is zero)
bz, err := ics20lib.EncodeFungibleTokenPacketData(ics20lib.ICS20LibFungibleTokenPacketData{
Denom: sdk.DefaultBondDenom,
Amount: transfertypes.UnboundedSpendLimit().BigInt(),
Sender: vestingAccAddress.String(),
Receiver: suite.chainB.SenderAccount.GetAddress().String(),
Memo: "",
})
suite.Require().NoError(err)
payload = channeltypesv2.NewPayload(transfertypes.ModuleName, transfertypes.ModuleName, transfertypes.V1, transfertypes.EncodingABI, bz)

sender = suite.chainA.GetSenderAccount(vestingAccPrivKey)
},
transfertypes.ErrInvalidAmount,
},
{
"failure: send transfers disabled",
func() {
Expand Down Expand Up @@ -91,6 +186,8 @@ func (suite *KeeperTestSuite) TestMsgSendPacketTransfer() {
Amount: ibctesting.DefaultCoinAmount.String(),
},
}
expEscrowAmounts = tokens
sender = suite.chainA.SenderAccounts[0]

ftpd := transfertypes.NewFungibleTokenPacketDataV2(tokens, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", transfertypes.ForwardingPacketData{})
bz := suite.chainA.Codec.MustMarshal(&ftpd)
Expand All @@ -99,18 +196,17 @@ func (suite *KeeperTestSuite) TestMsgSendPacketTransfer() {
payload = channeltypesv2.NewPayload(transfertypes.ModuleName, transfertypes.ModuleName, transfertypes.V2, transfertypes.EncodingProtobuf, bz)

tc.malleate()

packet, err := path.EndpointA.MsgSendPacket(timestamp, payload)
packet, err := path.EndpointA.MsgSendPacketWithSender(timestamp, payload, sender)

expPass := tc.expError == nil
if expPass {
suite.Require().NoError(err)
suite.Require().NotEmpty(packet)

// ensure every token sent is escrowed.
for _, t := range tokens {
for i, t := range tokens {
escrowedAmount := suite.chainA.GetSimApp().TransferKeeperV2.GetTotalEscrowForDenom(suite.chainA.GetContext(), t.Denom.IBCDenom())
expected, err := t.ToCoin()
expected, err := expEscrowAmounts[i].ToCoin()
suite.Require().NoError(err)
suite.Require().Equal(expected, escrowedAmount, "escrowed amount is not equal to expected amount")
}
Expand Down
34 changes: 27 additions & 7 deletions testing/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,20 @@ func (chain *TestChain) sendMsgs(msgs ...sdk.Msg) error {
return err
}

// SendMsgs delivers a transaction through the application. It updates the senders sequence
// number and updates the TestChain's headers. It returns the result and error if one
// occurred.
// SendMsgs delivers a transaction through the application using a predefined sender.
// It updates the senders sequence number and updates the TestChain's headers.
// It returns the result and error if one occurred.
func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) {
senderAccount := SenderAccount{
SenderPrivKey: chain.SenderPrivKey,
SenderAccount: chain.SenderAccount,
}

return chain.SendMsgsWithSender(senderAccount, msgs...)
}

// SendMsgsWithSender delivers a transaction through the application using the provided sender.
func (chain *TestChain) SendMsgsWithSender(sender SenderAccount, msgs ...sdk.Msg) (*abci.ExecTxResult, error) {
if chain.SendMsgsOverride != nil {
return chain.SendMsgsOverride(msgs...)
}
Expand All @@ -359,7 +369,7 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) {

// increment acc sequence regardless of success or failure tx execution
defer func() {
err := chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1)
err := sender.SenderAccount.SetSequence(sender.SenderAccount.GetSequence() + 1)
if err != nil {
panic(err)
}
Expand All @@ -371,12 +381,12 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) {
chain.App.GetBaseApp(),
msgs,
chain.ChainID,
[]uint64{chain.SenderAccount.GetAccountNumber()},
[]uint64{chain.SenderAccount.GetSequence()},
[]uint64{sender.SenderAccount.GetAccountNumber()},
[]uint64{sender.SenderAccount.GetSequence()},
true,
chain.ProposedHeader.GetTime(),
chain.NextVals.Hash(),
chain.SenderPrivKey,
sender.SenderPrivKey,
)
if err != nil {
return nil, err
Expand Down Expand Up @@ -593,3 +603,13 @@ func (chain *TestChain) IBCClientHeader(header *ibctm.Header, trustedHeight clie

return header, nil
}

// GetSenderAccount returns the sender account associated with the provided private key.
func (chain *TestChain) GetSenderAccount(privKey cryptotypes.PrivKey) SenderAccount {
account := chain.GetSimApp().AccountKeeper.GetAccount(chain.GetContext(), sdk.AccAddress(privKey.PubKey().Address()))

return SenderAccount{
SenderPrivKey: privKey,
SenderAccount: account,
}
}
16 changes: 13 additions & 3 deletions testing/endpoint_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,21 @@ func (endpoint *Endpoint) RegisterCounterparty() (err error) {
return err
}

// MsgSendPacket sends a packet on the associated endpoint. The constructed packet is returned.
// MsgSendPacket sends a packet on the associated endpoint using a predefined sender. The constructed packet is returned.
func (endpoint *Endpoint) MsgSendPacket(timeoutTimestamp uint64, payload channeltypesv2.Payload) (channeltypesv2.Packet, error) {
msgSendPacket := channeltypesv2.NewMsgSendPacket(endpoint.ChannelID, timeoutTimestamp, endpoint.Chain.SenderAccount.GetAddress().String(), payload)
senderAccount := SenderAccount{
SenderPrivKey: endpoint.Chain.SenderPrivKey,
SenderAccount: endpoint.Chain.SenderAccount,
}

return endpoint.MsgSendPacketWithSender(timeoutTimestamp, payload, senderAccount)
}

// MsgSendPacketWithSender sends a packet on the associated endpoint using the provided sender. The constructed packet is returned.
func (endpoint *Endpoint) MsgSendPacketWithSender(timeoutTimestamp uint64, payload channeltypesv2.Payload, sender SenderAccount) (channeltypesv2.Packet, error) {
msgSendPacket := channeltypesv2.NewMsgSendPacket(endpoint.ChannelID, timeoutTimestamp, sender.SenderAccount.GetAddress().String(), payload)

res, err := endpoint.Chain.SendMsgs(msgSendPacket)
res, err := endpoint.Chain.SendMsgsWithSender(sender, msgSendPacket)
if err != nil {
return channeltypesv2.Packet{}, err
}
Expand Down
Loading