diff --git a/PENDING.md b/PENDING.md index 3f5a4146c81e..efe4508df495 100644 --- a/PENDING.md +++ b/PENDING.md @@ -3,6 +3,8 @@ BREAKING CHANGES * Gaia REST API (`gaiacli advanced rest-server`) + * [\#3284](https://github.com/cosmos/cosmos-sdk/issues/3284) Rename the `name` + field to `from` in the `base_req` body. * Gaia CLI (`gaiacli`) @@ -31,6 +33,11 @@ FEATURES IMPROVEMENTS * Gaia REST API + * [\#3284](https://github.com/cosmos/cosmos-sdk/issues/3284) Update Gaia Lite + REST service to support the following: + * Automatic account number and sequence population when fields are omitted + * Generate only functionality no longer requires access to a local Keybase + * `from` field in the `base_req` body can be a Keybase name or account address * Gaia CLI (`gaiacli`) diff --git a/client/context/context.go b/client/context/context.go index 6950122c432e..a253a88fae55 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -8,7 +8,9 @@ import ( "path/filepath" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" + cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/spf13/viper" @@ -19,14 +21,10 @@ import ( tmliteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" - "github.com/cosmos/cosmos-sdk/client/keys" - cskeys "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) -var ( - verifier tmlite.Verifier -) +var verifier tmlite.Verifier // CLIContext implements a typical CLI context created in SDK modules for // transaction handling and queries. @@ -47,8 +45,8 @@ type CLIContext struct { Verifier tmlite.Verifier Simulate bool GenerateOnly bool - fromAddress types.AccAddress - fromName string + FromAddress sdk.AccAddress + FromName string Indent bool } @@ -63,7 +61,11 @@ func NewCLIContext() CLIContext { } from := viper.GetString(client.FlagFrom) - fromAddress, fromName := fromFields(from) + fromAddress, fromName, err := GetFromFields(from) + if err != nil { + fmt.Printf("failed to get from fields: %v", err) + os.Exit(1) + } // We need to use a single verifier for all contexts if verifier == nil { @@ -85,8 +87,8 @@ func NewCLIContext() CLIContext { Verifier: verifier, Simulate: viper.GetBool(client.FlagDryRun), GenerateOnly: viper.GetBool(client.FlagGenerateOnly), - fromAddress: fromAddress, - fromName: fromName, + FromAddress: fromAddress, + FromName: fromName, Indent: viper.GetBool(client.FlagIndentResponse), } } @@ -137,37 +139,6 @@ func createVerifier() tmlite.Verifier { return verifier } -func fromFields(from string) (fromAddr types.AccAddress, fromName string) { - if from == "" { - return nil, "" - } - - keybase, err := keys.GetKeyBase() - if err != nil { - fmt.Println("no keybase found") - os.Exit(1) - } - - var info cskeys.Info - if addr, err := types.AccAddressFromBech32(from); err == nil { - info, err = keybase.GetByAddress(addr) - if err != nil { - fmt.Printf("could not find key %s\n", from) - os.Exit(1) - } - } else { - info, err = keybase.Get(from) - if err != nil { - fmt.Printf("could not find key %s\n", from) - os.Exit(1) - } - } - - fromAddr = info.GetAddress() - fromName = info.GetName() - return -} - // WithCodec returns a copy of the context with an updated codec. func (ctx CLIContext) WithCodec(cdc *codec.Codec) CLIContext { ctx.Codec = cdc @@ -255,6 +226,19 @@ func (ctx CLIContext) WithSimulation(simulate bool) CLIContext { return ctx } +// WithFromName returns a copy of the context with an updated from account name. +func (ctx CLIContext) WithFromName(name string) CLIContext { + ctx.FromName = name + return ctx +} + +// WithFromAddress returns a copy of the context with an updated from account +// address. +func (ctx CLIContext) WithFromAddress(addr sdk.AccAddress) CLIContext { + ctx.FromAddress = addr + return ctx +} + // PrintOutput prints output while respecting output and indent flags // NOTE: pass in marshalled structs that have been unmarshaled // because this function will panic on marshaling errors @@ -279,3 +263,31 @@ func (ctx CLIContext) PrintOutput(toPrint fmt.Stringer) (err error) { fmt.Println(string(out)) return } + +// GetFromFields returns a from account address and Keybase name given either +// an address or key name. +func GetFromFields(from string) (sdk.AccAddress, string, error) { + if from == "" { + return nil, "", nil + } + + keybase, err := keys.GetKeyBase() + if err != nil { + return nil, "", err + } + + var info cryptokeys.Info + if addr, err := sdk.AccAddressFromBech32(from); err == nil { + info, err = keybase.GetByAddress(addr) + if err != nil { + return nil, "", err + } + } else { + info, err = keybase.Get(from) + if err != nil { + return nil, "", err + } + } + + return info.GetAddress(), info.GetName(), nil +} diff --git a/client/context/query.go b/client/context/query.go index aba8df19095e..cf70b3cea35f 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -82,13 +82,13 @@ func (ctx CLIContext) GetAccount(address []byte) (auth.Account, error) { } // GetFromAddress returns the from address from the context's name. -func (ctx CLIContext) GetFromAddress() (sdk.AccAddress, error) { - return ctx.fromAddress, nil +func (ctx CLIContext) GetFromAddress() sdk.AccAddress { + return ctx.FromAddress } // GetFromName returns the key name for the current context. -func (ctx CLIContext) GetFromName() (string, error) { - return ctx.fromName, nil +func (ctx CLIContext) GetFromName() string { + return ctx.FromName } // GetAccountNumber returns the next account number for the given account @@ -116,11 +116,7 @@ func (ctx CLIContext) GetAccountSequence(address []byte) (uint64, error) { // EnsureAccountExists ensures that an account exists for a given context. An // error is returned if it does not. func (ctx CLIContext) EnsureAccountExists() error { - addr, err := ctx.GetFromAddress() - if err != nil { - return err - } - + addr := ctx.GetFromAddress() accountBytes, err := ctx.QueryStore(auth.AddressStoreKey(addr), ctx.AccountStore) if err != nil { return err diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 0d680ada44ba..5e13cf474e8f 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -2,7 +2,6 @@ package lcd import ( "encoding/hex" - "encoding/json" "fmt" "net/http" "os" @@ -26,6 +25,7 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" @@ -211,16 +211,17 @@ func TestCoinSend(t *testing.T) { // run simulation and test success with estimated gas res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "10000", 1.0, true, false, fees) require.Equal(t, http.StatusOK, res.StatusCode, body) - var responseBody struct { - GasEstimate int64 `json:"gas_estimate"` - } - require.Nil(t, json.Unmarshal([]byte(body), &responseBody)) + + var gasEstResp utils.GasEstimateResponse + require.Nil(t, cdc.UnmarshalJSON([]byte(body), &gasEstResp)) + require.NotZero(t, gasEstResp.GasEstimate) acc = getAccount(t, port, addr) require.Equal(t, expectedBalance.Amount, acc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom)) - res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, - fmt.Sprintf("%d", responseBody.GasEstimate), 1.0, false, false, fees) + // run successful tx + gas := fmt.Sprintf("%d", gasEstResp.GasEstimate) + res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, gas, 1.0, false, false, fees) require.Equal(t, http.StatusOK, res.StatusCode, body) err = cdc.UnmarshalJSON([]byte(body), &resultTx) @@ -235,15 +236,67 @@ func TestCoinSend(t *testing.T) { require.Equal(t, expectedBalance.Amount.SubRaw(1), acc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom)) } +func TestCoinSendAccAuto(t *testing.T) { + addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}) + defer cleanup() + + acc := getAccount(t, port, addr) + initialBalance := acc.GetCoins() + + // send a transfer tx without specifying account number and sequence + res, body, _ := doTransferWithGasAccAuto(t, port, seed, name1, memo, pw, "200000", 1.0, false, false, fees) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + // query sender + acc = getAccount(t, port, addr) + coins := acc.GetCoins() + expectedBalance := initialBalance[0].Minus(fees[0]) + + require.Equal(t, stakingTypes.DefaultBondDenom, coins[0].Denom) + require.Equal(t, expectedBalance.Amount.SubRaw(1), coins[0].Amount) +} + +func TestCoinSendGenerateOnly(t *testing.T) { + addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}) + defer cleanup() + + // generate only + res, body, _ := doTransferWithGas(t, port, seed, "", memo, "", addr, "200000", 1, false, true, fees) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var stdTx auth.StdTx + require.Nil(t, cdc.UnmarshalJSON([]byte(body), &stdTx)) + require.Equal(t, len(stdTx.Msgs), 1) + require.Equal(t, stdTx.GetMsgs()[0].Route(), "bank") + require.Equal(t, stdTx.GetMsgs()[0].GetSigners(), []sdk.AccAddress{addr}) + require.Equal(t, 0, len(stdTx.Signatures)) + require.Equal(t, memo, stdTx.Memo) + require.NotZero(t, stdTx.Fee.Gas) + require.IsType(t, stdTx.GetMsgs()[0], bank.MsgSend{}) + require.Equal(t, addr, stdTx.GetMsgs()[0].(bank.MsgSend).Inputs[0].Address) +} + func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}) defer cleanup() acc := getAccount(t, port, addr) - // generate TX - res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, client.GasFlagAuto, 1, false, true, fees) + // simulate tx + res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, client.GasFlagAuto, 1, true, false, fees) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var gasEstResp utils.GasEstimateResponse + require.Nil(t, cdc.UnmarshalJSON([]byte(body), &gasEstResp)) + require.NotZero(t, gasEstResp.GasEstimate) + + // generate tx + gas := fmt.Sprintf("%d", gasEstResp.GasEstimate) + res, body, _ = doTransferWithGas(t, port, seed, name1, memo, "", addr, gas, 1, false, true, fees) require.Equal(t, http.StatusOK, res.StatusCode, body) + var msg auth.StdTx require.Nil(t, cdc.UnmarshalJSON([]byte(body), &msg)) require.Equal(t, len(msg.Msgs), 1) @@ -251,6 +304,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { require.Equal(t, msg.Msgs[0].GetSigners(), []sdk.AccAddress{addr}) require.Equal(t, 0, len(msg.Signatures)) require.Equal(t, memo, msg.Memo) + require.NotZero(t, msg.Fee.Gas) gasEstimate := int64(msg.Fee.Gas) accnum := acc.GetAccountNumber() @@ -268,6 +322,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { } json, err := cdc.MarshalJSON(payload) require.Nil(t, err) + res, body = Request(t, port, "POST", "/tx/sign", json) require.Equal(t, http.StatusOK, res.StatusCode, body) require.Nil(t, cdc.UnmarshalJSON([]byte(body), &signedMsg)) diff --git a/client/lcd/swagger-ui/swagger.yaml b/client/lcd/swagger-ui/swagger.yaml index eed9d7e27691..363345917aac 100644 --- a/client/lcd/swagger-ui/swagger.yaml +++ b/client/lcd/swagger-ui/swagger.yaml @@ -1,28 +1,28 @@ --- -swagger: '2.0' +swagger: "2.0" info: version: "3.0" title: Gaia-Lite for Cosmos description: A REST interface for state queries, transaction generation, signing, and broadcast. tags: -- name: ICS0 - description: Tendermint APIs, such as query blocks, transactions and validatorset -- name: ICS1 - description: Key management APIs -- name: ICS20 - description: Create, sign and broadcast transactions -- name: ICS21 - description: Stake module APIs -- name: ICS22 - description: Governance module APIs -- name: ICS23 - description: Slashing module APIs -- name: ICS24 - description: WIP - Fee distribution module APIs -- name: version - description: Query app version + - name: ICS0 + description: Tendermint APIs, such as query blocks, transactions and validatorset + - name: ICS1 + description: Key management APIs + - name: ICS20 + description: Create, sign and broadcast transactions + - name: ICS21 + description: Stake module APIs + - name: ICS22 + description: Governance module APIs + - name: ICS23 + description: Slashing module APIs + - name: ICS24 + description: WIP - Fee distribution module APIs + - name: version + description: Query app version schemes: -- https + - https host: fabo.interblock.io:1317 securityDefinitions: kms: @@ -32,7 +32,7 @@ paths: get: summary: Version of Gaia-lite tags: - - version + - version description: Get the version of gaia-lite running locally to compare against expected responses: 200: @@ -41,7 +41,7 @@ paths: get: summary: Version of the connected node tags: - - version + - version description: Get the version of the SDK running on the connected node to compare against expected responses: 200: @@ -53,9 +53,9 @@ paths: description: Information about the connected node summary: The properties of the connected node tags: - - ICS0 + - ICS0 produces: - - application/json + - application/json responses: 200: description: Node status @@ -90,7 +90,7 @@ paths: get: summary: Syncing state of node tags: - - ICS0 + - ICS0 description: Get if the node is currently syning with other nodes responses: 200: @@ -101,9 +101,9 @@ paths: get: summary: Get the latest block tags: - - ICS0 + - ICS0 produces: - - application/json + - application/json responses: 200: description: The latest block @@ -115,15 +115,15 @@ paths: get: summary: Get a block at a certain height tags: - - ICS0 + - ICS0 produces: - - application/json + - application/json parameters: - - in: path - name: height - description: Block height - required: true - type: number + - in: path + name: height + description: Block height + required: true + type: number responses: 200: description: The block at a specific height @@ -139,9 +139,9 @@ paths: get: summary: Get the latest validator set tags: - - ICS0 + - ICS0 produces: - - application/json + - application/json responses: 200: description: The validator set at the latest block height @@ -160,15 +160,15 @@ paths: get: summary: Get a validator set a certain height tags: - - ICS0 + - ICS0 produces: - - application/json + - application/json parameters: - - in: path - name: height - description: Block height - required: true - type: number + - in: path + name: height + description: Block height + required: true + type: number responses: 200: description: The validator set at a specific block height @@ -191,15 +191,15 @@ paths: get: summary: Get a Tx by hash tags: - - ICS0 + - ICS0 produces: - - application/json + - application/json parameters: - - in: path - name: hash - description: Tx hash - required: true - type: string + - in: path + name: hash + description: Tx hash + required: true + type: string responses: 200: description: Tx with the provided hash @@ -210,25 +210,25 @@ paths: /txs: get: tags: - - ICS0 + - ICS0 summary: Search transactions description: Search transactions by tag(s). produces: - - application/json + - application/json parameters: - - in: query - name: tag - type: string - description: "transaction tags such as 'action=submit-proposal' and 'proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc' which results in the following endpoint: 'GET /txs?action=submit-proposal&proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc'" - required: true - - in: query - name: page - description: Pagination page - type: integer - - in: query - name: size - description: Pagination size - type: integer + - in: query + name: tag + type: string + description: "transaction tags such as 'action=submit-proposal' and 'proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc' which results in the following endpoint: 'GET /txs?action=submit-proposal&proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc'" + required: true + - in: query + name: page + description: Pagination page + type: integer + - in: query + name: size + description: Pagination size + type: integer responses: 200: description: All txs matching the provided tags @@ -242,26 +242,26 @@ paths: description: Internal Server Error post: tags: - - ICS0 + - ICS0 summary: broadcast Tx description: broadcast tx with tendermint rpc consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: body - name: txBroadcast - description: Build a StdTx transaction and serilize it to a byte array with amino, then the `"tx"` field in the post body will be the base64 encoding of the byte array. The supported return types includes `"block"`(return after tx commit), `"sync"`(return afer CheckTx) and `"async"`(return right away). - required: true - schema: - type: object - properties: - tx: - type: string - return: - type: string - example: block + - in: body + name: txBroadcast + description: Build a StdTx transaction and serilize it to a byte array with amino, then the `"tx"` field in the post body will be the base64 encoding of the byte array. The supported return types includes `"block"`(return after tx commit), `"sync"`(return afer CheckTx) and `"async"`(return right away). + required: true + schema: + type: object + properties: + tx: + type: string + return: + type: string + example: block responses: 200: description: Broadcast tx result @@ -272,28 +272,28 @@ paths: /tx/sign: post: tags: - - ICS20 + - ICS20 summary: Sign a Tx description: Sign a Tx providing locally stored account and according password consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: body - name: sendToken - description: sign tx - required: true - schema: - type: object - properties: - base_req: - $ref: "#/definitions/BaseReq" - tx: - $ref: "#/definitions/StdTx" - append_sig: - type: boolean - example: true + - in: body + name: sendToken + description: sign tx + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + tx: + $ref: "#/definitions/StdTx" + append_sig: + type: boolean + example: true responses: 200: description: The signed Tx @@ -308,23 +308,23 @@ paths: /tx/broadcast: post: tags: - - ICS20 + - ICS20 summary: Send a signed Tx description: Send a signed Tx to a Gaiad full node consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: body - name: txBroadcast - description: broadcast tx - required: true - schema: - type: object - properties: - tx: - $ref: "#/definitions/StdTx" + - in: body + name: txBroadcast + description: broadcast tx + required: true + schema: + type: object + properties: + tx: + $ref: "#/definitions/StdTx" responses: 202: description: Tx was send and will probably be added to the next block @@ -338,15 +338,15 @@ paths: get: summary: Get the account balances tags: - - ICS20 + - ICS20 produces: - - application/json + - application/json parameters: - - in: path - name: address - description: Account address in bech32 format - required: true - type: string + - in: path + name: address + description: Account address in bech32 format + required: true + type: string responses: 200: description: Account balances @@ -363,30 +363,30 @@ paths: summary: Send coins (build -> sign -> send) description: Send coins (build -> sign -> send) tags: - - ICS20 + - ICS20 consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: path - name: address - description: Account address in bech32 format - required: true - type: string - - in: body - name: account - description: The password of the account to remove from the KMS - required: true - schema: - type: object - properties: - base_req: - $ref: "#/definitions/BaseReq" - amount: - type: array - items: - $ref: "#/definitions/Coin" + - in: path + name: address + description: Account address in bech32 format + required: true + type: string + - in: body + name: account + description: The password of the account to remove from the KMS + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + amount: + type: array + items: + $ref: "#/definitions/Coin" responses: 202: description: Tx was send and will probably be added to the next block @@ -402,43 +402,43 @@ paths: get: summary: List of accounts stored locally tags: - - ICS1 + - ICS1 produces: - - application/json + - application/json responses: 200: description: Array of accounts schema: type: array items: - $ref: '#/definitions/KeyOutput' + $ref: "#/definitions/KeyOutput" 500: description: Server internal error post: summary: Create a new account locally tags: - - ICS1 + - ICS1 consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: body - name: account - description: The account to create - schema: - type: object - required: - - name - - password - - seed - properties: - name: - type: string - password: - type: string - seed: - type: string + - in: body + name: account + description: The account to create + schema: + type: object + required: + - name + - password + - seed + properties: + name: + type: string + password: + type: string + seed: + type: string responses: 200: description: Returns account information of the created key @@ -454,7 +454,7 @@ paths: get: summary: Create a new seed to create a new account with tags: - - ICS1 + - ICS1 responses: 200: description: 24 word Seed @@ -465,30 +465,30 @@ paths: post: summary: Recover a account from a seed tags: - - ICS1 + - ICS1 consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: path - name: name - description: Account name - required: true - type: string - - in: body - name: pwdAndSeed - description: Provide password and seed to recover a key - schema: - type: object - required: - - password - - seed - properties: - password: - type: string - seed: - type: string + - in: path + name: name + description: Account name + required: true + type: string + - in: body + name: pwdAndSeed + description: Provide password and seed to recover a key + schema: + type: object + required: + - password + - seed + properties: + password: + type: string + seed: + type: string responses: 200: description: Returns account information of the recovered key @@ -502,17 +502,17 @@ paths: description: Server internal error /keys/{name}: parameters: - - in: path - name: name - description: Account name - required: true - type: string + - in: path + name: name + description: Account name + required: true + type: string get: summary: Get a certain locally stored account tags: - - ICS1 + - ICS1 produces: - - application/json + - application/json responses: 200: description: Locally stored account @@ -523,23 +523,23 @@ paths: put: summary: Update the password for this account in the KMS tags: - - ICS1 + - ICS1 consumes: - - application/json + - application/json parameters: - - in: body - name: account - description: The new and old password - schema: - type: object - required: - - new_password - - old_password - properties: - new_password: - type: string - old_password: - type: string + - in: body + name: account + description: The new and old password + schema: + type: object + required: + - new_password + - old_password + properties: + new_password: + type: string + old_password: + type: string responses: 200: description: Updated password @@ -550,20 +550,20 @@ paths: delete: summary: Remove an account tags: - - ICS1 + - ICS1 consumes: - - application/json + - application/json parameters: - - in: body - name: account - description: The password of the account to remove from the KMS - schema: - type: object - required: - - password - properties: - password: - type: string + - in: body + name: account + description: The password of the account to remove from the KMS + schema: + type: object + required: + - password + properties: + password: + type: string responses: 200: description: Removed account @@ -575,15 +575,15 @@ paths: get: summary: Get the account information on blockchain tags: - - ICS1 + - ICS1 produces: - - application/json + - application/json parameters: - - in: path - name: address - description: Account address - required: true - type: string + - in: path + name: address + description: Account address + required: true + type: string responses: 200: description: Account information on the blockchain @@ -613,17 +613,17 @@ paths: description: Server internel error /staking/delegators/{delegatorAddr}/delegations: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string get: summary: Get all delegations from a delegator tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -638,26 +638,26 @@ paths: post: summary: Submit delegation parameters: - - in: body - name: delegation - description: The password of the account to remove from the KMS - schema: - type: object - properties: - base_req: - $ref: "#/definitions/BaseReq" - delegator_addr: - $ref: "#/definitions/Address" - validator_addr: - $ref: "#/definitions/ValidatorAddress" - delegation: - $ref: "#/definitions/Coin" + - in: body + name: delegation + description: The password of the account to remove from the KMS + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + delegator_addr: + $ref: "#/definitions/Address" + validator_addr: + $ref: "#/definitions/ValidatorAddress" + delegation: + $ref: "#/definitions/Coin" tags: - - ICS21 + - ICS21 consumes: - - application/json + - application/json produces: - - application/json + - application/json responses: 200: description: OK @@ -671,22 +671,22 @@ paths: description: Internal Server Error /staking/delegators/{delegatorAddr}/delegations/{validatorAddr}: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string - - in: path - name: validatorAddr - description: Bech32 OperatorAddress of validator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string get: summary: Query the current delegation between a delegator and a validator tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -698,17 +698,17 @@ paths: description: Internal Server Error /staking/delegators/{delegatorAddr}/unbonding_delegations: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string get: summary: Get all unbonding delegations from a delegator tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -723,37 +723,27 @@ paths: post: summary: Submit an unbonding delegation parameters: - - in: query - name: simulate - description: if true, ignore the gas field and perform a simulation of a transaction, but don't broadcast it - required: false - type: boolean - - in: query - name: generate_only - description: if true, build an unsigned transaction and write it back - required: false - type: boolean - - in: body - name: delegation - description: The password of the account to remove from the KMS - schema: - type: object - properties: - base_req: - $ref: "#/definitions/BaseReq" - delegator_addr: - $ref: "#/definitions/Address" - validator_addr: - $ref: "#/definitions/ValidatorAddress" - shares: - type: string - example: "100" - tags: - - ICS21 + - in: body + name: delegation + description: The password of the account to remove from the KMS + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + delegator_addr: + $ref: "#/definitions/Address" + validator_addr: + $ref: "#/definitions/ValidatorAddress" + shares: + type: string + example: "100" + tags: + - ICS21 consumes: - - application/json + - application/json produces: - - application/json + - application/json responses: 200: description: OK @@ -767,22 +757,22 @@ paths: description: Internal Server Error /staking/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string - - in: path - name: validatorAddr - description: Bech32 OperatorAddress of validator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string get: summary: Query all unbonding delegations between a delegator and a validator tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -796,27 +786,27 @@ paths: description: Internal Server Error /staking/redelegations: parameters: - - in: query - name: delegator - description: Bech32 AccAddress of Delegator - required: false - type: string - - in: query - name: validator_from - description: Bech32 ValAddress of SrcValidator - required: false - type: string - - in: query - name: validator_to - description: Bech32 ValAddress of DstValidator - required: false - type: string + - in: query + name: delegator + description: Bech32 AccAddress of Delegator + required: false + type: string + - in: query + name: validator_from + description: Bech32 ValAddress of SrcValidator + required: false + type: string + - in: query + name: validator_to + description: Bech32 ValAddress of DstValidator + required: false + type: string get: summary: Get all redelegations (filter by query params) tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -828,41 +818,31 @@ paths: description: Internal Server Error /staking/delegators/{delegatorAddr}/redelegations: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string post: summary: Submit a redelegation parameters: - - in: query - name: simulate - description: if true, ignore the gas field and perform a simulation of a transaction, but don't broadcast it - required: false - type: boolean - - in: query - name: generate_only - description: if true, build an unsigned transaction and write it back - required: false - type: boolean - - in: body - name: delegation - description: The password of the account to remove from the KMS - schema: - type: object - properties: - base_req: - $ref: "#/definitions/BaseReq" - delegator_addr: - $ref: "#/definitions/Address" - validator_src_addr: - $ref: "#/definitions/ValidatorAddress" - validator_dst_addr: - $ref: "#/definitions/ValidatorAddress" - shares: - type: string - example: "100" + - in: body + name: delegation + description: The password of the account to remove from the KMS + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + delegator_addr: + $ref: "#/definitions/Address" + validator_src_addr: + $ref: "#/definitions/ValidatorAddress" + validator_dst_addr: + $ref: "#/definitions/ValidatorAddress" + shares: + type: string + example: "100" tags: - ICS21 consumes: @@ -882,17 +862,17 @@ paths: description: Internal Server Error /staking/delegators/{delegatorAddr}/validators: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string get: summary: Query all validators that a delegator is bonded to tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -906,22 +886,22 @@ paths: description: Internal Server Error /staking/delegators/{delegatorAddr}/validators/{validatorAddr}: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string - - in: path - name: validatorAddr - description: Bech32 ValAddress of Delegator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + - in: path + name: validatorAddr + description: Bech32 ValAddress of Delegator + required: true + type: string get: summary: Query a validator that a delegator is bonded to tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -933,17 +913,17 @@ paths: description: Internal Server Error /staking/delegators/{delegatorAddr}/txs: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string get: summary: Get all staking txs (i.e msgs) from a delegator tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -961,9 +941,9 @@ paths: get: summary: Get all validator candidates tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -975,17 +955,17 @@ paths: description: Internal Server Error /staking/validators/{validatorAddr}: parameters: - - in: path - name: validatorAddr - description: Bech32 OperatorAddress of validator - required: true - type: string + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string get: summary: Query the information from a single validator tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -997,17 +977,17 @@ paths: description: Internal Server Error /staking/validators/{validatorAddr}/delegations: parameters: - - in: path - name: validatorAddr - description: Bech32 OperatorAddress of validator - required: true - type: string + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string get: summary: Get all delegations from a validator tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -1021,17 +1001,17 @@ paths: description: Internal Server Error /staking/validators/{validatorAddr}/unbonding_delegations: parameters: - - in: path - name: validatorAddr - description: Bech32 OperatorAddress of validator - required: true - type: string + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string get: summary: Get all unbonding delegations from a validator tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -1047,9 +1027,9 @@ paths: get: summary: Get the current state of the staking pool tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -1074,9 +1054,9 @@ paths: get: summary: Get the current staking parameter values tags: - - ICS21 + - ICS21 produces: - - application/json + - application/json responses: 200: description: OK @@ -1104,15 +1084,15 @@ paths: summary: Get sign info of given validator description: Get sign info of given validator produces: - - application/json + - application/json tags: - - ICS23 + - ICS23 parameters: - - type: string - description: Bech32 validator public key - name: validatorPubKey - required: true - in: path + - type: string + description: Bech32 validator public key + name: validatorPubKey + required: true + in: path responses: 200: description: OK @@ -1138,26 +1118,26 @@ paths: summary: Unjail a jailed validator description: Send transaction to unjail a jailed validator consumes: - - application/json + - application/json produces: - - application/json + - application/json tags: - - ICS23 + - ICS23 parameters: - - type: string - description: Bech32 validator address - name: validatorAddr - required: true - in: path - - description: '' - name: UnjailBody - in: body - required: true - schema: - type: object - properties: - base_req: - $ref: "#/definitions/BaseReq" + - type: string + description: Bech32 validator address + name: validatorAddr + required: true + in: path + - description: "" + name: UnjailBody + in: body + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" responses: 200: description: OK @@ -1173,9 +1153,9 @@ paths: get: summary: Get the current slashing parameters tags: - - ICS23 + - ICS23 produces: - - application/json + - application/json responses: 200: description: OK @@ -1203,34 +1183,34 @@ paths: summary: Submit a proposal description: Send transaction to submit a proposal consumes: - - application/json + - application/json produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - description: valid value of `"proposal_type"` can be `"text"`, `"parameter_change"`, `"software_upgrade"` - name: post_proposal_body - in: body - required: true - schema: - type: object - properties: - base_req: - $ref: "#/definitions/BaseReq" - title: - type: string - description: - type: string - proposal_type: - type: string - example: "text" - proposer: - $ref: "#/definitions/Address" - initial_deposit: - type: array - items: - $ref: "#/definitions/Coin" + - description: valid value of `"proposal_type"` can be `"text"`, `"parameter_change"`, `"software_upgrade"` + name: post_proposal_body + in: body + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + title: + type: string + description: + type: string + proposal_type: + type: string + example: "text" + proposer: + $ref: "#/definitions/Address" + initial_deposit: + type: array + items: + $ref: "#/definitions/Coin" responses: 200: description: OK @@ -1246,25 +1226,25 @@ paths: summary: Query proposals description: Query proposals information with parameters produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - in: query - name: voter - description: voter address - required: false - type: string - - in: query - name: depositor - description: depositor address - required: false - type: string - - in: query - name: status - description: proposal status, valid values can be `"deposit_period"`, `"voting_period"`, `"passed"`, `"rejected"` - required: false - type: string + - in: query + name: voter + description: voter address + required: false + type: string + - in: query + name: depositor + description: depositor address + required: false + type: string + - in: query + name: status + description: proposal status, valid values can be `"deposit_period"`, `"voting_period"`, `"passed"`, `"rejected"` + required: false + type: string responses: 200: description: OK @@ -1281,14 +1261,14 @@ paths: summary: Query a proposal description: Query a proposal by id produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - type: string - name: proposalId - required: true - in: path + - type: string + name: proposalId + required: true + in: path responses: 200: description: OK @@ -1303,14 +1283,14 @@ paths: summary: Query proposer description: Query for the proposer for a proposal produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - type: string - name: proposalId - required: true - in: path + - type: string + name: proposalId + required: true + in: path responses: 200: description: OK @@ -1325,14 +1305,14 @@ paths: summary: Query deposits description: Query deposits by proposalId produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - type: string - name: proposalId - required: true - in: path + - type: string + name: proposalId + required: true + in: path responses: 200: description: OK @@ -1348,32 +1328,32 @@ paths: summary: Deposit tokens to a proposal description: Send transaction to deposit tokens to a proposal consumes: - - application/json + - application/json produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - type: string - description: proposal id - name: proposalId - required: true - in: path - - description: '' - name: post_deposit_body - in: body - required: true - schema: - type: object - properties: - base_req: - $ref: "#/definitions/BaseReq" - depositor: - $ref: "#/definitions/Address" - amount: - type: array - items: - $ref: "#/definitions/Coin" + - type: string + description: proposal id + name: proposalId + required: true + in: path + - description: "" + name: post_deposit_body + in: body + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + depositor: + $ref: "#/definitions/Address" + amount: + type: array + items: + $ref: "#/definitions/Coin" responses: 200: description: OK @@ -1390,20 +1370,20 @@ paths: summary: Query deposit description: Query deposit by proposalId and depositor address produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - type: string - description: proposal id - name: proposalId - required: true - in: path - - type: string - description: Bech32 depositor address - name: depositor - required: true - in: path + - type: string + description: proposal id + name: proposalId + required: true + in: path + - type: string + description: Bech32 depositor address + name: depositor + required: true + in: path responses: 200: description: OK @@ -1420,15 +1400,15 @@ paths: summary: Query voters description: Query voters information by proposalId produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - type: string - description: proposal id - name: proposalId - required: true - in: path + - type: string + description: proposal id + name: proposalId + required: true + in: path responses: 200: description: OK @@ -1444,31 +1424,31 @@ paths: summary: Vote a proposal description: Send transaction to vote a proposal consumes: - - application/json + - application/json produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - type: string - description: proposal id - name: proposalId - required: true - in: path - - description: valid value of `"option"` field can be `"yes"`, `"no"`, `"no_with_veto"` and `"abstain"` - name: post_vote_body - in: body - required: true - schema: - type: object - properties: - base_req: - $ref: "#/definitions/BaseReq" - voter: - $ref: "#/definitions/Address" - option: - type: string - example: "yes" + - type: string + description: proposal id + name: proposalId + required: true + in: path + - description: valid value of `"option"` field can be `"yes"`, `"no"`, `"no_with_veto"` and `"abstain"` + name: post_vote_body + in: body + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + voter: + $ref: "#/definitions/Address" + option: + type: string + example: "yes" responses: 200: description: OK @@ -1485,20 +1465,20 @@ paths: summary: Query vote description: Query vote information by proposal Id and voter address produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - type: string - description: proposal id - name: proposalId - required: true - in: path - - type: string - description: Bech32 voter address - name: voter - required: true - in: path + - type: string + description: proposal id + name: proposalId + required: true + in: path + - type: string + description: Bech32 voter address + name: voter + required: true + in: path responses: 200: description: OK @@ -1515,15 +1495,15 @@ paths: summary: Get a proposal's tally result at the current time description: Gets a proposal's tally result at the current time. If the proposal is pending deposits (i.e status 'DepositPeriod') it returns an empty tally result. produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 parameters: - - type: string - description: proposal id - name: proposalId - required: true - in: path + - type: string + description: proposal id + name: proposalId + required: true + in: path responses: 200: description: OK @@ -1538,9 +1518,9 @@ paths: summary: Query governance deposit parameters description: Query governance deposit parameters. The max_deposit_period units are in nanoseconds. produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 responses: 200: description: OK @@ -1565,9 +1545,9 @@ paths: summary: Query governance tally parameters description: Query governance tally parameters produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 responses: 200: description: OK @@ -1593,9 +1573,9 @@ paths: summary: Query governance voting parameters description: Query governance voting parameters. The voting_period units are in nanoseconds. produces: - - application/json + - application/json tags: - - ICS22 + - ICS22 responses: 200: description: OK @@ -1612,18 +1592,18 @@ paths: description: Internal Server Error /distribution/delegators/{delegatorAddr}/rewards: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string get: summary: Get the total rewards balance from all delegations description: Get the sum of all the rewards earned by delegations by a single delegator produces: - - application/json + - application/json tags: - - ICS24 + - ICS24 responses: 200: description: OK @@ -1639,28 +1619,18 @@ paths: summary: Withdraw all the delegator's delegation rewards description: Withdraw all the delegator's delegation rewards tags: - - ICS24 + - ICS24 consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: query - name: simulate - description: if true, ignore the gas field and perform a simulation of a transaction, but don't broadcast it - required: false - type: boolean - - in: query - name: generate_only - description: if true, build an unsigned transaction and write it back - required: false - type: boolean - - in: body - name: Withdraw request body - schema: - properties: - base_req: - $ref: "#/definitions/BaseReq" + - in: body + name: Withdraw request body + schema: + properties: + base_req: + $ref: "#/definitions/BaseReq" responses: 200: description: OK @@ -1674,23 +1644,23 @@ paths: description: Internal Server Error /distribution/delegators/{delegatorAddr}/rewards/{validatorAddr}: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string - - in: path - name: validatorAddr - description: Bech32 OperatorAddress of validator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string get: summary: Query a delegation reward description: Query a single delegation reward by a delegator tags: - - ICS24 + - ICS24 produces: - - application/json + - application/json responses: 200: description: OK @@ -1706,28 +1676,18 @@ paths: summary: Withdraw a delegation reward description: Withdraw a delegator's delegation reward from a single validator tags: - - ICS24 + - ICS24 consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: query - name: simulate - description: if true, ignore the gas field and perform a simulation of a transaction, but don't broadcast it - required: false - type: boolean - - in: query - name: generate_only - description: if true, build an unsigned transaction and write it back - required: false - type: boolean - - in: body - name: Withdraw request body - schema: - properties: - base_req: - $ref: "#/definitions/BaseReq" + - in: body + name: Withdraw request body + schema: + properties: + base_req: + $ref: "#/definitions/BaseReq" responses: 200: description: OK @@ -1741,18 +1701,18 @@ paths: description: Internal Server Error /distribution/delegators/{delegatorAddr}/withdraw_address: parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string get: summary: Get the rewards withdrawal address description: Get the delegations' rewards withdrawal address. This is the address in which the user will receive the reward funds tags: - - ICS24 + - ICS24 produces: - - application/json + - application/json responses: 200: description: OK @@ -1766,30 +1726,20 @@ paths: summary: Replace the rewards withdrawal address description: Replace the delegations' rewards withdrawal address for a new one. tags: - - ICS24 + - ICS24 consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: query - name: simulate - description: if true, ignore the gas field and perform a simulation of a transaction, but don't broadcast it - required: false - type: boolean - - in: query - name: generate_only - description: if true, build an unsigned transaction and write it back - required: false - type: boolean - - in: body - name: Withdraw request body - schema: - properties: - base_req: - $ref: "#/definitions/BaseReq" - withdraw_address: - $ref: "#/definitions/Address" + - in: body + name: Withdraw request body + schema: + properties: + base_req: + $ref: "#/definitions/BaseReq" + withdraw_address: + $ref: "#/definitions/Address" responses: 200: description: OK @@ -1812,9 +1762,9 @@ paths: summary: Validator distribution information description: Query the distribution information of a single validator tags: - - ICS24 + - ICS24 produces: - - application/json + - application/json responses: 200: description: OK @@ -1835,9 +1785,9 @@ paths: summary: Commission and self-delegation rewards of a single a validator description: Query the commission and self-delegation rewards of a validator. tags: - - ICS24 + - ICS24 produces: - - application/json + - application/json responses: 200: description: OK @@ -1853,28 +1803,18 @@ paths: summary: Withdraw the validator's rewards description: Withdraw the validator's self-delegation and commissions rewards tags: - - ICS24 + - ICS24 consumes: - - application/json + - application/json produces: - - application/json + - application/json parameters: - - in: query - name: simulate - description: if true, ignore the gas field and perform a simulation of a transaction, but don't broadcast it - required: false - type: boolean - - in: query - name: generate_only - description: if true, build an unsigned transaction and write it back - required: false - type: boolean - - in: body - name: Withdraw request body - schema: - properties: - base_req: - $ref: "#/definitions/BaseReq" + - in: body + name: Withdraw request body + schema: + properties: + base_req: + $ref: "#/definitions/BaseReq" responses: 200: description: OK @@ -1890,9 +1830,9 @@ paths: get: summary: Fee distribution parameters tags: - - ICS24 + - ICS24 produces: - - application/json + - application/json responses: 200: description: OK @@ -1910,9 +1850,9 @@ paths: get: summary: Fee distribution pool tags: - - ICS24 + - ICS24 produces: - - application/json + - application/json responses: 200: description: OK @@ -1948,8 +1888,8 @@ definitions: gas_wanted: 10000 info: info tags: - - '' - - '' + - "" + - "" DeliverTxResult: type: object properties: @@ -1977,8 +1917,8 @@ definitions: gas_wanted: 10000 info: info tags: - - '' - - '' + - "" + - "" BroadcastTxCommitResult: type: object properties: @@ -2123,7 +2063,7 @@ definitions: example: 1 time: type: string - example: '2017-12-30T05:53:09.287+01:00' + example: "2017-12-30T05:53:09.287+01:00" num_txs: type: number example: 0 @@ -2186,7 +2126,7 @@ definitions: example: "0" timestamp: type: string - example: '2017-12-30T05:53:09.287+01:00' + example: "2017-12-30T05:53:09.287+01:00" type: type: number example: 2 @@ -2194,7 +2134,7 @@ definitions: $ref: "#/definitions/BlockID" signature: type: string - example: '7uTC74QlknqYWEwg7Vn6M8Om7FuZ0EO4bjvuj6rwH1mTUJrRuMMZvAAqT9VjNgP0RA/TDp6u/92AqrZfXJSpBQ==' + example: "7uTC74QlknqYWEwg7Vn6M8Om7FuZ0EO4bjvuj6rwH1mTUJrRuMMZvAAqT9VjNgP0RA/TDp6u/92AqrZfXJSpBQ==" BlockQuery: type: object properties: @@ -2210,9 +2150,10 @@ definitions: BaseReq: type: object properties: - name: + from: type: string - example: "my_name" + example: "cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc" + description: Sender address or Keybase name to generate a transaction password: type: string example: "12345678" @@ -2238,21 +2179,19 @@ definitions: type: array items: $ref: "#/definitions/Coin" - gas_prices: - type: array - items: - $ref: "#/definitions/DecCoin" generate_only: type: boolean example: false + description: Create a JSON transaction that can be signed client side instead of actually signing and broadcasting simulate: type: boolean - example: true + example: false + description: Estimate gas for a transaction (cannot be used in conjunction with generate_only) TendermintValidator: type: object properties: address: - $ref: '#/definitions/ValidatorAddress' + $ref: "#/definitions/ValidatorAddress" pub_key: type: string example: cosmosvalconspub1zcjduepq7sjfglw7ra4mjxpw4ph7dtdhdheh7nz8dfgl6t8u2n5szuuql9mqsrwquu @@ -2276,7 +2215,7 @@ definitions: proposal_status: type: string final_tally_result: - $ref: "#/definitions/TallyResult" + $ref: "#/definitions/TallyResult" submit_time: type: string total_deposit: @@ -2331,7 +2270,7 @@ definitions: type: object properties: operator_address: - $ref: '#/definitions/ValidatorAddress' + $ref: "#/definitions/ValidatorAddress" consensus_pubkey: type: string example: cosmosvalconspub1zcjduepq7sjfglw7ra4mjxpw4ph7dtdhdheh7nz8dfgl6t8u2n5szuuql9mqsrwquu @@ -2356,31 +2295,31 @@ definitions: type: string bond_height: type: string - example: '0' + example: "0" bond_intra_tx_counter: type: integer example: 0 unbonding_height: type: string - example: '0' + example: "0" unbonding_time: type: string - example: '1970-01-01T00:00:00Z' + example: "1970-01-01T00:00:00Z" commission: type: object properties: rate: type: string - example: '0' + example: "0" max_rate: type: string - example: '0' + example: "0" max_change_rate: type: string - example: '0' + example: "0" update_time: type: string - example: '1970-01-01T00:00:00Z' + example: "1970-01-01T00:00:00Z" Delegation: type: object properties: @@ -2434,13 +2373,13 @@ definitions: community_pool: type: array items: - $ref: '#/definitions/Coin' + $ref: "#/definitions/Coin" val_accum: - $ref: '#/definitions/TotalAccum' + $ref: "#/definitions/TotalAccum" val_pool: type: array items: - $ref: '#/definitions/Coin' + $ref: "#/definitions/Coin" TotalAccum: type: object properties: @@ -2452,16 +2391,16 @@ definitions: type: object properties: operator_addr: - $ref: '#/definitions/ValidatorAddress' + $ref: "#/definitions/ValidatorAddress" fee_pool_withdrawal_height: type: integer del_accum: - $ref: '#/definitions/TotalAccum' + $ref: "#/definitions/TotalAccum" del_pool: type: array items: - $ref: '#/definitions/Coin' + $ref: "#/definitions/Coin" val_commission: type: array items: - $ref: '#/definitions/Coin' + $ref: "#/definitions/Coin" diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index da41e196b276..71c2a38d6ac2 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -688,23 +688,32 @@ func doTransfer(t *testing.T, port, seed, name, memo, password string, addr sdk. return receiveAddr, resultTx } -func doTransferWithGas(t *testing.T, port, seed, name, memo, password string, addr sdk.AccAddress, gas string, - gasAdjustment float64, simulate, generateOnly bool, fees sdk.Coins) ( - res *http.Response, body string, receiveAddr sdk.AccAddress) { +func doTransferWithGas( + t *testing.T, port, seed, from, memo, password string, addr sdk.AccAddress, + gas string, gasAdjustment float64, simulate, generateOnly bool, fees sdk.Coins, +) (res *http.Response, body string, receiveAddr sdk.AccAddress) { // create receive address kb := client.MockKeyBase() - receiveInfo, _, err := kb.CreateMnemonic("receive_address", cryptoKeys.English, gapp.DefaultKeyPass, cryptoKeys.SigningAlgo("secp256k1")) + + receiveInfo, _, err := kb.CreateMnemonic( + "receive_address", cryptoKeys.English, gapp.DefaultKeyPass, cryptoKeys.SigningAlgo("secp256k1"), + ) require.Nil(t, err) - receiveAddr = sdk.AccAddress(receiveInfo.GetPubKey().Address()) + receiveAddr = sdk.AccAddress(receiveInfo.GetPubKey().Address()) acc := getAccount(t, port, addr) accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) + if generateOnly { + // generate only txs do not use a Keybase so the address must be used + from = addr.String() + } + baseReq := utils.NewBaseReq( - name, password, memo, chainID, gas, + from, password, memo, chainID, gas, fmt.Sprintf("%f", gasAdjustment), accnum, sequence, fees, nil, generateOnly, simulate, ) @@ -721,6 +730,39 @@ func doTransferWithGas(t *testing.T, port, seed, name, memo, password string, ad return } +func doTransferWithGasAccAuto( + t *testing.T, port, seed, from, memo, password string, gas string, + gasAdjustment float64, simulate, generateOnly bool, fees sdk.Coins, +) (res *http.Response, body string, receiveAddr sdk.AccAddress) { + + // create receive address + kb := client.MockKeyBase() + + receiveInfo, _, err := kb.CreateMnemonic( + "receive_address", cryptoKeys.English, gapp.DefaultKeyPass, cryptoKeys.SigningAlgo("secp256k1"), + ) + require.Nil(t, err) + + receiveAddr = sdk.AccAddress(receiveInfo.GetPubKey().Address()) + chainID := viper.GetString(client.FlagChainID) + + baseReq := utils.NewBaseReq( + from, password, memo, chainID, gas, + fmt.Sprintf("%f", gasAdjustment), 0, 0, fees, nil, generateOnly, simulate, + ) + + sr := sendReq{ + Amount: sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 1)}, + BaseReq: baseReq, + } + + req, err := cdc.MarshalJSON(sr) + require.NoError(t, err) + + res, body = Request(t, port, "POST", fmt.Sprintf("/bank/accounts/%s/transfers", receiveAddr), req) + return +} + type sendReq struct { Amount sdk.Coins `json:"amount"` BaseReq utils.BaseReq `json:"base_req"` diff --git a/client/utils/rest.go b/client/utils/rest.go index f6bd18a4f583..44fc746adf13 100644 --- a/client/utils/rest.go +++ b/client/utils/rest.go @@ -16,7 +16,12 @@ import ( authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" ) -//---------------------------------------- +// GasEstimateResponse defines a response definition for tx gas estimation. +type GasEstimateResponse struct { + GasEstimate uint64 `json:"gas_estimate"` +} + +//----------------------------------------------------------------------------- // Basic HTTP utilities // WriteErrorResponse prepares and writes a HTTP error @@ -28,9 +33,17 @@ func WriteErrorResponse(w http.ResponseWriter, status int, err string) { // WriteSimulationResponse prepares and writes an HTTP // response for transactions simulations. -func WriteSimulationResponse(w http.ResponseWriter, gas uint64) { +func WriteSimulationResponse(w http.ResponseWriter, cdc *codec.Codec, gas uint64) { + gasEst := GasEstimateResponse{GasEstimate: gas} + resp, err := cdc.MarshalJSON(gasEst) + if err != nil { + WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - w.Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas))) + w.Write(resp) } // ParseInt64OrReturnBadRequest converts s to a int64 value. @@ -77,31 +90,13 @@ func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEm return n, true } -// WriteGenerateStdTxResponse writes response for the generate_only mode. -func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec, txBldr authtxb.TxBuilder, msgs []sdk.Msg) { - stdMsg, err := txBldr.Build(msgs) - if err != nil { - WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - output, err := cdc.MarshalJSON(auth.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo)) - if err != nil { - WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - w.Write(output) - return -} - -//---------------------------------------- +//----------------------------------------------------------------------------- // Building / Sending utilities // BaseReq defines a structure that can be embedded in other request structures // that all share common "base" fields. type BaseReq struct { - Name string `json:"name"` + From string `json:"from"` Password string `json:"password"` Memo string `json:"memo"` ChainID string `json:"chain_id"` @@ -117,12 +112,12 @@ type BaseReq struct { // NewBaseReq creates a new basic request instance and sanitizes its values func NewBaseReq( - name, password, memo, chainID string, gas, gasAdjustment string, + from, password, memo, chainID string, gas, gasAdjustment string, accNumber, seq uint64, fees sdk.Coins, gasPrices sdk.DecCoins, genOnly, simulate bool, ) BaseReq { return BaseReq{ - Name: strings.TrimSpace(name), + From: strings.TrimSpace(from), Password: password, Memo: strings.TrimSpace(memo), ChainID: strings.TrimSpace(chainID), @@ -140,7 +135,7 @@ func NewBaseReq( // Sanitize performs basic sanitization on a BaseReq object. func (br BaseReq) Sanitize() BaseReq { return NewBaseReq( - br.Name, br.Password, br.Memo, br.ChainID, br.Gas, br.GasAdjustment, + br.From, br.Password, br.Memo, br.ChainID, br.Gas, br.GasAdjustment, br.AccountNumber, br.Sequence, br.Fees, br.GasPrices, br.GenerateOnly, br.Simulate, ) } @@ -171,8 +166,8 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool { } } - if len(br.Name) == 0 { - WriteErrorResponse(w, http.StatusUnauthorized, "name required but not specified") + if len(br.From) == 0 { + WriteErrorResponse(w, http.StatusUnauthorized, "name or address required but not specified") return false } @@ -209,59 +204,65 @@ func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req i } // CompleteAndBroadcastTxREST implements a utility function that facilitates -// sending a series of messages in a signed transaction given a TxBuilder and a -// QueryContext. It ensures that the account exists, has a proper number and -// sequence set. In addition, it builds and signs a transaction with the -// supplied messages. Finally, it broadcasts the signed transaction to a node. +// sending a series of messages in a signed tx. In addition, it will handle +// tx gas simulation and estimation. // -// NOTE: Also see CompleteAndBroadcastTxCli. -// NOTE: Also see x/stake/client/rest/tx.go delegationsRequestHandlerFn. +// NOTE: Also see CompleteAndBroadcastTxCLI. func CompleteAndBroadcastTxREST( w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext, baseReq BaseReq, msgs []sdk.Msg, cdc *codec.Codec, ) { - gasAdjustment, ok := ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment) + gasAdj, ok := ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment) if !ok { return } - simulateAndExecute, gas, err := client.ParseGas(baseReq.Gas) + simAndExec, gas, err := client.ParseGas(baseReq.Gas) if err != nil { WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } + // derive the from account address and name from the Keybase + fromAddress, fromName, err := context.GetFromFields(baseReq.From) + if err != nil { + WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress) txBldr := authtxb.NewTxBuilder( GetTxEncoder(cdc), baseReq.AccountNumber, - baseReq.Sequence, gas, gasAdjustment, baseReq.Simulate, + baseReq.Sequence, gas, gasAdj, baseReq.Simulate, baseReq.ChainID, baseReq.Memo, baseReq.Fees, baseReq.GasPrices, ) - if baseReq.Simulate || simulateAndExecute { - if gasAdjustment < 0 { + txBldr, err = prepareTxBuilder(txBldr, cliCtx) + if err != nil { + WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + if baseReq.Simulate || simAndExec { + if gasAdj < 0 { WriteErrorResponse(w, http.StatusBadRequest, "gas adjustment must be a positive float") return } - txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, msgs) + txBldr, err = EnrichWithGas(txBldr, cliCtx, cliCtx.GetFromName(), msgs) if err != nil { WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } if baseReq.Simulate { - WriteSimulationResponse(w, txBldr.GetGas()) + WriteSimulationResponse(w, cdc, txBldr.GetGas()) return } } - if baseReq.GenerateOnly { - WriteGenerateStdTxResponse(w, cdc, txBldr, msgs) - return - } - - txBytes, err := txBldr.BuildAndSign(baseReq.Name, baseReq.Password, msgs) + txBytes, err := txBldr.BuildAndSign(cliCtx.GetFromName(), baseReq.Password, msgs) if keyerror.IsErrKeyNotFound(err) { WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return @@ -282,9 +283,10 @@ func CompleteAndBroadcastTxREST( PostProcessResponse(w, cdc, res, cliCtx.Indent) } -// PostProcessResponse performs post process for rest response +// PostProcessResponse performs post processing for a REST response. func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response interface{}, indent bool) { var output []byte + switch response.(type) { default: var err error @@ -300,6 +302,41 @@ func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response inter case []byte: output = response.([]byte) } + w.Header().Set("Content-Type", "application/json") w.Write(output) } + +// WriteGenerateStdTxResponse writes response for the generate only mode. +func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec, br BaseReq, msgs []sdk.Msg) { + gasAdj, ok := ParseFloat64OrReturnBadRequest(w, br.GasAdjustment, client.DefaultGasAdjustment) + if !ok { + return + } + + _, gas, err := client.ParseGas(br.Gas) + if err != nil { + WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + txBldr := authtxb.NewTxBuilder( + GetTxEncoder(cdc), br.AccountNumber, br.Sequence, gas, gasAdj, + br.Simulate, br.ChainID, br.Memo, br.Fees, br.GasPrices, + ) + + stdMsg, err := txBldr.Build(msgs) + if err != nil { + WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + output, err := cdc.MarshalJSON(auth.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo)) + if err != nil { + WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + w.Write(output) + return +} diff --git a/client/utils/utils.go b/client/utils/utils.go index 92ce82b9937f..a30a54cd135c 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -18,26 +18,23 @@ import ( authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" ) -// CompleteAndBroadcastTxCli implements a utility function that facilitates +// CompleteAndBroadcastTxCLI implements a utility function that facilitates // sending a series of messages in a signed transaction given a TxBuilder and a // QueryContext. It ensures that the account exists, has a proper number and // sequence set. In addition, it builds and signs a transaction with the // supplied messages. Finally, it broadcasts the signed transaction to a node. // // NOTE: Also see CompleteAndBroadcastTxREST. -func CompleteAndBroadcastTxCli(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) error { +func CompleteAndBroadcastTxCLI(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) error { txBldr, err := prepareTxBuilder(txBldr, cliCtx) if err != nil { return err } - name, err := cliCtx.GetFromName() - if err != nil { - return err - } + name := cliCtx.GetFromName() if txBldr.GetSimulateAndExecute() || cliCtx.Simulate { - txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs) + txBldr, err = EnrichWithGas(txBldr, cliCtx, name, msgs) if err != nil { return err } @@ -63,9 +60,9 @@ func CompleteAndBroadcastTxCli(txBldr authtxb.TxBuilder, cliCtx context.CLIConte return err } -// EnrichCtxWithGas calculates the gas estimate that would be consumed by the +// EnrichWithGas calculates the gas estimate that would be consumed by the // transaction and set the transaction's respective value accordingly. -func EnrichCtxWithGas(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (authtxb.TxBuilder, error) { +func EnrichWithGas(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (authtxb.TxBuilder, error) { _, adjusted, err := simulateMsgs(txBldr, cliCtx, name, msgs) if err != nil { return txBldr, err @@ -236,10 +233,7 @@ func prepareTxBuilder(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (auth return txBldr, err } - from, err := cliCtx.GetFromAddress() - if err != nil { - return txBldr, err - } + from := cliCtx.GetFromAddress() // TODO: (ref #1903) Allow for user supplied account number without // automatically doing a manual lookup. @@ -275,22 +269,21 @@ func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg func buildUnsignedStdTxOffline(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) { if txBldr.GetSimulateAndExecute() { - var name string - name, err = cliCtx.GetFromName() - if err != nil { - return - } + name := cliCtx.GetFromName() - txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs) + txBldr, err = EnrichWithGas(txBldr, cliCtx, name, msgs) if err != nil { return } + fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.GetGas()) } + stdSignMsg, err := txBldr.Build(msgs) if err != nil { return } + return auth.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil } @@ -300,5 +293,6 @@ func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool { return true } } + return false } diff --git a/docs/clients/service-providers.md b/docs/clients/service-providers.md index 358031b966f4..68024d64132a 100644 --- a/docs/clients/service-providers.md +++ b/docs/clients/service-providers.md @@ -105,10 +105,19 @@ The recommended way to listen for incoming transaction is to periodically query ## Rest API -The Rest API documents all the available endpoints that you can use to interract with your full node. It can be found [here](https://cosmos.network/rpc/). - -The API is divided into ICS standards for each category of endpoints. For example, the [ICS20](https://cosmos.network/rpc/#/ICS20/) describes the API to interact with tokens. - -To give more flexibility to implementers, we have included the ability to generate unsigned transactions, [sign](https://cosmos.network/rpc/#/ICS20/post_tx_sign) and [broadcast](https://cosmos.network/rpc/#/ICS20/post_tx_broadcast) them with different API endpoints. This allows service providers to use their own signing mechanism for instance. - -In order to generate an unsigned transaction (example with [coin transfer](https://cosmos.network/rpc/#/ICS20/post_bank_accounts__address__transfers)), you need to use the flag `?generate_only`. +The Rest API documents all the available endpoints that you can use to interact +with your full node. It can be found [here](https://cosmos.network/rpc/). + +The API is divided into ICS standards for each category of endpoints. For +example, the [ICS20](https://cosmos.network/rpc/#/ICS20/) describes the API to +interact with tokens. + +To give more flexibility to implementers, we have included the ability to +generate unsigned transactions, [sign](https://cosmos.network/rpc/#/ICS20/post_tx_sign) +and [broadcast](https://cosmos.network/rpc/#/ICS20/post_tx_broadcast) them with +different API endpoints. This allows service providers to use their own signing +mechanism for instance. + +In order to generate an unsigned transaction (example with +[coin transfer](https://cosmos.network/rpc/#/ICS20/post_bank_accounts__address__transfers)), +you need to use the field `generate_only` in the body of `base_req`. diff --git a/docs/gaia/gaiacli.md b/docs/gaia/gaiacli.md index 5982c30d4eda..0b1bafd2696b 100644 --- a/docs/gaia/gaiacli.md +++ b/docs/gaia/gaiacli.md @@ -209,7 +209,8 @@ You can also check your balance at a given block by using the `--block` flag: gaiacli query account --block= ``` -You can simulate a transaction without actually broadcasting it by appending the `--dry-run` flag to the command line: +You can simulate a transaction without actually broadcasting it by appending the +`--dry-run` flag to the command line: ```bash gaiacli tx send \ @@ -220,7 +221,8 @@ gaiacli tx send \ --dry-run ``` -Furthermore, you can build a transaction and print its JSON format to STDOUT by appending `--generate-only` to the list of the command line arguments: +Furthermore, you can build a transaction and print its JSON format to STDOUT by +appending `--generate-only` to the list of the command line arguments: ```bash gaiacli tx send \ @@ -231,7 +233,14 @@ gaiacli tx send \ --generate-only > unsignedSendTx.json ``` -You can now sign the transaction file generated through the `--generate-only` flag by providing your key to the following command: +::: tip Note +Simulation cannot be used in conjunction with tx generation only functionality +due to the fact that simulation requires a public key and generation only does +not utilize a Keybase. + +You can now sign the transaction file generated through the `--generate-only` +flag by providing your key to the following command: +::: ```bash gaiacli tx sign \ diff --git a/x/auth/client/rest/sign.go b/x/auth/client/rest/sign.go index 7f7787ea4298..11b8c083ba88 100644 --- a/x/auth/client/rest/sign.go +++ b/x/auth/client/rest/sign.go @@ -41,6 +41,15 @@ func SignTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha return } + // derive the from account address and name from the Keybase + fromAddress, fromName, err := context.GetFromFields(m.BaseReq.From) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress) + txBldr := authtxb.NewTxBuilder( utils.GetTxEncoder(cdc), m.BaseReq.AccountNumber, @@ -54,7 +63,7 @@ func SignTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha nil, ) - signedTx, err := txBldr.SignStdTx(m.BaseReq.Name, m.BaseReq.Password, m.Tx, m.AppendSig) + signedTx, err := txBldr.SignStdTx(cliCtx.GetFromName(), m.BaseReq.Password, m.Tx, m.AppendSig) if keyerror.IsErrKeyNotFound(err) { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index 161261276ad8..9da232789a50 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -50,11 +50,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command { return err } - from, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - + from := cliCtx.GetFromAddress() account, err := cliCtx.GetAccount(from) if err != nil { return err @@ -71,7 +67,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command { return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false) } - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index d73d7e61e3cb..d087e9316e99 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/bank/client" + bankclient "github.com/cosmos/cosmos-sdk/x/bank/client" "github.com/gorilla/mux" ) @@ -37,7 +37,7 @@ func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIC vars := mux.Vars(r) bech32Addr := vars["address"] - to, err := sdk.AccAddressFromBech32(bech32Addr) + toAddr, err := sdk.AccAddressFromBech32(bech32Addr) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return @@ -54,13 +54,30 @@ func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIC return } - info, err := kb.Get(req.BaseReq.Name) + if req.BaseReq.GenerateOnly { + // When generate only is supplied, the from field must be a valid Bech32 + // address. + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + msg := bankclient.CreateMsg(fromAddr, toAddr, req.Amount) + utils.WriteGenerateStdTxResponse(w, cdc, req.BaseReq, []sdk.Msg{msg}) + return + } + + // derive the from account address and name from the Keybase + fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - msg := client.CreateMsg(sdk.AccAddress(info.GetPubKey().Address()), to, req.Amount) + cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress) + msg := bankclient.CreateMsg(cliCtx.GetFromAddress(), toAddr, req.Amount) + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc) } } diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go index 67113c2b92b3..9a761d8de6c1 100644 --- a/x/distribution/client/cli/tx.go +++ b/x/distribution/client/cli/tx.go @@ -63,18 +63,11 @@ func GetCmdWithdrawRewards(cdc *codec.Codec) *cobra.Command { var msg sdk.Msg switch { case isVal: - addr, err := cliCtx.GetFromAddress() - if err != nil { - return err - } + addr := cliCtx.GetFromAddress() valAddr := sdk.ValAddress(addr.Bytes()) msg = types.NewMsgWithdrawValidatorCommission(valAddr) default: - delAddr, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - + delAddr := cliCtx.GetFromAddress() valAddr, err := sdk.ValAddressFromBech32(onlyFromVal) if err != nil { return err @@ -88,7 +81,7 @@ func GetCmdWithdrawRewards(cdc *codec.Codec) *cobra.Command { } // build and sign the transaction, then broadcast to Tendermint - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } cmd.Flags().String(flagOnlyFromValidator, "", "only withdraw from this validator address (in bech)") @@ -109,11 +102,7 @@ func GetCmdSetWithdrawAddr(cdc *codec.Codec) *cobra.Command { WithCodec(cdc). WithAccountDecoder(cdc) - delAddr, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - + delAddr := cliCtx.GetFromAddress() withdrawAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err @@ -122,7 +111,7 @@ func GetCmdSetWithdrawAddr(cdc *codec.Codec) *cobra.Command { msg := types.NewMsgSetWithdrawAddress(delAddr, withdrawAddr) // build and sign the transaction, then broadcast to Tendermint - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } return cmd diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 89deae745672..69e82abf6b11 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -86,10 +86,7 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome WithAccountDecoder(cdc) // Get from address - from, err := cliCtx.GetFromAddress() - if err != nil { - return err - } + from := cliCtx.GetFromAddress() // Pull associated account account, err := cliCtx.GetAccount(from) @@ -126,7 +123,7 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome // Build and sign the transaction, then broadcast to Tendermint // proposalID must be returned, and it is a part of response. cliCtx.PrintResponse = true - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } @@ -199,11 +196,7 @@ $ gaiacli tx gov deposit 1 10stake --from mykey return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } - // Get from address - from, err := cliCtx.GetFromAddress() - if err != nil { - return err - } + from := cliCtx.GetFromAddress() // Fetch associated account account, err := cliCtx.GetAccount(from) @@ -233,7 +226,7 @@ $ gaiacli tx gov deposit 1 10stake --from mykey } // Build and sign the transaction, then broadcast to a Tendermint node. - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } @@ -258,10 +251,7 @@ $ gaiacli tx gov vote 1 yes --from mykey WithAccountDecoder(cdc) // Get voting address - from, err := cliCtx.GetFromAddress() - if err != nil { - return err - } + from := cliCtx.GetFromAddress() // validate that the proposal id is a uint proposalID, err := strconv.ParseUint(args[0], 10, 64) @@ -294,7 +284,7 @@ $ gaiacli tx gov vote 1 yes --from mykey } // Build and sign the transaction, then broadcast to a Tendermint node. - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 96142941ef07..b39d2f700f47 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -101,6 +101,11 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han return } + if req.BaseReq.GenerateOnly { + utils.WriteGenerateStdTxResponse(w, cdc, req.BaseReq, []sdk.Msg{msg}) + return + } + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc) } } @@ -140,6 +145,11 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF return } + if req.BaseReq.GenerateOnly { + utils.WriteGenerateStdTxResponse(w, cdc, req.BaseReq, []sdk.Msg{msg}) + return + } + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc) } } @@ -185,6 +195,11 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc return } + if req.BaseReq.GenerateOnly { + utils.WriteGenerateStdTxResponse(w, cdc, req.BaseReq, []sdk.Msg{msg}) + return + } + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc) } } diff --git a/x/ibc/client/cli/ibctx.go b/x/ibc/client/cli/ibctx.go index 2bea7cc80801..22e70f6a93ec 100644 --- a/x/ibc/client/cli/ibctx.go +++ b/x/ibc/client/cli/ibctx.go @@ -32,11 +32,7 @@ func IBCTransferCmd(cdc *codec.Codec) *cobra.Command { WithCodec(cdc). WithAccountDecoder(cdc) - from, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - + from := cliCtx.GetFromAddress() msg, err := buildMsg(from) if err != nil { return err @@ -45,7 +41,7 @@ func IBCTransferCmd(cdc *codec.Codec) *cobra.Command { return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false) } - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } diff --git a/x/ibc/client/cli/relay.go b/x/ibc/client/cli/relay.go index f9928c8ef904..231e0917fb05 100644 --- a/x/ibc/client/cli/relay.go +++ b/x/ibc/client/cli/relay.go @@ -82,11 +82,7 @@ func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) { toChainID := viper.GetString(FlagToChainID) toChainNode := viper.GetString(FlagToChainNode) - address, err := context.NewCLIContext().GetFromAddress() - if err != nil { - panic(err) - } - + address := context.NewCLIContext().GetFromAddress() c.address = address c.loop(fromChainID, fromChainNode, toChainID, toChainNode) @@ -96,10 +92,7 @@ func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) { func (c relayCommander) loop(fromChainID, fromChainNode, toChainID, toChainNode string) { cliCtx := context.NewCLIContext() - name, err := cliCtx.GetFromName() - if err != nil { - panic(err) - } + name := cliCtx.GetFromName() passphrase, err := keys.ReadPassphraseFromStdin(name) if err != nil { panic(err) @@ -207,11 +200,7 @@ func (c relayCommander) refine(bz []byte, ibcSeq, accSeq uint64, passphrase stri txBldr := authtxb.NewTxBuilderFromCLI().WithSequence(accSeq).WithTxEncoder(utils.GetTxEncoder(c.cdc)) cliCtx := context.NewCLIContext() - name, err := cliCtx.GetFromName() - if err != nil { - panic(err) - } - + name := cliCtx.GetFromName() res, err := txBldr.BuildAndSign(name, passphrase, []sdk.Msg{msg}) if err != nil { panic(err) diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index ab26b6e42046..a92f9ea195e0 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -48,18 +48,28 @@ func TransferRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context. return } - info, err := kb.Get(req.BaseReq.Name) - if err != nil { - utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) - return + var fromAddr sdk.AccAddress + + if req.BaseReq.GenerateOnly { + // When generate only is supplied, the from field must be a valid Bech32 + // address. + addr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + fromAddr = addr } - packet := ibc.NewIBCPacket( - sdk.AccAddress(info.GetPubKey().Address()), to, - req.Amount, req.BaseReq.ChainID, destChainID, - ) + packet := ibc.NewIBCPacket(fromAddr, to, req.Amount, req.BaseReq.ChainID, destChainID) msg := ibc.IBCTransferMsg{IBCPacket: packet} + if req.BaseReq.GenerateOnly { + utils.WriteGenerateStdTxResponse(w, cdc, req.BaseReq, []sdk.Msg{msg}) + return + } + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc) } } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 4fc1c9cde490..968a03e91193 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -25,16 +25,13 @@ func GetCmdUnjail(cdc *codec.Codec) *cobra.Command { WithCodec(cdc). WithAccountDecoder(cdc) - valAddr, err := cliCtx.GetFromAddress() - if err != nil { - return err - } + valAddr := cliCtx.GetFromAddress() msg := slashing.NewMsgUnjail(sdk.ValAddress(valAddr)) if cliCtx.GenerateOnly { return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false) } - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index add8c6665bee..1c4266aa151d 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -43,24 +43,38 @@ func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CL return } - info, err := kb.Get(req.BaseReq.Name) + valAddr, err := sdk.ValAddressFromBech32(bech32validator) if err != nil { - utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - valAddr, err := sdk.ValAddressFromBech32(bech32validator) + msg := slashing.NewMsgUnjail(valAddr) + err = msg.ValidateBasic() if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + if req.BaseReq.GenerateOnly { + utils.WriteGenerateStdTxResponse(w, cdc, req.BaseReq, []sdk.Msg{msg}) return } - if !bytes.Equal(info.GetPubKey().Address(), valAddr) { + // derive the from account address and name from the Keybase + fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress) + + if !bytes.Equal(cliCtx.GetFromAddress(), valAddr) { utils.WriteErrorResponse(w, http.StatusUnauthorized, "must use own validator address") return } - msg := slashing.NewMsgUnjail(valAddr) utils.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc) } } diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index 4a2ed6eb4def..6838cc0e048b 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -39,7 +39,7 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { } // build and sign the transaction, then broadcast to Tendermint - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } @@ -71,11 +71,7 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { WithCodec(cdc). WithAccountDecoder(cdc) - valAddr, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - + valAddr := cliCtx.GetFromAddress() description := staking.Description{ Moniker: viper.GetString(FlagMoniker), Identity: viper.GetString(FlagIdentity), @@ -102,7 +98,7 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { } // build and sign the transaction, then broadcast to Tendermint - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } @@ -128,11 +124,7 @@ func GetCmdDelegate(cdc *codec.Codec) *cobra.Command { return err } - delAddr, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - + delAddr := cliCtx.GetFromAddress() valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err @@ -144,7 +136,7 @@ func GetCmdDelegate(cdc *codec.Codec) *cobra.Command { return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false) } // build and sign the transaction, then broadcast to Tendermint - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } @@ -167,11 +159,7 @@ func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command { var err error - delAddr, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - + delAddr := cliCtx.GetFromAddress() valSrcAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) if err != nil { return err @@ -199,7 +187,7 @@ func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command { return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false) } // build and sign the transaction, then broadcast to Tendermint - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } @@ -220,11 +208,7 @@ func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command { WithCodec(cdc). WithAccountDecoder(cdc) - delAddr, err := cliCtx.GetFromAddress() - if err != nil { - return err - } - + delAddr := cliCtx.GetFromAddress() valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err @@ -247,7 +231,7 @@ func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command { return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false) } // build and sign the transaction, then broadcast to Tendermint - return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) }, } @@ -265,12 +249,9 @@ func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr authtxb.TxBuilder return txBldr, nil, err } - valAddr, err := cliCtx.GetFromAddress() - if err != nil { - return txBldr, nil, err - } - + valAddr := cliCtx.GetFromAddress() pkStr := viper.GetString(FlagPubKey) + pk, err := sdk.GetConsPubKeyBech32(pkStr) if err != nil { return txBldr, nil, err diff --git a/x/staking/client/rest/tx.go b/x/staking/client/rest/tx.go index 73d86ce423fa..26b821f1d5f2 100644 --- a/x/staking/client/rest/tx.go +++ b/x/staking/client/rest/tx.go @@ -68,24 +68,32 @@ func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context. return } - info, err := kb.Get(req.BaseReq.Name) + msg := staking.NewMsgDelegate(req.DelegatorAddr, req.ValidatorAddr, req.Delegation) + err = msg.ValidateBasic() if err != nil { - utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - if !bytes.Equal(info.GetPubKey().Address(), req.DelegatorAddr) { - utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") + if req.BaseReq.GenerateOnly { + utils.WriteGenerateStdTxResponse(w, cdc, req.BaseReq, []sdk.Msg{msg}) return } - msg := staking.NewMsgDelegate(req.DelegatorAddr, req.ValidatorAddr, req.Delegation) - err = msg.ValidateBasic() + // derive the from account address and name from the Keybase + fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } + cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress) + + if !bytes.Equal(cliCtx.GetFromAddress(), req.DelegatorAddr) { + utils.WriteErrorResponse(w, http.StatusUnauthorized, "must use own delegator address") + return + } + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc) } } @@ -105,24 +113,32 @@ func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx contex return } - info, err := kb.Get(req.BaseReq.Name) + msg := staking.NewMsgBeginRedelegate(req.DelegatorAddr, req.ValidatorSrcAddr, req.ValidatorDstAddr, req.SharesAmount) + err = msg.ValidateBasic() if err != nil { - utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - if !bytes.Equal(info.GetPubKey().Address(), req.DelegatorAddr) { - utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") + if req.BaseReq.GenerateOnly { + utils.WriteGenerateStdTxResponse(w, cdc, req.BaseReq, []sdk.Msg{msg}) return } - msg := staking.NewMsgBeginRedelegate(req.DelegatorAddr, req.ValidatorSrcAddr, req.ValidatorDstAddr, req.SharesAmount) - err = msg.ValidateBasic() + // derive the from account address and name from the Keybase + fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } + cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress) + + if !bytes.Equal(cliCtx.GetFromAddress(), req.DelegatorAddr) { + utils.WriteErrorResponse(w, http.StatusUnauthorized, "must use own delegator address") + return + } + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc) } } @@ -142,24 +158,32 @@ func postUnbondingDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx return } - info, err := kb.Get(req.BaseReq.Name) + msg := staking.NewMsgUndelegate(req.DelegatorAddr, req.ValidatorAddr, req.SharesAmount) + err = msg.ValidateBasic() if err != nil { - utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - if !bytes.Equal(info.GetPubKey().Address(), req.DelegatorAddr) { - utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") + if req.BaseReq.GenerateOnly { + utils.WriteGenerateStdTxResponse(w, cdc, req.BaseReq, []sdk.Msg{msg}) return } - msg := staking.NewMsgUndelegate(req.DelegatorAddr, req.ValidatorAddr, req.SharesAmount) - err = msg.ValidateBasic() + // derive the from account address and name from the Keybase + fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } + cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress) + + if !bytes.Equal(cliCtx.GetFromAddress(), req.DelegatorAddr) { + utils.WriteErrorResponse(w, http.StatusUnauthorized, "must use own delegator address") + return + } + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc) } }