Skip to content

Commit

Permalink
Merge pull request #662 from cosmos/matt/ibc-rest
Browse files Browse the repository at this point in the history
REST IBC transfer endpoint
  • Loading branch information
ebuchman authored Mar 29, 2018
2 parents 072f8f1 + 5cfad33 commit 66a1130
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 0 deletions.
55 changes: 55 additions & 0 deletions client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
2 changes: 2 additions & 0 deletions client/lcd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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
}
14 changes: 14 additions & 0 deletions x/ibc/rest/root.go
Original file line number Diff line number Diff line change
@@ -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")
}
100 changes: 100 additions & 0 deletions x/ibc/rest/transfer.go
Original file line number Diff line number Diff line change
@@ -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)
}
}

0 comments on commit 66a1130

Please sign in to comment.