diff --git a/x/tx/CHANGELOG.md b/x/tx/CHANGELOG.md index 951ee0b521..0a0b60ed6c 100644 --- a/x/tx/CHANGELOG.md +++ b/x/tx/CHANGELOG.md @@ -37,6 +37,7 @@ Since v0.13.0, x/tx follows Cosmos SDK semver: https://github.com/cosmos/cosmos- * SDK v0.53.x support. * [#23708](https://github.com/cosmos/cosmos-sdk/pull/23708) Add unordered transaction support. +* [#24408](https://github.com/cosmos/cosmos-sdk/pull/24408) Fix add feePayer as signer. * [#24409](https://github.com/cosmos/cosmos-sdk/pull/24409) Fallback to injected resolver for placeholder descriptors. ## [v0.13.8](https://github.com/cosmos/cosmos-sdk/releases/tag/x/tx/v0.13.8) - 2025-01-28 diff --git a/x/tx/decode/decode.go b/x/tx/decode/decode.go index 4dafe9549a..d71be86f86 100644 --- a/x/tx/decode/decode.go +++ b/x/tx/decode/decode.go @@ -118,6 +118,18 @@ func (d *Decoder) Decode(txBytes []byte) (*DecodedTx, error) { } } + // If a fee payer is specified in the AuthInfo, it must be added to the list of signers + if authInfo.Fee != nil && authInfo.Fee.Payer != "" { + feeAddr, err := d.signingCtx.AddressCodec().StringToBytes(authInfo.Fee.Payer) + if err != nil { + return nil, errorsmod.Wrap(ErrTxDecode, err.Error()) + } + + if _, seen := seenSigners[string(feeAddr)]; !seen { + signers = append(signers, feeAddr) + } + } + return &DecodedTx{ Messages: msgs, Tx: theTx, diff --git a/x/tx/decode/decode_test.go b/x/tx/decode/decode_test.go index a54702cbe9..5d22e01dba 100644 --- a/x/tx/decode/decode_test.go +++ b/x/tx/decode/decode_test.go @@ -50,19 +50,42 @@ func TestDecode(t *testing.T) { require.NoError(t, err) testCases := []struct { - name string - msg proto.Message - error string + name string + msg proto.Message + feePayer string + error string + expectedSigners int }{ { - name: "happy path", - msg: &bankv1beta1.MsgSend{}, + name: "happy path", + msg: &bankv1beta1.MsgSend{}, + expectedSigners: 1, }, { name: "empty signer option", msg: &testpb.A{}, error: "no cosmos.msg.v1.signer option found for message A; use DefineCustomGetSigners to specify a custom getter: tx parse error", }, + { + name: "invalid feePayer", + msg: &bankv1beta1.MsgSend{}, + feePayer: "payer", + error: `encoding/hex: invalid byte: U+0070 'p': tx parse error`, + }, + { + name: "valid feePayer", + msg: &bankv1beta1.MsgSend{}, + feePayer: "636f736d6f733168363935356b3836397a72306770383975717034337a373263393033666d35647a366b75306c", // hexadecimal to work with dummyAddressCodec + expectedSigners: 2, + }, + { + name: "same msg signer and feePayer", + msg: &bankv1beta1.MsgSend{ + FromAddress: "636f736d6f733168363935356b3836397a72306770383975717034337a373263393033666d35647a366b75306c", + }, + feePayer: "636f736d6f733168363935356b3836397a72306770383975717034337a373263393033666d35647a366b75306c", + expectedSigners: 1, + }, } for _, tc := range testCases { @@ -83,7 +106,7 @@ func TestDecode(t *testing.T) { Fee: &txv1beta1.Fee{ Amount: []*basev1beta1.Coin{{Amount: "100", Denom: "denom"}}, GasLimit: 100, - Payer: "payer", + Payer: tc.feePayer, Granter: "", }, }, @@ -98,6 +121,7 @@ func TestDecode(t *testing.T) { return } require.NoError(t, err) + require.Equal(t, len(decodeTx.Signers), tc.expectedSigners) require.Equal(t, fmt.Sprintf("/%s", tc.msg.ProtoReflect().Descriptor().FullName()),