-
Notifications
You must be signed in to change notification settings - Fork 629
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
imp (api)!: convert coins to token only once in MsgTransfer #7110
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,13 +24,6 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. | |
return nil, err | ||
} | ||
|
||
if msg.Forwarding.GetUnwind() { | ||
msg, err = k.unwindHops(ctx, msg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
coins := msg.GetCoins() | ||
tokens := make([]types.Token, 0, len(coins)) | ||
for _, coin := range coins { | ||
|
@@ -42,6 +35,13 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. | |
tokens = append(tokens, token) | ||
} | ||
|
||
if msg.Forwarding.GetUnwind() { | ||
msg, err = k.unwindHops(msg, tokens) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
appVersion, found := k.ics4Wrapper.GetAppVersion(ctx, msg.SourcePort, msg.SourceChannel) | ||
if !found { | ||
return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "application version not found for source port: %s and source channel: %s", msg.SourcePort, msg.SourceChannel) | ||
|
@@ -109,8 +109,8 @@ func (k Keeper) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) | |
// unwindHops unwinds the hops present in the tokens denomination and returns the message modified to reflect | ||
// the unwound path to take. It assumes that only a single token is present (as this is verified in ValidateBasic) | ||
// in the tokens list and ensures that the token is not native to the chain. | ||
func (k Keeper) unwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgTransfer, error) { | ||
unwindHops, err := k.getUnwindHops(ctx, msg.GetCoins()) | ||
func (k Keeper) unwindHops(msg *types.MsgTransfer, tokens []types.Token) (*types.MsgTransfer, error) { | ||
unwindHops, err := k.getUnwindHops(tokens) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -130,30 +130,22 @@ func (k Keeper) unwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgT | |
// getUnwindHops returns the hops to be used during unwinding. If coins consists of more than | ||
// one coin, all coins must have the exact same trace, else an error is returned. getUnwindHops | ||
// also validates that the coins are not native to the chain. | ||
func (k Keeper) getUnwindHops(ctx sdk.Context, coins sdk.Coins) ([]types.Hop, error) { | ||
func (Keeper) getUnwindHops(tokens []types.Token) ([]types.Hop, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function can technically be moved out of the keeper now, since it does need to read state to convert coins to token anymore. Happy to do it if it seems the best thing to do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense to me! |
||
// Sanity: validation for MsgTransfer ensures coins are not empty. | ||
if len(coins) == 0 { | ||
if len(tokens) == 0 { | ||
return nil, errorsmod.Wrap(types.ErrInvalidForwarding, "coins cannot be empty") | ||
} | ||
|
||
token, err := k.tokenFromCoin(ctx, coins[0]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
token := tokens[0] | ||
|
||
if token.Denom.IsNative() { | ||
return nil, errorsmod.Wrap(types.ErrInvalidForwarding, "cannot unwind a native token") | ||
} | ||
|
||
unwindTrace := token.Denom.Trace | ||
for _, coin := range coins[1:] { | ||
token, err := k.tokenFromCoin(ctx, coin) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for _, t := range tokens[1:] { | ||
// Implicitly ensures coin we're iterating over is not native. | ||
if !slices.Equal(token.Denom.Trace, unwindTrace) { | ||
if !slices.Equal(t.Denom.Trace, unwindTrace) { | ||
return nil, errorsmod.Wrap(types.ErrInvalidForwarding, "cannot unwind tokens with different traces.") | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -327,13 +327,6 @@ func (suite *KeeperTestSuite) TestUnwindHops() { | |
suite.Require().Equal(*msg, *modified, "expected msg and modified msg are different") | ||
}, | ||
}, | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't believe we need this test anymore, because this would have failed during the conversion we don't perform anymore |
||
"failure: no denom set on keeper", | ||
func() {}, | ||
func(modified *types.MsgTransfer, err error) { | ||
suite.Require().ErrorIs(err, types.ErrDenomNotFound) | ||
}, | ||
}, | ||
{ | ||
"failure: validateBasic() fails due to invalid channelID", | ||
func() { | ||
|
@@ -398,7 +391,15 @@ func (suite *KeeperTestSuite) TestUnwindHops() { | |
) | ||
|
||
tc.malleate() | ||
gotMsg, err := suite.chainA.GetSimApp().TransferKeeper.UnwindHops(suite.chainA.GetContext(), msg) | ||
|
||
tokens := make([]types.Token, 0, len(coins)) | ||
for _, c := range msg.GetCoins() { | ||
token, err := suite.chainA.GetSimApp().TransferKeeper.TokenFromCoin(suite.chainA.GetContext(), c) | ||
suite.Require().NoError(err) | ||
tokens = append(tokens, token) | ||
} | ||
|
||
gotMsg, err := suite.chainA.GetSimApp().TransferKeeper.UnwindHops(msg, tokens) | ||
tc.assertResult(gotMsg, err) | ||
}) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an API-breaking change but since I assume the whole feature branch will this should not be an issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please correct me if I am wrong, but since this function is in a
_test.go
file, then it is not part of the public API, right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's a good point, I wasn't too sure about it tbh!