Skip to content

Commit

Permalink
THORChain changes
Browse files Browse the repository at this point in the history
Support THORChain Ledger app v2.0.0
  • Loading branch information
HildisviniOttar committed Jul 15, 2021
1 parent 84d0a64 commit 3ac8e98
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 361 deletions.
18 changes: 0 additions & 18 deletions .circleci/config.yml

This file was deleted.

2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ install:
- go env

build_script:
- go build -x ./common.go ./user_app.go ./validator_app.go
- go build -x ./common.go ./user_app.go
- go test ./common

10 changes: 5 additions & 5 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
********************************************************************************/

package ledger_cosmos_go
package ledger_thorchain_go

import (
"encoding/binary"
Expand Down Expand Up @@ -53,20 +53,20 @@ func NewVersionRequiredError(req VersionInfo, ver VersionInfo) error {
// CheckVersion compares the current version with the required version
func CheckVersion(ver VersionInfo, req VersionInfo) error {
if ver.Major != req.Major {
if (ver.Major > req.Major){
if ver.Major > req.Major {
return nil
}
return NewVersionRequiredError(req, ver)
}

if ver.Minor != req.Minor {
if (ver.Minor > req.Minor) {
if ver.Minor > req.Minor {
return nil
}
return NewVersionRequiredError(req, ver)
}

if (ver.Patch >= req.Patch){
if ver.Patch >= req.Patch {
return nil
}
return NewVersionRequiredError(req, ver)
Expand Down Expand Up @@ -95,7 +95,7 @@ func GetBip32bytesv2(bip44Path []uint32, hardenCount int) ([]byte, error) {
return nil, fmt.Errorf("path should contain 5 elements")
}
for index, element := range bip44Path {
pos := index*4
pos := index * 4
value := element
if index < hardenCount {
value = 0x80000000 | element
Expand Down
2 changes: 1 addition & 1 deletion common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
********************************************************************************/

package ledger_cosmos_go
package ledger_thorchain_go

import (
"fmt"
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/cosmos/ledger-cosmos-go
module github.com/thorchain/ledger-thorchain-go

go 1.12

Expand Down
106 changes: 25 additions & 81 deletions user_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
* limitations under the License.
********************************************************************************/

package ledger_cosmos_go
/* THORChain uses same CLA (0x55) as Cosmos app, so okay to use cosmos/ledger-go for transport */
package ledger_thorchain_go

import (
"fmt"
"math"

"github.com/cosmos/ledger-go"
ledger_go "github.com/cosmos/ledger-go"
)

const (
Expand All @@ -33,27 +34,27 @@ const (
userMessageChunkSize = 250
)

// LedgerCosmos represents a connection to the Cosmos app in a Ledger Nano S device
type LedgerCosmos struct {
// LedgerTHORChain represents a connection to the THORChain app in a Ledger Nano S/X device
type LedgerTHORChain struct {
api *ledger_go.Ledger
version VersionInfo
}

// FindLedgerCosmosUserApp finds a Cosmos user app running in a ledger device
func FindLedgerCosmosUserApp() (*LedgerCosmos, error) {
// FindLedgerTHORChainUserApp finds a THORChain user app running in a ledger device
func FindLedgerTHORChainUserApp() (*LedgerTHORChain, error) {
ledgerAPI, err := ledger_go.FindLedger()

if err != nil {
return nil, err
}

app := LedgerCosmos{ledgerAPI, VersionInfo{}}
app := LedgerTHORChain{ledgerAPI, VersionInfo{}}
appVersion, err := app.GetVersion()

if err != nil {
defer ledgerAPI.Close()
if err.Error() == "[APDU_CODE_CLA_NOT_SUPPORTED] Class not supported" {
return nil, fmt.Errorf("are you sure the Cosmos app is open?")
return nil, fmt.Errorf("are you sure the THORChain app is open?")
}
return nil, err
}
Expand All @@ -67,30 +68,28 @@ func FindLedgerCosmosUserApp() (*LedgerCosmos, error) {
return &app, err
}

// Close closes a connection with the Cosmos user app
func (ledger *LedgerCosmos) Close() error {
// Close closes a connection with the THORChain user app
func (ledger *LedgerTHORChain) Close() error {
return ledger.api.Close()
}

// VersionIsSupported returns true if the App version is supported by this library
func (ledger *LedgerCosmos) CheckVersion(ver VersionInfo) error {
func (ledger *LedgerTHORChain) CheckVersion(ver VersionInfo) error {
version, err := ledger.GetVersion()
if err != nil {
return err
}

switch version.Major {
case 1:
return CheckVersion(ver, VersionInfo{0, 1, 5, 1})
case 2:
return CheckVersion(ver, VersionInfo{0, 2, 1, 0})
return CheckVersion(ver, VersionInfo{0, 2, 0, 0})
default:
return fmt.Errorf("App version is not supported")
}
}

// GetVersion returns the current version of the Cosmos user app
func (ledger *LedgerCosmos) GetVersion() (*VersionInfo, error) {
// GetVersion returns the current version of the THORChain user app
func (ledger *LedgerTHORChain) GetVersion() (*VersionInfo, error) {
message := []byte{userCLA, userINSGetVersion, 0, 0, 0}
response, err := ledger.api.Exchange(message)

Expand All @@ -103,7 +102,7 @@ func (ledger *LedgerCosmos) GetVersion() (*VersionInfo, error) {
}

ledger.version = VersionInfo{
AppMode: response[0],
AppMode: response[0], //Debug is 0xFF, otherwise 0x00
Major: response[1],
Minor: response[2],
Patch: response[3],
Expand All @@ -112,12 +111,10 @@ func (ledger *LedgerCosmos) GetVersion() (*VersionInfo, error) {
return &ledger.version, nil
}

// SignSECP256K1 signs a transaction using Cosmos user app
// SignSECP256K1 signs a transaction using THORChain user app
// this command requires user confirmation in the device
func (ledger *LedgerCosmos) SignSECP256K1(bip32Path []uint32, transaction []byte) ([]byte, error) {
func (ledger *LedgerTHORChain) SignSECP256K1(bip32Path []uint32, transaction []byte) ([]byte, error) {
switch ledger.version.Major {
case 1:
return ledger.signv1(bip32Path, transaction)
case 2:
return ledger.signv2(bip32Path, transaction)
default:
Expand All @@ -127,8 +124,8 @@ func (ledger *LedgerCosmos) SignSECP256K1(bip32Path []uint32, transaction []byte

// GetPublicKeySECP256K1 retrieves the public key for the corresponding bip32 derivation path (compressed)
// this command DOES NOT require user confirmation in the device
func (ledger *LedgerCosmos) GetPublicKeySECP256K1(bip32Path []uint32) ([]byte, error) {
pubkey, _, err := ledger.getAddressPubKeySECP256K1(bip32Path, "cosmos", false)
func (ledger *LedgerTHORChain) GetPublicKeySECP256K1(bip32Path []uint32) ([]byte, error) {
pubkey, _, err := ledger.getAddressPubKeySECP256K1(bip32Path, "thor", false)
return pubkey, err
}

Expand All @@ -139,11 +136,11 @@ func validHRPByte(b byte) bool {

// GetAddressPubKeySECP256K1 returns the pubkey (compressed) and address (bech(
// this command requires user confirmation in the device
func (ledger *LedgerCosmos) GetAddressPubKeySECP256K1(bip32Path []uint32, hrp string) (pubkey []byte, addr string, err error) {
func (ledger *LedgerTHORChain) GetAddressPubKeySECP256K1(bip32Path []uint32, hrp string) (pubkey []byte, addr string, err error) {
return ledger.getAddressPubKeySECP256K1(bip32Path, hrp, true)
}

func (ledger *LedgerCosmos) GetBip32bytes(bip32Path []uint32, hardenCount int) ([]byte, error) {
func (ledger *LedgerTHORChain) GetBip32bytes(bip32Path []uint32, hardenCount int) ([]byte, error) {
var pathBytes []byte
var err error

Expand All @@ -165,60 +162,7 @@ func (ledger *LedgerCosmos) GetBip32bytes(bip32Path []uint32, hardenCount int) (
return pathBytes, nil
}

func (ledger *LedgerCosmos) signv1(bip32Path []uint32, transaction []byte) ([]byte, error) {
var packetIndex byte = 1
var packetCount = 1 + byte(math.Ceil(float64(len(transaction))/float64(userMessageChunkSize)))

var finalResponse []byte

var message []byte

for packetIndex <= packetCount {
chunk := userMessageChunkSize
if packetIndex == 1 {
pathBytes, err := ledger.GetBip32bytes(bip32Path, 3)
if err != nil {
return nil, err
}
header := []byte{userCLA, userINSSignSECP256K1, packetIndex, packetCount, byte(len(pathBytes))}
message = append(header, pathBytes...)
} else {
if len(transaction) < userMessageChunkSize {
chunk = len(transaction)
}
header := []byte{userCLA, userINSSignSECP256K1, packetIndex, packetCount, byte(chunk)}
message = append(header, transaction[:chunk]...)
}

response, err := ledger.api.Exchange(message)
if err != nil {
if err.Error() == "[APDU_CODE_BAD_KEY_HANDLE] The parameters in the data field are incorrect" {
// In this special case, we can extract additional info
errorMsg := string(response)
switch errorMsg {
case "ERROR: JSMN_ERROR_NOMEM":
return nil, fmt.Errorf("Not enough tokens were provided")
case "PARSER ERROR: JSMN_ERROR_INVAL":
return nil, fmt.Errorf("Unexpected character in JSON string")
case "PARSER ERROR: JSMN_ERROR_PART":
return nil, fmt.Errorf("The JSON string is not a complete.")
}
return nil, fmt.Errorf(errorMsg)
}
return nil, err
}

finalResponse = response
if packetIndex > 1 {
transaction = transaction[chunk:]
}
packetIndex++

}
return finalResponse, nil
}

func (ledger *LedgerCosmos) signv2(bip32Path []uint32, transaction []byte) ([]byte, error) {
func (ledger *LedgerTHORChain) signv2(bip32Path []uint32, transaction []byte) ([]byte, error) {
var packetIndex byte = 1
var packetCount = 1 + byte(math.Ceil(float64(len(transaction))/float64(userMessageChunkSize)))

Expand Down Expand Up @@ -283,7 +227,7 @@ func (ledger *LedgerCosmos) signv2(bip32Path []uint32, transaction []byte) ([]by

// GetAddressPubKeySECP256K1 returns the pubkey (compressed) and address (bech(
// this command requires user confirmation in the device
func (ledger *LedgerCosmos) getAddressPubKeySECP256K1(bip32Path []uint32, hrp string, requireConfirmation bool) (pubkey []byte, addr string, err error) {
func (ledger *LedgerTHORChain) getAddressPubKeySECP256K1(bip32Path []uint32, hrp string, requireConfirmation bool) (pubkey []byte, addr string, err error) {
if len(hrp) > 83 {
return nil, "", fmt.Errorf("hrp len should be <10")
}
Expand Down Expand Up @@ -322,7 +266,7 @@ func (ledger *LedgerCosmos) getAddressPubKeySECP256K1(bip32Path []uint32, hrp st
}

pubkey = response[0:33]
addr = string(response[33:len(response)])
addr = string(response[33:])

return pubkey, addr, err
}
20 changes: 10 additions & 10 deletions user_app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
********************************************************************************/

package ledger_cosmos_go
package ledger_thorchain_go

import (
"crypto/sha256"
Expand All @@ -30,7 +30,7 @@ import (
// Ledger Test Mnemonic: equip will roof matter pink blind book anxiety banner elbow sun young

func Test_UserFindLedger(t *testing.T) {
userApp, err := FindLedgerCosmosUserApp()
userApp, err := FindLedgerTHORChainUserApp()
if err != nil {
t.Fatalf(err.Error())
}
Expand All @@ -40,7 +40,7 @@ func Test_UserFindLedger(t *testing.T) {
}

func Test_UserGetVersion(t *testing.T) {
userApp, err := FindLedgerCosmosUserApp()
userApp, err := FindLedgerTHORChainUserApp()
if err != nil {
t.Fatalf(err.Error())
}
Expand All @@ -59,7 +59,7 @@ func Test_UserGetVersion(t *testing.T) {
}

func Test_UserGetPublicKey(t *testing.T) {
userApp, err := FindLedgerCosmosUserApp()
userApp, err := FindLedgerTHORChainUserApp()
if err != nil {
t.Fatalf(err.Error())
}
Expand All @@ -85,7 +85,7 @@ func Test_UserGetPublicKey(t *testing.T) {
}

func Test_GetAddressPubKeySECP256K1_Zero(t *testing.T) {
userApp, err := FindLedgerCosmosUserApp()
userApp, err := FindLedgerTHORChainUserApp()
if err != nil {
t.Fatalf(err.Error())
}
Expand All @@ -111,7 +111,7 @@ func Test_GetAddressPubKeySECP256K1_Zero(t *testing.T) {
}

func Test_GetAddressPubKeySECP256K1(t *testing.T) {
userApp, err := FindLedgerCosmosUserApp()
userApp, err := FindLedgerTHORChainUserApp()
if err != nil {
t.Fatalf(err.Error())
}
Expand All @@ -137,7 +137,7 @@ func Test_GetAddressPubKeySECP256K1(t *testing.T) {
}

func Test_UserPK_HDPaths(t *testing.T) {
userApp, err := FindLedgerCosmosUserApp()
userApp, err := FindLedgerTHORChainUserApp()
if err != nil {
t.Fatalf(err.Error())
}
Expand Down Expand Up @@ -206,7 +206,7 @@ func getDummyTx() []byte {
}

func Test_UserSign(t *testing.T) {
userApp, err := FindLedgerCosmosUserApp()
userApp, err := FindLedgerTHORChainUserApp()
if err != nil {
t.Fatalf(err.Error())
}
Expand Down Expand Up @@ -254,7 +254,7 @@ func Test_UserSign(t *testing.T) {
}

func Test_UserSign_Fails(t *testing.T) {
userApp, err := FindLedgerCosmosUserApp()
userApp, err := FindLedgerTHORChainUserApp()
if err != nil {
t.Fatalf(err.Error())
}
Expand All @@ -273,6 +273,6 @@ func Test_UserSign_Fails(t *testing.T) {
errMessage := err.Error()

if errMessage != "Invalid character in JSON string" && errMessage != "Unexpected characters" {
assert.Fail(t, "Unexpected error message returned: " + errMessage )
assert.Fail(t, "Unexpected error message returned: "+errMessage)
}
}
Loading

0 comments on commit 3ac8e98

Please sign in to comment.