From ef68be2f38e84c0b3ad7c73dc22ad6be6e197792 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 19 Mar 2018 18:13:28 +0100 Subject: [PATCH 1/4] Added IBC transfer REST endpoint --- client/lcd/root.go | 2 + x/ibc/rest/root.go | 14 ++++++ x/ibc/rest/transfer.go | 100 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 x/ibc/rest/root.go create mode 100644 x/ibc/rest/transfer.go diff --git a/client/lcd/root.go b/client/lcd/root.go index 7f18af59dc..9464081e0d 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -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 } diff --git a/x/ibc/rest/root.go b/x/ibc/rest/root.go new file mode 100644 index 0000000000..81e74d0312 --- /dev/null +++ b/x/ibc/rest/root.go @@ -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") +} diff --git a/x/ibc/rest/transfer.go b/x/ibc/rest/transfer.go new file mode 100644 index 0000000000..f47159160e --- /dev/null +++ b/x/ibc/rest/transfer.go @@ -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) + } +} From bad5228c4c7e03a6d92dbeb86c716cb5f36bc6ee Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 19 Mar 2018 18:13:47 +0100 Subject: [PATCH 2/4] IBC transfer REST test --- client/lcd/lcd_test.go | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 99c040f1a3..f8555990d4 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -252,6 +252,41 @@ func TestCoinSend(t *testing.T) { assert.Equal(t, int64(1), mycoins.Amount) } +func TestIBCTransfer(t *testing.T) { + + // create TX + receiveAddr, resultTx := doSend(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) + + // query ibc egress packet state + res, body = request(t, port, "GET", "/accounts/"+receiveAddr, nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + 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, int64(1), mycoins.Amount) +} + func TestTxs(t *testing.T) { // TODO: re-enable once we can get txs by tag @@ -441,3 +476,32 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype return receiveAddr, resultTx } + +func doIBCTransfer(t *testing.T, port, seed string) (receiveAddr 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 receiveAddr, resultTx +} From 0eec9671b200d0e43d2daeda22c75b3b50035778 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 20 Mar 2018 11:53:02 +0100 Subject: [PATCH 3/4] Fixed IBC test --- client/lcd/lcd_test.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index f8555990d4..199fa54b5b 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -255,7 +255,7 @@ func TestCoinSend(t *testing.T) { func TestIBCTransfer(t *testing.T) { // create TX - receiveAddr, resultTx := doSend(t, port, seed) + resultTx := doIBCTransfer(t, port, seed) time.Sleep(time.Second * 2) // T @@ -275,16 +275,14 @@ func TestIBCTransfer(t *testing.T) { assert.Equal(t, coinDenom, mycoins.Denom) assert.Equal(t, coinAmount-2, mycoins.Amount) - // query ibc egress packet state - res, body = request(t, port, "GET", "/accounts/"+receiveAddr, nil) - require.Equal(t, http.StatusOK, res.StatusCode, body) + // TODO: query ibc egress packet state 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, int64(1), mycoins.Amount) + assert.Equal(t, int64(9999998), mycoins.Amount) } func TestTxs(t *testing.T) { @@ -477,13 +475,13 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype return receiveAddr, resultTx } -func doIBCTransfer(t *testing.T, port, seed string) (receiveAddr string, resultTx ctypes.ResultBroadcastTxCommit) { +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() + receiveAddr := receiveInfo.PubKey.Address().String() // get the account to get the sequence res, body := request(t, port, "GET", "/accounts/"+sendAddr, nil) @@ -503,5 +501,5 @@ func doIBCTransfer(t *testing.T, port, seed string) (receiveAddr string, resultT err = json.Unmarshal([]byte(body), &resultTx) require.Nil(t, err) - return receiveAddr, resultTx + return resultTx } From 5cfad33e49c8d1c7ac8d1a74a59172bc47d612ae Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 20 Mar 2018 13:46:02 +0100 Subject: [PATCH 4/4] Remove duplicate check --- client/lcd/lcd_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 199fa54b5b..39dbe83794 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -276,13 +276,6 @@ func TestIBCTransfer(t *testing.T) { assert.Equal(t, coinAmount-2, mycoins.Amount) // TODO: query ibc egress packet state - - 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, int64(9999998), mycoins.Amount) } func TestTxs(t *testing.T) {