diff --git a/CHANGELOG.md b/CHANGELOG.md index 7021e7154b2..09ea428258f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#2193](https://github.com/osmosis-labs/osmosis/pull/2193) Add TwapKeeper to the Osmosis app * [#2227](https://github.com/osmosis-labs/osmosis/pull/2227) Enable charging fee in base denom for `CreateGauge` and `AddToGauge`. * [#2283](https://github.com/osmosis-labs/osmosis/pull/2283) x/incentives: refactor `CreateGauge` and `AddToGauge` fees to use txfees denom +* [#2206](https://github.com/osmosis-labs/osmosis/pull/2283) Register all Amino interfaces and concrete types on the authz Amino codec. This will allow the authz module to properly serialize and de-serializes instances using Amino. #### Golang API breaks diff --git a/app/apptesting/test_suite.go b/app/apptesting/test_suite.go index 629407c0e68..6b44ed63f93 100644 --- a/app/apptesting/test_suite.go +++ b/app/apptesting/test_suite.go @@ -1,21 +1,27 @@ package apptesting import ( + "encoding/json" "fmt" + "testing" "time" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/store/rootmulti" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/cosmos/cosmos-sdk/x/authz" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking/teststaking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/ed25519" @@ -323,6 +329,45 @@ func CreateRandomAccounts(numAccts int) []sdk.AccAddress { return testAddrs } +func TestMessageAuthzSerialization(t *testing.T, msg sdk.Msg) { + someDate := time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC) + const ( + mockGranter string = "cosmos1abc" + mockGrantee string = "cosmos1xyz" + ) + + var ( + mockMsgGrant authz.MsgGrant + mockMsgRevoke authz.MsgRevoke + mockMsgExec authz.MsgExec + ) + + // Authz: Grant Msg + typeURL := sdk.MsgTypeURL(msg) + grant, err := authz.NewGrant(someDate, authz.NewGenericAuthorization(typeURL), someDate.Add(time.Hour)) + require.NoError(t, err) + + msgGrant := authz.MsgGrant{Granter: mockGranter, Grantee: mockGrantee, Grant: grant} + msgGrantBytes := json.RawMessage(sdk.MustSortJSON(authzcodec.ModuleCdc.MustMarshalJSON(&msgGrant))) + err = authzcodec.ModuleCdc.UnmarshalJSON(msgGrantBytes, &mockMsgGrant) + require.NoError(t, err) + + // Authz: Revoke Msg + msgRevoke := authz.MsgRevoke{Granter: mockGranter, Grantee: mockGrantee, MsgTypeUrl: typeURL} + msgRevokeByte := json.RawMessage(sdk.MustSortJSON(authzcodec.ModuleCdc.MustMarshalJSON(&msgRevoke))) + err = authzcodec.ModuleCdc.UnmarshalJSON(msgRevokeByte, &mockMsgRevoke) + require.NoError(t, err) + + // Authz: Exec Msg + msgAny, err := cdctypes.NewAnyWithValue(msg) + require.NoError(t, err) + msgExec := authz.MsgExec{Grantee: mockGrantee, Msgs: []*cdctypes.Any{msgAny}} + execMsgByte := json.RawMessage(sdk.MustSortJSON(authzcodec.ModuleCdc.MustMarshalJSON(&msgExec))) + err = authzcodec.ModuleCdc.UnmarshalJSON(execMsgByte, &mockMsgExec) + require.NoError(t, err) + require.Equal(t, msgExec.Msgs[0].Value, mockMsgExec.Msgs[0].Value) +} + func GenerateTestAddrs() (string, string) { pk1 := ed25519.GenPrivKey().PubKey() validAddr := sdk.AccAddress(pk1.Address()).String() diff --git a/x/gamm/types/codec.go b/x/gamm/types/codec.go index c0d961f54a6..d00a4182bc9 100644 --- a/x/gamm/types/codec.go +++ b/x/gamm/types/codec.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" ) // RegisterLegacyAminoCodec registers the necessary x/gamm interfaces and concrete types @@ -55,5 +56,10 @@ var ( func init() { RegisterLegacyAminoCodec(amino) + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + sdk.RegisterLegacyAminoCodec(amino) + RegisterLegacyAminoCodec(authzcodec.Amino) + amino.Seal() } diff --git a/x/gamm/types/msgs_test.go b/x/gamm/types/msgs_test.go index b4715c2b583..7c63a5b988b 100644 --- a/x/gamm/types/msgs_test.go +++ b/x/gamm/types/msgs_test.go @@ -9,6 +9,7 @@ import ( gammtypes "github.com/osmosis-labs/osmosis/v10/x/gamm/types" + "github.com/osmosis-labs/osmosis/v10/app/apptesting" appParams "github.com/osmosis-labs/osmosis/v10/app/params" ) @@ -868,3 +869,97 @@ func TestMsgExitSwapShareAmountIn(t *testing.T) { } } } + +// Test authz serialize and de-serializes for gamm msg. +func TestAuthzMsg(t *testing.T) { + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()).String() + coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1)) + + testCases := []struct { + name string + gammMsg sdk.Msg + }{ + { + name: "MsgExitSwapExternAmountOut", + gammMsg: &gammtypes.MsgExitSwapShareAmountIn{ + Sender: addr1, + PoolId: 1, + TokenOutDenom: "test", + ShareInAmount: sdk.NewInt(100), + TokenOutMinAmount: sdk.NewInt(100), + }, + }, + { + name: `MsgExitSwapExternAmountOut`, + gammMsg: &gammtypes.MsgExitSwapExternAmountOut{ + Sender: addr1, + PoolId: 1, + TokenOut: coin, + ShareInMaxAmount: sdk.NewInt(1), + }, + }, + { + name: "MsgExitPool", + gammMsg: &gammtypes.MsgExitPool{ + Sender: addr1, + PoolId: 1, + ShareInAmount: sdk.NewInt(100), + TokenOutMins: sdk.NewCoins(coin), + }, + }, + { + name: "MsgJoinPool", + gammMsg: &gammtypes.MsgJoinPool{ + Sender: addr1, + PoolId: 1, + ShareOutAmount: sdk.NewInt(1), + TokenInMaxs: sdk.NewCoins(coin), + }, + }, + { + name: "MsgJoinSwapExternAmountIn", + gammMsg: &gammtypes.MsgJoinSwapExternAmountIn{ + Sender: addr1, + PoolId: 1, + TokenIn: coin, + ShareOutMinAmount: sdk.NewInt(1), + }, + }, + { + name: "MsgJoinSwapShareAmountOut", + gammMsg: &gammtypes.MsgSwapExactAmountIn{ + Sender: addr1, + Routes: []gammtypes.SwapAmountInRoute{{ + PoolId: 0, + TokenOutDenom: "test", + }, { + PoolId: 1, + TokenOutDenom: "test2", + }}, + TokenIn: coin, + TokenOutMinAmount: sdk.NewInt(1), + }, + }, + { + name: "MsgSwapExactAmountOut", + gammMsg: &gammtypes.MsgSwapExactAmountOut{ + Sender: addr1, + Routes: []gammtypes.SwapAmountOutRoute{{ + PoolId: 0, + TokenInDenom: "test", + }, { + PoolId: 1, + TokenInDenom: "test2", + }}, + TokenOut: coin, + TokenInMaxAmount: sdk.NewInt(1), + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + apptesting.TestMessageAuthzSerialization(t, tc.gammMsg) + }) + } +} diff --git a/x/incentives/types/codec.go b/x/incentives/types/codec.go index 07c7a66698d..7d948cdf770 100644 --- a/x/incentives/types/codec.go +++ b/x/incentives/types/codec.go @@ -5,6 +5,7 @@ import ( cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" ) var ( @@ -32,5 +33,10 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { func init() { RegisterCodec(amino) + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + sdk.RegisterLegacyAminoCodec(amino) + RegisterCodec(authzcodec.Amino) + amino.Seal() } diff --git a/x/incentives/types/msgs_test.go b/x/incentives/types/msgs_test.go index 322895e0a1b..cda7d4f362e 100644 --- a/x/incentives/types/msgs_test.go +++ b/x/incentives/types/msgs_test.go @@ -11,6 +11,9 @@ import ( incentivestypes "github.com/osmosis-labs/osmosis/v10/x/incentives/types" + "github.com/osmosis-labs/osmosis/v10/app/apptesting" + + appParams "github.com/osmosis-labs/osmosis/v10/app/params" lockuptypes "github.com/osmosis-labs/osmosis/v10/x/lockup/types" ) @@ -212,3 +215,51 @@ func TestMsgAddToGauge(t *testing.T) { } } } + +// // Test authz serialize and de-serializes for incentives msg. +func TestAuthzMsg(t *testing.T) { + appParams.SetAddressPrefixes() + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()).String() + coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1)) + someDate := time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC) + + const ( + mockGranter string = "cosmos1abc" + mockGrantee string = "cosmos1xyz" + ) + + testCases := []struct { + name string + incentivesMsg sdk.Msg + }{ + { + name: "MsgAddToGauge", + incentivesMsg: &incentivestypes.MsgAddToGauge{ + Owner: addr1, + GaugeId: 1, + Rewards: sdk.NewCoins(coin), + }, + }, + { + name: "MsgCreateGauge", + incentivesMsg: &incentivestypes.MsgCreateGauge{ + IsPerpetual: false, + Owner: addr1, + DistributeTo: lockuptypes.QueryCondition{ + LockQueryType: lockuptypes.ByDuration, + Denom: "lptoken", + Duration: time.Second, + }, + Coins: sdk.NewCoins(coin), + StartTime: someDate, + NumEpochsPaidOver: 1, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + apptesting.TestMessageAuthzSerialization(t, tc.incentivesMsg) + }) + } +} diff --git a/x/lockup/types/codec.go b/x/lockup/types/codec.go index 5faea80aaaa..d15b1353f24 100644 --- a/x/lockup/types/codec.go +++ b/x/lockup/types/codec.go @@ -5,6 +5,7 @@ import ( cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" ) func RegisterCodec(cdc *codec.LegacyAmino) { @@ -30,5 +31,10 @@ var ( func init() { RegisterCodec(amino) + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + sdk.RegisterLegacyAminoCodec(amino) + RegisterCodec(authzcodec.Amino) + amino.Seal() } diff --git a/x/lockup/types/msgs_test.go b/x/lockup/types/msgs_test.go index 63d0aa097b4..d07ff050252 100644 --- a/x/lockup/types/msgs_test.go +++ b/x/lockup/types/msgs_test.go @@ -9,8 +9,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/osmosis-labs/osmosis/v10/app/apptesting" - appParams "github.com/osmosis-labs/osmosis/v10/app/params" "github.com/osmosis-labs/osmosis/v10/x/lockup/types" + + "github.com/tendermint/tendermint/crypto/ed25519" + + appParams "github.com/osmosis-labs/osmosis/v10/app/params" ) func TestMsgLockTokens(t *testing.T) { @@ -248,3 +251,48 @@ func TestMsgExtendLockup(t *testing.T) { }) } } + +// // Test authz serialize and de-serializes for lockup msg. +func TestAuthzMsg(t *testing.T) { + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()).String() + coin := sdk.NewCoin("denom", sdk.NewInt(1)) + + const ( + mockGranter string = "cosmos1abc" + mockGrantee string = "cosmos1xyz" + ) + + testCases := []struct { + name string + msg sdk.Msg + }{ + { + name: "MsgLockTokens", + msg: &types.MsgLockTokens{ + Owner: addr1, + Duration: time.Hour, + Coins: sdk.NewCoins(coin), + }, + }, + { + name: "MsgBeginUnlocking", + msg: &types.MsgBeginUnlocking{ + Owner: addr1, + ID: 1, + Coins: sdk.NewCoins(coin), + }, + }, + { + name: "MsgBeginUnlockingAll", + msg: &types.MsgBeginUnlockingAll{ + Owner: addr1, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + apptesting.TestMessageAuthzSerialization(t, tc.msg) + }) + } +} diff --git a/x/superfluid/types/codec.go b/x/superfluid/types/codec.go index d766d0057f5..2387c279b80 100644 --- a/x/superfluid/types/codec.go +++ b/x/superfluid/types/codec.go @@ -5,6 +5,7 @@ import ( cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -44,5 +45,10 @@ var ( func init() { RegisterCodec(amino) + sdk.RegisterLegacyAminoCodec(amino) + + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + RegisterCodec(authzcodec.Amino) amino.Seal() } diff --git a/x/superfluid/types/msg_test.go b/x/superfluid/types/msg_test.go new file mode 100644 index 00000000000..68b4e7aa522 --- /dev/null +++ b/x/superfluid/types/msg_test.go @@ -0,0 +1,72 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/v10/app/apptesting" + "github.com/osmosis-labs/osmosis/v10/x/superfluid/types" + + "github.com/tendermint/tendermint/crypto/ed25519" +) + +// // Test authz serialize and de-serializes for superfluid msg. +func TestAuthzMsg(t *testing.T) { + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()).String() + coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1)) + + const ( + mockGranter string = "cosmos1abc" + mockGrantee string = "cosmos1xyz" + ) + + testCases := []struct { + name string + msg sdk.Msg + }{ + { + name: "MsgLockAndSuperfluidDelegate", + msg: &types.MsgLockAndSuperfluidDelegate{ + Sender: addr1, + Coins: sdk.NewCoins(coin), + ValAddr: "valoper1xyz", + }, + }, + { + name: "MsgSuperfluidDelegate", + msg: &types.MsgSuperfluidDelegate{ + Sender: addr1, + LockId: 1, + ValAddr: "valoper1xyz", + }, + }, + { + name: "MsgSuperfluidUnbondLock", + msg: &types.MsgSuperfluidUnbondLock{ + Sender: addr1, + LockId: 1, + }, + }, + { + name: "MsgSuperfluidUndelegate", + msg: &types.MsgSuperfluidUndelegate{ + Sender: addr1, + LockId: 1, + }, + }, + { + name: "MsgUnPoolWhitelistedPool", + msg: &types.MsgUnPoolWhitelistedPool{ + Sender: addr1, + PoolId: 1, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + apptesting.TestMessageAuthzSerialization(t, tc.msg) + }) + } +} diff --git a/x/tokenfactory/types/codec.go b/x/tokenfactory/types/codec.go index 6b7571f7005..b086a51e17f 100644 --- a/x/tokenfactory/types/codec.go +++ b/x/tokenfactory/types/codec.go @@ -4,6 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" // this line is used by starport scaffolding # 1 "github.com/cosmos/cosmos-sdk/types/msgservice" @@ -36,5 +37,10 @@ var ( func init() { RegisterCodec(amino) + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + sdk.RegisterLegacyAminoCodec(amino) + RegisterCodec(authzcodec.Amino) + amino.Seal() } diff --git a/x/tokenfactory/types/msgs_test.go b/x/tokenfactory/types/msgs_test.go new file mode 100644 index 00000000000..3e9be48e3db --- /dev/null +++ b/x/tokenfactory/types/msgs_test.go @@ -0,0 +1,64 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/v10/app/apptesting" + "github.com/osmosis-labs/osmosis/v10/x/tokenfactory/types" + + "github.com/tendermint/tendermint/crypto/ed25519" +) + +// // Test authz serialize and de-serializes for tokenfactory msg. +func TestAuthzMsg(t *testing.T) { + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()).String() + coin := sdk.NewCoin("denom", sdk.NewInt(1)) + + const ( + mockGranter string = "cosmos1abc" + mockGrantee string = "cosmos1xyz" + ) + + testCases := []struct { + name string + msg sdk.Msg + }{ + { + name: "MsgCreateDenom", + msg: &types.MsgCreateDenom{ + Sender: addr1, + Subdenom: "valoper1xyz", + }, + }, + { + name: "MsgBurn", + msg: &types.MsgBurn{ + Sender: addr1, + Amount: coin, + }, + }, + { + name: "MsgMint", + msg: &types.MsgMint{ + Sender: addr1, + Amount: coin, + }, + }, + { + name: "MsgChangeAdmin", + msg: &types.MsgChangeAdmin{ + Sender: addr1, + Denom: "denom", + NewAdmin: "osmo1q8tq5qhrhw6t970egemuuwywhlhpnmdmts6xnu", + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + apptesting.TestMessageAuthzSerialization(t, tc.msg) + }) + } +}