Skip to content
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
22 changes: 14 additions & 8 deletions x/bank/keeper/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,22 @@ func (k MoveSendKeeper) InputOutputCoins(ctx context.Context, input types.Input,
types.NewCoinSpentEvent(fromAddr, input.Coins),
)

// emit coin received events and do address caching
addrMap := make(map[string][]byte)
for _, output := range outputs {
// emit coin received events and resolve recipients
outAddrs := make([]sdk.AccAddress, len(outputs))
for i, output := range outputs {
addr, err := k.ak.AddressCodec().StringToBytes(output.Address)
if err != nil {
return err
}

// cache bytes address
addrMap[output.Address] = addr
// apply the registered send restriction, consistent with SendCoins
addr, err = k.sendRestriction.apply(ctx, fromAddr, addr, output.Coins)
if err != nil {
return err
}

// cache the post-restriction recipient
outAddrs[i] = addr

// emit coin received event
sdkCtx.EventManager().EmitEvent(
Expand All @@ -152,7 +158,7 @@ func (k MoveSendKeeper) InputOutputCoins(ctx context.Context, input types.Input,
sdkCtx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeTransfer,
sdk.NewAttribute(types.AttributeKeyRecipient, output.Address),
sdk.NewAttribute(types.AttributeKeyRecipient, sdk.AccAddress(addr).String()),
sdk.NewAttribute(sdk.AttributeKeyAmount, output.Coins.String()),
),
)
Expand All @@ -165,9 +171,9 @@ func (k MoveSendKeeper) InputOutputCoins(ctx context.Context, input types.Input,

recipients := make([]sdk.AccAddress, 0, len(outputs))
amounts := make([]math.Int, 0, len(outputs))
for _, output := range outputs {
for i, output := range outputs {
// Create account if recipient does not exist.
outAddress := addrMap[output.Address]
outAddress := outAddrs[i]
accExists := k.ak.HasAccount(ctx, outAddress)
if !accExists {
defer telemetry.IncrCounter(1, "new", "account")
Expand Down
45 changes: 45 additions & 0 deletions x/bank/keeper/send_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package keeper_test

import (
"context"
"testing"

"github.com/stretchr/testify/require"

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

bankkeeper "github.com/initia-labs/initia/x/bank/keeper"
)

func TestInputOutputCoinsAppliesSendRestriction(t *testing.T) {
ctx, input := createDefaultTestInput(t)

bk, ok := input.BankKeeper.(bankkeeper.BaseKeeper)
require.True(t, ok)

denom := testDenoms[0]
coins := sdk.NewCoins(sdk.NewInt64Coin(denom, 1_000))

from := input.Faucet.NewFundedAccount(ctx, sdk.NewInt64Coin(denom, 1_000_000))
to := input.Faucet.NewFundedAccount(ctx, sdk.NewInt64Coin(denom, 1))

// register a restriction that records every invocation
var calls int
bk.AppendSendRestriction(func(_ context.Context, _, toAddr sdk.AccAddress, _ sdk.Coins) (sdk.AccAddress, error) {
calls++
return toAddr, nil
})

// SendCoins (MsgSend) must apply the restriction
calls = 0
require.NoError(t, bk.SendCoins(ctx, from, to, coins))
require.Equal(t, 1, calls)

// InputOutputCoins (MsgMultiSend) must apply the restriction once per output
calls = 0
in := banktypes.Input{Address: from.String(), Coins: coins}
outputs := []banktypes.Output{{Address: to.String(), Coins: coins}}
require.NoError(t, bk.InputOutputCoins(ctx, in, outputs))
require.Equal(t, 1, calls)
}
Loading