Merge pull request #662 from cosmos/matt/ibc-rest
REST IBC transfer endpoint
This commit is contained in:
commit
66a1130f9d
|
@ -252,6 +252,32 @@ func TestCoinSend(t *testing.T) {
|
|||
assert.Equal(t, int64(1), mycoins.Amount)
|
||||
}
|
||||
|
||||
func TestIBCTransfer(t *testing.T) {
|
||||
|
||||
// create TX
|
||||
resultTx := doIBCTransfer(t, port, seed)
|
||||
|
||||
time.Sleep(time.Second * 2) // T
|
||||
|
||||
// check if tx was commited
|
||||
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||
|
||||
// query sender
|
||||
res, body := request(t, port, "GET", "/accounts/"+sendAddr, nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var m auth.BaseAccount
|
||||
err := json.Unmarshal([]byte(body), &m)
|
||||
require.Nil(t, err)
|
||||
coins := m.Coins
|
||||
mycoins := coins[0]
|
||||
assert.Equal(t, coinDenom, mycoins.Denom)
|
||||
assert.Equal(t, coinAmount-2, mycoins.Amount)
|
||||
|
||||
// TODO: query ibc egress packet state
|
||||
}
|
||||
|
||||
func TestTxs(t *testing.T) {
|
||||
|
||||
// TODO: re-enable once we can get txs by tag
|
||||
|
@ -444,3 +470,32 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype
|
|||
|
||||
return receiveAddr, resultTx
|
||||
}
|
||||
|
||||
func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||
|
||||
// create receive address
|
||||
kb := client.MockKeyBase()
|
||||
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
||||
require.Nil(t, err)
|
||||
receiveAddr := receiveInfo.PubKey.Address().String()
|
||||
|
||||
// get the account to get the sequence
|
||||
res, body := request(t, port, "GET", "/accounts/"+sendAddr, nil)
|
||||
// require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
acc := auth.BaseAccount{}
|
||||
err = json.Unmarshal([]byte(body), &acc)
|
||||
require.Nil(t, err)
|
||||
fmt.Println("BODY", body)
|
||||
fmt.Println("ACC", acc)
|
||||
sequence := acc.Sequence
|
||||
|
||||
// send
|
||||
jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password":"%s", "sequence":%d, "amount":[{ "denom": "%s", "amount": 1 }] }`, name, password, sequence, coinDenom))
|
||||
res, body = request(t, port, "POST", "/ibc/testchain/"+receiveAddr+"/send", jsonStr)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
err = json.Unmarshal([]byte(body), &resultTx)
|
||||
require.Nil(t, err)
|
||||
|
||||
return resultTx
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
auth "github.com/cosmos/cosmos-sdk/x/auth/rest"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank/rest"
|
||||
ibc "github.com/cosmos/cosmos-sdk/x/ibc/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -78,5 +79,6 @@ func createHandler(cdc *wire.Codec) http.Handler {
|
|||
tx.RegisterRoutes(r, cdc)
|
||||
auth.RegisterRoutes(r, cdc, "main")
|
||||
bank.RegisterRoutes(r, cdc, kb)
|
||||
ibc.RegisterRoutes(r, cdc, kb)
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
// RegisterRoutes - Central function to define routes that get registered by the main application
|
||||
func RegisterRoutes(r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
|
||||
r.HandleFunc("/ibc/{destchain}/{address}/send", TransferRequestHandler(cdc, kb)).Methods("POST")
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/go-crypto/keys"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/commands"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
)
|
||||
|
||||
type transferBody struct {
|
||||
// Fees sdk.Coin `json="fees"`
|
||||
Amount sdk.Coins `json:"amount"`
|
||||
LocalAccountName string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
SrcChainID string `json:"src_chain_id"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
}
|
||||
|
||||
// TransferRequestHandler - http request handler to transfer coins to a address
|
||||
// on a different chain via IBC
|
||||
func TransferRequestHandler(cdc *wire.Codec, kb keys.Keybase) func(http.ResponseWriter, *http.Request) {
|
||||
c := commands.Commander{cdc}
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// collect data
|
||||
vars := mux.Vars(r)
|
||||
destChainID := vars["destchain"]
|
||||
address := vars["address"]
|
||||
|
||||
var m transferBody
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &m)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
info, err := kb.Get(m.LocalAccountName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
bz, err := hex.DecodeString(address)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
to := sdk.Address(bz)
|
||||
|
||||
// build message
|
||||
packet := ibc.NewIBCPacket(info.PubKey.Address(), to, m.Amount, m.SrcChainID, destChainID)
|
||||
msg := ibc.IBCTransferMsg{packet}
|
||||
|
||||
// sign
|
||||
// XXX: OMG
|
||||
viper.Set(client.FlagSequence, m.Sequence)
|
||||
txBytes, err := builder.SignAndBuild(m.LocalAccountName, m.Password, msg, c.Cdc)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// send
|
||||
res, err := builder.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
output, err := json.MarshalIndent(res, "", " ")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(output)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue