Summary
We need a function in bank for SendManyCoins
, and for SendCoinsFromModuleToManyAccount
. These should mirror the SendCoins
and SendCoinsFromModuleToAccount
functions that already exist in bank. (SendCoins is in x/bank/keeper/send.go, SendCoinsFromModuleToAccount is in x/bank/keeper/keeper.go
)
Heres the brief adaptation of each, bsaically taking the single case, and putting recipients in a loop:
func (k BaseKeeper) SendCoinsFromModuleToManyAccounts(
ctx sdk.Context, senderModule string, recipientAddrs []sdk.AccAddress, amts []sdk.Coins,
) error {
if len(recipientAddrs) != len(amts) {
panic({MAKE AN ERROR HERE})
}
senderAddr := k.ak.GetModuleAddress(senderModule)
if senderAddr == nil {
panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule))
}
for _, recipientAddr := range recipientAddrs {
if k.BlockedAddr(recipientAddr) {
return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", recipientAddr)
}
}
return k.SendManyCoins(ctx, senderAddr, recipientAddrs, amts)
}
func (k BaseSendKeeper) SendManyCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddrs []sdk.AccAddress, amts []sdk.Coins) error {
totalAmt := {sum up all amts}
err := k.subUnlockedCoins(ctx, fromAddr, totalAmt)
if err != nil {
return err
}
fromAddrBech32 := fromAddr.String()
for i, toAddr := range toAddrs {
amt := amts[i]
err = k.addCoins(ctx, toAddr, amt)
if err != nil {
return err
}
// Create account if recipient does not exist.
//
// NOTE: This should ultimately be removed in favor a more flexible approach
// such as delegated fee messages.
acc := k.ak.GetAccount(ctx, toAddr)
if acc == nil {
defer telemetry.IncrCounter(1, "new", "account")
k.ak.SetAccount(ctx, k.ak.NewAccountWithAddress(ctx, toAddr))
}
ctx.EventManager().EmitEvent( sdk.NewEvent(
types.EventTypeTransfer,
sdk.NewAttribute(types.AttributeKeyRecipient, toAddr.String()),
sdk.NewAttribute(types.AttributeKeySender, fromAddrBech32),
sdk.NewAttribute(sdk.AttributeKeyAmount, amt.String()),
),
)
}
}
return nil
}
We should probably also switch SendCoins to use SendManyCoins instead, but thats pretty secondary.
The big gains here is it only bech32 encodes the fromAddr once, only does one subtract from the fromAddr, and only has one event per recipient, not 2 events per recipients.
While all of that sounds silly, its a very big impact at our scale. Standalone 50% events reduction, will be more paired with more osmosis changes. SendCoins is literally where ~all the computation time goes, this eliminates ~half the cost. (Actually more, because subtracting coins for weird reasons costed more than adding coins)
For Admin Use