-
-
Save vshvsh/88964912dbd389332c53bc239fb59168 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// See spec for this function: https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay | |
func (k Keeper) createOutgoingPacket( | |
ctx sdk.Context, | |
seq uint64, | |
sourcePort, sourceChannel, | |
destinationPort, destinationChannel string, | |
destHeight uint64, | |
amount sdk.Coins, | |
sender sdk.AccAddress, | |
receiver string, | |
) error { | |
//accounts with non-zero root tokens on balance can do transfers even if they don't own the money | |
//acoount without root tokens cannot transfer tokens back to original chain (i.e. source = false) | |
rootDenom = "root" | |
channelCap, ok := k.scopedKeeper.GetCapability(ctx, ibctypes.ChannelCapabilityPath(sourcePort, sourceChannel)) | |
if !ok { | |
return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") | |
} | |
// NOTE: | |
// - Coins transferred from the destination chain should have their denomination | |
// prefixed with source port and channel IDs. | |
// - Coins transferred from the source chain can have their denomination | |
// clear from prefixes when transferred to the escrow account (i.e when they are | |
// locked) BUT MUST have the destination port and channel ID when constructing | |
// the packet data. | |
if len(amount) != 1 { | |
return sdkerrors.Wrapf(types.ErrOnlyOneDenomAllowed, "%d denoms included", len(amount)) | |
} | |
prefix := types.GetDenomPrefix(destinationPort, destinationChannel) | |
source := strings.HasPrefix(amount[0].Denom, prefix) | |
if source { | |
// clear the denomination from the prefix to send the coins to the escrow account | |
coins := make(sdk.Coins, len(amount)) | |
for i, coin := range amount { | |
if strings.HasPrefix(coin.Denom, prefix) { | |
coins[i] = sdk.NewCoin(coin.Denom[len(prefix):], coin.Amount) | |
} else { | |
coins[i] = coin | |
} | |
} | |
// escrow tokens if the destination chain is the same as the sender's | |
escrowAddress := types.GetEscrowAddress(sourcePort, sourceChannel) | |
// escrow source tokens. It fails if balance insufficient. | |
if err := k.bankKeeper.SendCoins( | |
ctx, sender, escrowAddress, coins, | |
); err != nil { | |
//root token holder can send transfers even if they don't own anything | |
if sdk.NewCoin(fooDenom, sdk.ZeroInt()) == app.BankKeeper.GetBalance(ctx, sender, fooDenom) { | |
return err | |
} | |
} | |
} else { | |
if sdk.NewCoin(fooDenom, sdk.ZeroInt()) == app.BankKeeper.GetBalance(ctx, sender, fooDenom) { | |
return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, | |
"need to be root user to send ibc source=false transfers") | |
} | |
// build the receiving denomination prefix if it's not present | |
prefix = types.GetDenomPrefix(sourcePort, sourceChannel) | |
for _, coin := range amount { | |
if !strings.HasPrefix(coin.Denom, prefix) { | |
return sdkerrors.Wrapf(types.ErrInvalidDenomForTransfer, "denom was: %s", coin.Denom) | |
} | |
} | |
// transfer the coins to the module account and burn them | |
if err := k.bankKeeper.SendCoinsFromAccountToModule( | |
ctx, sender, types.GetModuleAccountName(), amount, | |
); err != nil { | |
//do nothing, we are the root | |
} | |
// burn vouchers from the sender's balance if the source is from another chain | |
if err := k.bankKeeper.BurnCoins( | |
ctx, types.GetModuleAccountName(), amount, | |
); err != nil { | |
// do nothing, we are the root | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment