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

(feat) Add possibility to transfer entire balance. (backport #6877) #6929

Merged
merged 4 commits into from
Jul 25, 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be removed

Copy link
Contributor

@crodriguezvega crodriguezvega Jul 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it can be deleted. In general the whole compatibility folder could be deleted. I can do it in a separate PR.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"chain-a": [
"main"
],
"chain-b": [
"main"
],
"entrypoint": [
"TestTransferTestSuite"
],
"test": [
"TestMsgTransfer_Succeeds_Nonincentivized_MultiDenom",
"TestMsgTransfer_EntireBalance",
"TestMsgTransfer_Fails_InvalidAddress_MultiDenom"
],
"relayer-type": [
"hermes"
]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"chain-a": [
"release-v9.0.x"
],
"chain-b": [
"release-v9.0.x"
],
"entrypoint": [
"TestTransferTestSuite"
],
"test": [
"TestMsgTransfer_Succeeds_Nonincentivized_MultiDenom",
"TestMsgTransfer_EntireBalance",
"TestMsgTransfer_Fails_InvalidAddress_MultiDenom"
],
"relayer-type": [
"hermes"
]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"chain-a": [
"release-v9.0.x"
],
"chain-b": [
"release-v9.0.x"
],
"entrypoint": [
"TestTransferTestSuite"
],
"test": [
"TestMsgTransfer_Succeeds_Nonincentivized_MultiDenom",
"TestMsgTransfer_EntireBalance",
"TestMsgTransfer_Fails_InvalidAddress_MultiDenom"
],
"relayer-type": [
"hermes"
]
}
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Features

* (apps/transfer) [\#6877](https://github.com/cosmos/ibc-go/pull/6877) Added the possibility to transfer the entire user balance of a particular denomination by using [`UnboundedSpendLimit`](https://github.com/cosmos/ibc-go/blob/715f00eef8727da41db25fdd4763b709bdbba07e/modules/apps/transfer/types/transfer_authorization.go#L253-L255) as the token amount.

### Bug Fixes

## [v7.6.0](https://github.com/cosmos/ibc-go/releases/tag/v7.6.0) - 2024-06-20
Expand Down
5 changes: 5 additions & 0 deletions modules/apps/transfer/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ func (k Keeper) sendTransfer(
telemetry.NewLabel(coretypes.LabelDestinationChannel, destinationChannel),
}

// Using types.UnboundedSpendLimit allows us to send the entire balance of a given denom.
if token.Amount.Equal(types.UnboundedSpendLimit()) {
token.Amount = k.bankKeeper.GetBalance(ctx, sender, token.Denom).Amount
}

// NOTE: SendTransfer simply sends the denomination as it exists on its own
// chain inside the packet data. The receiving chain will perform denom
// prefixing as necessary.
Expand Down
9 changes: 9 additions & 0 deletions modules/apps/transfer/keeper/relay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ func (suite *KeeperTestSuite) TestSendTransfer() {
memo = "memo"
}, true,
},
{
"successful transfer of entire balance",
func() {
coin.Amount = types.UnboundedSpendLimit()
var ok bool
expEscrowAmount, ok = sdk.NewIntFromString(ibctesting.DefaultGenesisAccBalance)
suite.Require().True(ok)
}, true,
},
{
"source channel not found",
func() {
Expand Down
17 changes: 15 additions & 2 deletions modules/apps/transfer/types/coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package types

import (
"fmt"
"math/big"
"strings"

"cosmossdk.io/math"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
)

// maxUint256 is the maximum value for a 256 bit unsigned integer.
var maxUint256 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))

// SenderChainIsSource returns false if the denomination originally came
// from the receiving chain and true otherwise.
func SenderChainIsSource(sourcePort, sourceChannel, denom string) bool {
Expand Down Expand Up @@ -42,7 +46,16 @@ func GetPrefixedDenom(portID, channelID, baseDenom string) string {

// GetTransferCoin creates a transfer coin with the port ID and channel ID
// prefixed to the base denom.
func GetTransferCoin(portID, channelID, baseDenom string, amount math.Int) sdk.Coin {
func GetTransferCoin(portID, channelID, baseDenom string, amount sdkmath.Int) sdk.Coin {
denomTrace := ParseDenomTrace(GetPrefixedDenom(portID, channelID, baseDenom))
return sdk.NewCoin(denomTrace.IBCDenom(), amount)
}

// UnboundedSpendLimit returns the sentinel value that can be used
// as the amount for a denomination's spend limit for which spend limit updating
// should be disabled. Please note that using this sentinel value means that a grantee
// will be granted the privilege to do ICS20 token transfers for the total amount
// of the denomination available at the granter's account.
func UnboundedSpendLimit() sdkmath.Int {
return sdkmath.NewIntFromBigInt(maxUint256)
}
14 changes: 0 additions & 14 deletions modules/apps/transfer/types/transfer_authorization.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package types

import (
"math/big"
"strings"

sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/authz"
Expand All @@ -15,9 +13,6 @@ import (

var _ authz.Authorization = &TransferAuthorization{}

// maxUint256 is the maximum value for a 256 bit unsigned integer.
var maxUint256 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))

// NewTransferAuthorization creates a new TransferAuthorization object.
func NewTransferAuthorization(allocations ...Allocation) *TransferAuthorization {
return &TransferAuthorization{
Expand Down Expand Up @@ -174,12 +169,3 @@ func validateMemo(ctx sdk.Context, memo string, allowedMemos []string) error {

return sdkerrors.Wrapf(ErrInvalidAuthorization, "not allowed memo: %s", memo)
}

// UnboundedSpendLimit returns the sentinel value that can be used
// as the amount for a denomination's spend limit for which spend limit updating
// should be disabled. Please note that using this sentinel value means that a grantee
// will be granted the privilege to do ICS20 token transfers for the total amount
// of the denomination available at the granter's account.
func UnboundedSpendLimit() sdkmath.Int {
return sdk.NewIntFromBigInt(maxUint256)
}
6 changes: 5 additions & 1 deletion testing/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ type SenderAccount struct {
SenderAccount authtypes.AccountI
}

const (
DefaultGenesisAccBalance = "10000000000000000000"
)

// TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI
// header and the validators of the TestChain. It also contains a field called ChainID. This
// is the clientID that *other* chains use to refer to this TestChain. The SenderAccount
Expand Down Expand Up @@ -104,7 +108,7 @@ func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, va
for i := 0; i < MaxAccounts; i++ {
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), uint64(i), 0)
amount, ok := sdk.NewIntFromString("10000000000000000000")
amount, ok := sdk.NewIntFromString(DefaultGenesisAccBalance)
require.True(t, ok)

// add sender account
Expand Down
Loading