diff --git a/Makefile b/Makefile index 84f66ba9..40b1f31b 100644 --- a/Makefile +++ b/Makefile @@ -295,9 +295,6 @@ test-integration-xion-treasury-grants: compile_integration_tests @XION_TEST_IMAGE=$(XION_TEST_IMAGE) ./integration_tests/integration_tests.test -test.failfast -test.v -test.run TestTreasuryContract test-integration-xion-update-treasury-configs: compile_integration_tests - @XION_TEST_IMAGE=$(XION_TEST_IMAGE) ./integration_tests/integration_tests.test -test.failfast -test.v -test.run TestUpdateTreasuryConfigs - -test-integration-xion-update-treasury-configs-cli: compile_integration_tests @XION_TEST_IMAGE=$(XION_TEST_IMAGE) ./integration_tests/integration_tests.test -test.failfast -test.v -test.run TestUpdateTreasuryConfigsWithCLI test-integration-xion-treasury-multi: compile_integration_tests diff --git a/integration_tests/testdata/contracts/treasury-aarch64.wasm b/integration_tests/testdata/contracts/treasury-aarch64.wasm index 6c2999a3..a0712f25 100755 Binary files a/integration_tests/testdata/contracts/treasury-aarch64.wasm and b/integration_tests/testdata/contracts/treasury-aarch64.wasm differ diff --git a/integration_tests/testdata/unsigned_msgs/fee_configs.json b/integration_tests/testdata/unsigned_msgs/fee_configs.json index 16ed1146..e6e1b0fb 100644 --- a/integration_tests/testdata/unsigned_msgs/fee_configs.json +++ b/integration_tests/testdata/unsigned_msgs/fee_configs.json @@ -1,10 +1,8 @@ -[ - { - "description": "Fee allowance for user1", - "allowance": { - "type_url": "/cosmos.feegrant.v1.BasicAllowance", - "value": "CgQICAI=" - }, - "expiration": 1715151235 - } -] +{ + "description": "Fee allowance for user1", + "allowance": { + "type_url": "/cosmos.feegrant.v1.BasicAllowance", + "value": "CgQICAI=" + }, + "expiration": 1715151235 +} diff --git a/integration_tests/update_treasury_configs_test.go b/integration_tests/update_treasury_configs_test.go index 1a75a8e5..fca76318 100644 --- a/integration_tests/update_treasury_configs_test.go +++ b/integration_tests/update_treasury_configs_test.go @@ -14,130 +14,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestUpdateTreasuryConfigs(t *testing.T) { - // Setup Xion chain - td := BuildXionChain(t, "0.0uxion", nil) - xion, ctx := td.xionChain, td.ctx - - config := types.GetConfig() - config.SetBech32PrefixForAccount("xion", "xionpub") - - // Create and fund test user - t.Log("Creating and funding user accounts") - fundAmount := math.NewInt(10_000_000) - users := ibctest.GetAndFundTestUsers(t, ctx, "default", fundAmount, xion) - xionUser := users[0] - - err := testutil.WaitForBlocks(ctx, 2, xion) - require.NoError(t, err) - - // Deploy contract - t.Log("Deploying contract") - fp, err := os.Getwd() - require.NoError(t, err) - - codeIDStr, err := xion.StoreContract(ctx, xionUser.FormattedAddress(), - path.Join(fp, "integration_tests", "testdata", "contracts", "treasury-aarch64.wasm")) - require.NoError(t, err) - - // Instantiate contract - t.Log("Instantiating contract") - instantiateMsg := TreasuryInstantiateMsg{ - TypeUrls: []string{}, - GrantConfigs: []GrantConfig{}, - FeeConfig: &FeeConfig{ - Description: "test fee grant", - }, - } - instantiateMsgStr, err := json.Marshal(instantiateMsg) - require.NoError(t, err) - - treasuryAddr, err := xion.InstantiateContract(ctx, xionUser.KeyName(), codeIDStr, string(instantiateMsgStr), true) - require.NoError(t, err) - - // Read JSON files for grants and fee configs - t.Log("Reading configuration JSON files") - grantsFile, err := os.ReadFile(path.Join(fp, "integration_tests", "testdata", "unsigned_msgs", "grants.json")) - require.NoError(t, err) - - feeConfigsFile, err := os.ReadFile(path.Join(fp, "integration_tests", "testdata", "unsigned_msgs", "fee_configs.json")) - require.NoError(t, err) - - var grants []map[string]interface{} - var feeConfigs []FeeConfig - err = json.Unmarshal(grantsFile, &grants) - require.NoError(t, err) - - err = json.Unmarshal(feeConfigsFile, &feeConfigs) - require.NoError(t, err) - - // Construct update_configs execute message - t.Log("Constructing update_configs message") - executeMsg := map[string]interface{}{ - "update_configs": map[string]interface{}{ - "grants": grants, - "fee_configs": feeConfigs, - }, - } - executeMsgStr, err := json.Marshal(executeMsg) - require.NoError(t, err) - - executeCmd := []string{ - "wasm", "execute", treasuryAddr, string(executeMsgStr), "--chain-id", xion.Config().ChainID, - } - - _, err = ExecTx(t, ctx, xion.GetNode(), xionUser.KeyName(), executeCmd...) - require.NoError(t, err) - - // Query and validate Grant Config URLs - t.Log("Querying grant config type URLs") - grantQueryMsg := map[string]interface{}{ - "grant_config_type_urls": struct{}{}, - } - grantQueryMsgStr, err := json.Marshal(grantQueryMsg) - require.NoError(t, err) - - grantQueryRaw, err := ExecQuery(t, ctx, xion.GetNode(), "wasm", "contract-state", "smart", treasuryAddr, string(grantQueryMsgStr)) - require.NoError(t, err) - - grantQueryBytes, err := json.Marshal(grantQueryRaw["data"]) - require.NoError(t, err) - - var queriedGrantConfigUrls []string - err = json.Unmarshal(grantQueryBytes, &queriedGrantConfigUrls) - require.NoError(t, err) - - // Validate that all grants are in the contract state - require.Equal(t, len(grants), len(queriedGrantConfigUrls)) - for _, grant := range grants { - msgTypeURL := grant["msg_type_url"].(string) - require.Contains(t, queriedGrantConfigUrls, msgTypeURL) - } - - // Query and validate Fee Config - t.Log("Querying fee config") - feeQueryMsg := map[string]interface{}{ - "fee_config": struct{}{}, - } - feeQueryMsgStr, err := json.Marshal(feeQueryMsg) - require.NoError(t, err) - - feeQueryRaw, err := ExecQuery(t, ctx, xion.GetNode(), "wasm", "contract-state", "smart", treasuryAddr, string(feeQueryMsgStr)) - require.NoError(t, err) - - feeQueryBytes, err := json.Marshal(feeQueryRaw["data"]) - require.NoError(t, err) - - var queriedFeeConfig FeeConfig - err = json.Unmarshal(feeQueryBytes, &queriedFeeConfig) - require.NoError(t, err) - - // Validate Fee Config - require.Equal(t, len(feeConfigs), 1) - require.Equal(t, feeConfigs[0].Description, queriedFeeConfig.Description) - require.Equal(t, feeConfigs[0].Allowance.TypeURL, queriedFeeConfig.Allowance.TypeURL) -} - func TestUpdateTreasuryConfigsWithCLI(t *testing.T) { // Setup Xion chain td := BuildXionChain(t, "0.0uxion", nil) @@ -187,30 +63,11 @@ func TestUpdateTreasuryConfigsWithCLI(t *testing.T) { feeConfigsFile, err := os.CreateTemp("", "*-fee_configs.json") require.NoError(t, err) - grantsData := []byte(`[ - { - "msg_type_url": "/cosmos.bank.v1.MsgSend", - "grant_config": { - "description": "Bank grant", - "authorization": { - "type_url": "/cosmos.authz.v1.GenericAuthorization", - "value": "CgRQYXk=" - }, - "optional": true - } - } - ]`) + grantsData, err := os.ReadFile(path.Join(fp, "integration_tests", "testdata", "unsigned_msgs", "grants.json")) + require.NoError(t, err) - feeConfigsData := []byte(`[ - { - "description": "Fee allowance for user1", - "allowance": { - "type_url": "/cosmos.feegrant.v1.BasicAllowance", - "value": "CgQICAI=" - }, - "expiration": 1715151235 - } - ]`) + feeConfigsData, err := os.ReadFile(path.Join(fp, "integration_tests", "testdata", "unsigned_msgs", "fee_configs.json")) + require.NoError(t, err) _, err = grantsFile.Write(grantsData) require.NoError(t, err) @@ -260,7 +117,7 @@ func TestUpdateTreasuryConfigsWithCLI(t *testing.T) { require.NoError(t, err) // Validate that all grants are in the contract state - require.Equal(t, 1, len(queriedGrantConfigUrls)) + require.Equal(t, 2, len(queriedGrantConfigUrls)) require.Equal(t, "/cosmos.bank.v1.MsgSend", queriedGrantConfigUrls[0]) // Query and validate Fee Config diff --git a/x/xion/client/cli/tx.go b/x/xion/client/cli/tx.go index 930a39a7..232964e8 100644 --- a/x/xion/client/cli/tx.go +++ b/x/xion/client/cli/tx.go @@ -516,9 +516,30 @@ func NewSignCmd() *cobra.Command { } func NewUpdateConfigsCmd() *cobra.Command { + type ExplicitAny struct { + TypeURL string `json:"type_url"` + Value []byte `json:"value"` + } + + type GrantConfig struct { + Description string `json:"description"` + Authorization ExplicitAny `json:"authorization"` + Optional bool `json:"optional"` + } + + type UpdateGrantConfig struct { + MsgTypeURL string `json:"msg_type_url"` + GrantConfig GrantConfig `json:"grant_config"` + } + + type FeeConfig struct { + Description string `json:"description"` + Allowance *ExplicitAny `json:"allowance,omitempty"` + Expiration int32 `json:"expiration,omitempty"` + } cmd := &cobra.Command{ - Use: "update-configs [contract-address] [grants-json-file] [fee-configs-json-file]", - Short: "Update grant and fee configurations in the treasury contract", + Use: "update-configs [contract] [grants_file] [fee_configs_file]", + Short: "Batch update grant configs and fee config for the treasury", Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) @@ -526,59 +547,73 @@ func NewUpdateConfigsCmd() *cobra.Command { return err } - // Parse arguments - contractAddress := args[0] + contract := args[0] grantsFile := args[1] feeConfigsFile := args[2] - // Read and parse grants JSON file grantsData, err := os.ReadFile(grantsFile) if err != nil { - return fmt.Errorf("failed to read grants JSON file: %w", err) + return fmt.Errorf("failed to read grants file: %w", err) } - var grants []map[string]interface{} + var grants []UpdateGrantConfig if err := json.Unmarshal(grantsData, &grants); err != nil { - return fmt.Errorf("failed to parse grants JSON file: %w", err) + return fmt.Errorf("failed to unmarshal grants: %w", err) } - // Read and parse fee configs JSON file feeConfigsData, err := os.ReadFile(feeConfigsFile) if err != nil { - return fmt.Errorf("failed to read fee configs JSON file: %w", err) + return fmt.Errorf("failed to read fee configs file: %w", err) + } + var feeConfig FeeConfig + if err := json.Unmarshal(feeConfigsData, &feeConfig); err != nil { + return fmt.Errorf("failed to unmarshal fee configs: %w", err) } - var feeConfigs []map[string]interface{} - if err := json.Unmarshal(feeConfigsData, &feeConfigs); err != nil { - return fmt.Errorf("failed to parse fee configs JSON file: %w", err) + var msgs []sdk.Msg + for _, grant := range grants { + executeMsg := map[string]interface{}{ + "update_grant_config": map[string]interface{}{ + "msg_type_url": grant.MsgTypeURL, + "grant_config": grant.GrantConfig, + }, + } + msgBz, err := json.Marshal(executeMsg) + if err != nil { + return fmt.Errorf("failed to marshal execute message for grant: %w", err) + } + msg := &wasmtypes.MsgExecuteContract{ + Sender: clientCtx.GetFromAddress().String(), + Contract: contract, + Msg: msgBz, + Funds: sdk.Coins{}, + } + msgs = append(msgs, msg) } - // Construct execute message - executeMsg := map[string]interface{}{ - "update_configs": map[string]interface{}{ - "grants": grants, - "fee_configs": feeConfigs, + feeExecuteMsg := map[string]interface{}{ + "update_fee_config": map[string]interface{}{ + "fee_config": feeConfig, }, } - - msgBz, err := json.Marshal(executeMsg) + feeMsgBz, err := json.Marshal(feeExecuteMsg) if err != nil { - return fmt.Errorf("failed to serialize execute message: %w", err) + return fmt.Errorf("failed to marshal execute message for fee config: %w", err) } - - // Create and broadcast transaction - msg := wasmtypes.MsgExecuteContract{ + feeMsg := &wasmtypes.MsgExecuteContract{ Sender: clientCtx.GetFromAddress().String(), - Contract: contractAddress, - Msg: msgBz, - Funds: nil, + Contract: contract, + Msg: feeMsgBz, + Funds: sdk.Coins{}, } + msgs = append(msgs, feeMsg) - if err := msg.ValidateBasic(); err != nil { - return err + err = tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msgs...) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + return nil }, } diff --git a/x/xion/client/cli/tx_test.go b/x/xion/client/cli/tx_test.go index f9b04c20..74eeeed7 100644 --- a/x/xion/client/cli/tx_test.go +++ b/x/xion/client/cli/tx_test.go @@ -219,7 +219,6 @@ func (s *CLITestSuite) TestUpdateConfigsCmd() { cmd := cli.NewUpdateConfigsCmd() cmd.SetOutput(io.Discard) - // Prepare mock JSON files for grants and fee configs grantsFile := "grants.json" feeConfigsFile := "fee_configs.json" @@ -228,17 +227,28 @@ func (s *CLITestSuite) TestUpdateConfigsCmd() { { "msg_type_url": "/cosmos.bank.v1.MsgSend", "grant_config": { - "description": "Bank grant", - "authorization": { - "type_url": "/cosmos.authz.v1.GenericAuthorization", - "value": "CgRQYXk=" - }, - "optional": true + "description": "Bank grant", + "authorization": { + "type_url": "/cosmos.authz.v1.GenericAuthorization", + "value": "CgRQYXk=" + }, + "optional": true + } + }, + { + "msg_type_url": "/cosmos.staking.v1.MsgDelegate", + "grant_config": { + "description": "Staking grant", + "authorization": { + "type_url": "/cosmos.authz.v1.GenericAuthorization", + "value": "CgREZWxlZ2F0ZQ==" + }, + "optional": false } } ]`) - feeConfigsData := []byte(`[ + feeConfigsData := []byte(` { "description": "Fee allowance for user1", "allowance": { @@ -247,7 +257,7 @@ func (s *CLITestSuite) TestUpdateConfigsCmd() { }, "expiration": 1715151235 } - ]`) + `) require.NoError(s.T(), os.WriteFile(grantsFile, grantsData, 0600)) defer os.Remove(grantsFile)