mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
Merge dc275944b2 into 4daaaadfc4
This commit is contained in:
commit
3830a5333d
3 changed files with 903 additions and 598 deletions
|
|
@ -50,6 +50,8 @@ var ErrTrezorPassphraseNeeded = errors.New("trezor: passphrase needed")
|
||||||
// is in browser mode.
|
// is in browser mode.
|
||||||
var errTrezorReplyInvalidHeader = errors.New("trezor: invalid reply header")
|
var errTrezorReplyInvalidHeader = errors.New("trezor: invalid reply header")
|
||||||
|
|
||||||
|
const trezorMaxDataChunk = 1024
|
||||||
|
|
||||||
// trezorDriver implements the communication with a Trezor hardware wallet.
|
// trezorDriver implements the communication with a Trezor hardware wallet.
|
||||||
type trezorDriver struct {
|
type trezorDriver struct {
|
||||||
device io.ReadWriter // USB device connection to communicate through
|
device io.ReadWriter // USB device connection to communicate through
|
||||||
|
|
@ -197,10 +199,7 @@ func (w *trezorDriver) trezorDerive(derivationPath []uint32) (common.Address, er
|
||||||
if _, err := w.trezorExchange(&trezor.EthereumGetAddress{AddressN: derivationPath}, address); err != nil {
|
if _, err := w.trezorExchange(&trezor.EthereumGetAddress{AddressN: derivationPath}, address); err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
if addr := address.GetAddressBin(); len(addr) > 0 { // Older firmwares use binary formats
|
if addr := address.GetAddress(); addr != "" {
|
||||||
return common.BytesToAddress(addr), nil
|
|
||||||
}
|
|
||||||
if addr := address.GetAddressHex(); len(addr) > 0 { // Newer firmwares use hexadecimal formats
|
|
||||||
return common.HexToAddress(addr), nil
|
return common.HexToAddress(addr), nil
|
||||||
}
|
}
|
||||||
return common.Address{}, errors.New("missing derived address")
|
return common.Address{}, errors.New("missing derived address")
|
||||||
|
|
@ -209,41 +208,24 @@ func (w *trezorDriver) trezorDerive(derivationPath []uint32) (common.Address, er
|
||||||
// trezorSign sends the transaction to the Trezor wallet, and waits for the user
|
// trezorSign sends the transaction to the Trezor wallet, and waits for the user
|
||||||
// to confirm or deny the transaction.
|
// to confirm or deny the transaction.
|
||||||
func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
|
func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
|
||||||
// Create the transaction initiation message
|
request, payload, err := w.buildSignRequest(derivationPath, tx, chainID)
|
||||||
data := tx.Data()
|
if err != nil {
|
||||||
length := uint32(len(data))
|
return common.Address{}, nil, err
|
||||||
|
|
||||||
request := &trezor.EthereumSignTx{
|
|
||||||
AddressN: derivationPath,
|
|
||||||
Nonce: new(big.Int).SetUint64(tx.Nonce()).Bytes(),
|
|
||||||
GasPrice: tx.GasPrice().Bytes(),
|
|
||||||
GasLimit: new(big.Int).SetUint64(tx.Gas()).Bytes(),
|
|
||||||
Value: tx.Value().Bytes(),
|
|
||||||
DataLength: &length,
|
|
||||||
}
|
}
|
||||||
if to := tx.To(); to != nil {
|
if len(payload) > trezorMaxDataChunk {
|
||||||
// Non contract deploy, set recipient explicitly
|
setInitialChunk(request, payload[:trezorMaxDataChunk])
|
||||||
hex := to.Hex()
|
payload = payload[trezorMaxDataChunk:]
|
||||||
request.ToHex = &hex // Newer firmwares (old will ignore)
|
|
||||||
request.ToBin = (*to)[:] // Older firmwares (new will ignore)
|
|
||||||
}
|
|
||||||
if length > 1024 { // Send the data chunked if that was requested
|
|
||||||
request.DataInitialChunk, data = data[:1024], data[1024:]
|
|
||||||
} else {
|
} else {
|
||||||
request.DataInitialChunk, data = data, nil
|
setInitialChunk(request, payload)
|
||||||
|
payload = nil
|
||||||
}
|
}
|
||||||
if chainID != nil { // EIP-155 transaction, set chain ID explicitly (only 32 bit is supported!?)
|
|
||||||
id := uint32(chainID.Int64())
|
|
||||||
request.ChainId = &id
|
|
||||||
}
|
|
||||||
// Send the initiation message and stream content until a signature is returned
|
|
||||||
response := new(trezor.EthereumTxRequest)
|
response := new(trezor.EthereumTxRequest)
|
||||||
if _, err := w.trezorExchange(request, response); err != nil {
|
if _, err := w.trezorExchange(request, response); err != nil {
|
||||||
return common.Address{}, nil, err
|
return common.Address{}, nil, err
|
||||||
}
|
}
|
||||||
for response.DataLength != nil && int(*response.DataLength) <= len(data) {
|
for response.DataLength != nil && int(*response.DataLength) <= len(payload) {
|
||||||
chunk := data[:*response.DataLength]
|
chunk := payload[:*response.DataLength]
|
||||||
data = data[*response.DataLength:]
|
payload = payload[*response.DataLength:]
|
||||||
|
|
||||||
if _, err := w.trezorExchange(&trezor.EthereumTxAck{DataChunk: chunk}, response); err != nil {
|
if _, err := w.trezorExchange(&trezor.EthereumTxAck{DataChunk: chunk}, response); err != nil {
|
||||||
return common.Address{}, nil, err
|
return common.Address{}, nil, err
|
||||||
|
|
@ -261,15 +243,21 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
|
||||||
|
|
||||||
// Create the correct signer and signature transform based on the chain ID
|
// Create the correct signer and signature transform based on the chain ID
|
||||||
var signer types.Signer
|
var signer types.Signer
|
||||||
|
legacyTx := tx.Type() == types.LegacyTxType
|
||||||
if chainID == nil {
|
if chainID == nil {
|
||||||
signer = new(types.HomesteadSigner)
|
signer = new(types.HomesteadSigner)
|
||||||
} else {
|
} else {
|
||||||
// Trezor backend does not support typed transactions yet.
|
signer = types.LatestSignerForChainID(chainID)
|
||||||
signer = types.NewEIP155Signer(chainID)
|
// Legacy (EIP-155) transactions still return the final ECDSA V value.
|
||||||
// if chainId is above (MaxUint32 - 36) / 2 then the final v values is returned
|
if legacyTx && signature[64] > 1 {
|
||||||
// directly. Otherwise, the returned value is 35 + chainid * 2.
|
if !chainID.IsUint64() {
|
||||||
if signature[64] > 1 && int(chainID.Int64()) <= (math.MaxUint32-36)/2 {
|
return common.Address{}, nil, errors.New("chain id overflows uint64")
|
||||||
signature[64] -= byte(chainID.Uint64()*2 + 35)
|
}
|
||||||
|
sigAdj := chainID.Uint64()*2 + 35
|
||||||
|
if sigAdj > math.MaxUint8 {
|
||||||
|
return common.Address{}, nil, errors.New("chain id is too large for trezor response")
|
||||||
|
}
|
||||||
|
signature[64] -= byte(sigAdj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,6 +273,126 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
|
||||||
return sender, signed, nil
|
return sender, signed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *trezorDriver) buildSignRequest(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (proto.Message, []byte, error) {
|
||||||
|
payload := tx.Data()
|
||||||
|
length := uint32(len(payload))
|
||||||
|
switch tx.Type() {
|
||||||
|
case types.LegacyTxType:
|
||||||
|
req := &trezor.EthereumSignTx{
|
||||||
|
AddressN: derivationPath,
|
||||||
|
Nonce: encodeUint64(tx.Nonce()),
|
||||||
|
GasPrice: bigIntBytes(tx.GasPrice()),
|
||||||
|
GasLimit: encodeUint64(tx.Gas()),
|
||||||
|
Value: bigIntBytes(tx.Value()),
|
||||||
|
DataLength: &length,
|
||||||
|
}
|
||||||
|
if chainID != nil {
|
||||||
|
if !chainID.IsUint64() {
|
||||||
|
return nil, nil, errors.New("chain id overflows trezor message")
|
||||||
|
}
|
||||||
|
id := chainID.Uint64()
|
||||||
|
req.ChainId = &id
|
||||||
|
}
|
||||||
|
if to := tx.To(); to != nil {
|
||||||
|
addr := to.Hex()
|
||||||
|
req.To = &addr
|
||||||
|
}
|
||||||
|
return req, payload, nil
|
||||||
|
case types.AccessListTxType, types.DynamicFeeTxType, types.BlobTxType:
|
||||||
|
if chainID == nil {
|
||||||
|
return nil, nil, errors.New("typed transactions require a chain id")
|
||||||
|
}
|
||||||
|
if !chainID.IsUint64() {
|
||||||
|
return nil, nil, errors.New("chain id overflows trezor message")
|
||||||
|
}
|
||||||
|
id := chainID.Uint64()
|
||||||
|
req := &trezor.EthereumSignTxEIP1559{
|
||||||
|
AddressN: derivationPath,
|
||||||
|
Nonce: encodeUint64(tx.Nonce()),
|
||||||
|
GasLimit: encodeUint64(tx.Gas()),
|
||||||
|
Value: bigIntBytes(tx.Value()),
|
||||||
|
DataLength: &length,
|
||||||
|
ChainId: &id,
|
||||||
|
AccessList: convertAccessListEIP1559(tx.AccessList()),
|
||||||
|
}
|
||||||
|
if to := tx.To(); to != nil {
|
||||||
|
addr := to.Hex()
|
||||||
|
req.To = &addr
|
||||||
|
}
|
||||||
|
switch tx.Type() {
|
||||||
|
case types.AccessListTxType:
|
||||||
|
price := bigIntBytes(tx.GasPrice())
|
||||||
|
req.MaxGasFee = price
|
||||||
|
req.MaxPriorityFee = price
|
||||||
|
case types.DynamicFeeTxType:
|
||||||
|
req.MaxGasFee = bigIntBytes(tx.GasFeeCap())
|
||||||
|
req.MaxPriorityFee = bigIntBytes(tx.GasTipCap())
|
||||||
|
case types.BlobTxType:
|
||||||
|
req.MaxGasFee = bigIntBytes(tx.GasFeeCap())
|
||||||
|
req.MaxPriorityFee = bigIntBytes(tx.GasTipCap())
|
||||||
|
req.MaxFeePerBlobGas = bigIntBytes(tx.BlobGasFeeCap())
|
||||||
|
req.BlobVersionedHashes = convertBlobHashes(tx.BlobHashes())
|
||||||
|
}
|
||||||
|
return req, payload, nil
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("unsupported transaction type %d", tx.Type())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeUint64(value uint64) []byte {
|
||||||
|
if value == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return new(big.Int).SetUint64(value).Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func bigIntBytes(v *big.Int) []byte {
|
||||||
|
if v == nil || v.Sign() == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return new(big.Int).Set(v).Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertAccessListEIP1559(list types.AccessList) []*trezor.EthereumSignTxEIP1559_EthereumAccessList {
|
||||||
|
if len(list) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([]*trezor.EthereumSignTxEIP1559_EthereumAccessList, len(list))
|
||||||
|
for i, entry := range list {
|
||||||
|
addr := entry.Address.Hex()
|
||||||
|
addrCopy := addr
|
||||||
|
keys := make([][]byte, len(entry.StorageKeys))
|
||||||
|
for j, key := range entry.StorageKeys {
|
||||||
|
keys[j] = append([]byte{}, key[:]...)
|
||||||
|
}
|
||||||
|
out[i] = &trezor.EthereumSignTxEIP1559_EthereumAccessList{
|
||||||
|
Address: &addrCopy,
|
||||||
|
StorageKeys: keys,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertBlobHashes(hashes []common.Hash) [][]byte {
|
||||||
|
if len(hashes) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([][]byte, len(hashes))
|
||||||
|
for i, h := range hashes {
|
||||||
|
out[i] = append([]byte{}, h[:]...)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func setInitialChunk(msg proto.Message, chunk []byte) {
|
||||||
|
switch req := msg.(type) {
|
||||||
|
case *trezor.EthereumSignTx:
|
||||||
|
req.DataInitialChunk = chunk
|
||||||
|
case *trezor.EthereumSignTxEIP1559:
|
||||||
|
req.DataInitialChunk = chunk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// trezorExchange performs a data exchange with the Trezor wallet, sending it a
|
// trezorExchange performs a data exchange with the Trezor wallet, sending it a
|
||||||
// message and retrieving the response. If multiple responses are possible, the
|
// message and retrieving the response. If multiple responses are possible, the
|
||||||
// method will also return the index of the destination object used.
|
// method will also return the index of the destination object used.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,18 +1,12 @@
|
||||||
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
|
||||||
// https://github.com/trezor/trezor-common/blob/master/protob/messages-ethereum.proto
|
|
||||||
// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9.
|
|
||||||
|
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
package hw.trezor.messages.ethereum;
|
package hw.trezor.messages.ethereum;
|
||||||
|
|
||||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
|
||||||
|
|
||||||
// Sugar for easier handling in Java
|
// Sugar for easier handling in Java
|
||||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||||
option java_outer_classname = "TrezorMessageEthereum";
|
option java_outer_classname = "TrezorMessageEthereum";
|
||||||
|
|
||||||
import "messages-common.proto";
|
import "messages-common.proto";
|
||||||
|
import "options.proto";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: Ask device for public key corresponding to address_n path
|
* Request: Ask device for public key corresponding to address_n path
|
||||||
|
|
@ -21,8 +15,8 @@ import "messages-common.proto";
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumGetPublicKey {
|
message EthereumGetPublicKey {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
optional bool show_display = 2; // optionally show on display before sending the result
|
optional bool show_display = 2; // optionally show on display before sending the result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -30,8 +24,8 @@ message EthereumGetPublicKey {
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message EthereumPublicKey {
|
message EthereumPublicKey {
|
||||||
optional hw.trezor.messages.common.HDNodeType node = 1; // BIP32 public node
|
required hw.trezor.messages.common.HDNodeType node = 1; // BIP32 public node
|
||||||
optional string xpub = 2; // serialized form of public node
|
required string xpub = 2; // serialized form of public node
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -41,8 +35,10 @@ message EthereumPublicKey {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumGetAddress {
|
message EthereumGetAddress {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
optional bool show_display = 2; // optionally show on display before sending the result
|
optional bool show_display = 2; // optionally show on display before sending the result
|
||||||
|
optional bytes encoded_network = 3; // encoded Ethereum network, see external-definitions.md for details
|
||||||
|
optional bool chunkify = 4; // display the address in chunks of 4 characters
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,30 +46,63 @@ message EthereumGetAddress {
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message EthereumAddress {
|
message EthereumAddress {
|
||||||
optional bytes addressBin = 1; // Ethereum address as 20 bytes (legacy firmwares)
|
optional bytes _old_address = 1 [deprecated=true]; // trezor <1.8.0, <2.1.0 - raw bytes of Ethereum address
|
||||||
optional string addressHex = 2; // Ethereum address as hex string (newer firmwares)
|
optional string address = 2; // Ethereum address as hex-encoded string
|
||||||
|
optional bytes mac = 3; // Address authentication code
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: Ask device to sign transaction
|
* Request: Ask device to sign transaction
|
||||||
* All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing.
|
* gas_price, gas_limit and chain_id must be provided and non-zero.
|
||||||
|
* All other fields are optional and default to value `0` if missing.
|
||||||
* Note: the first at most 1024 bytes of data MUST be transmitted as part of this message.
|
* Note: the first at most 1024 bytes of data MUST be transmitted as part of this message.
|
||||||
* @start
|
* @start
|
||||||
* @next EthereumTxRequest
|
* @next EthereumTxRequest
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumSignTx {
|
message EthereumSignTx {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
optional bytes nonce = 2; // <=256 bit unsigned big endian
|
optional bytes nonce = 2 [default='']; // <=256 bit unsigned big endian
|
||||||
optional bytes gas_price = 3; // <=256 bit unsigned big endian (in wei)
|
required bytes gas_price = 3; // <=256 bit unsigned big endian (in wei)
|
||||||
optional bytes gas_limit = 4; // <=256 bit unsigned big endian
|
required bytes gas_limit = 4; // <=256 bit unsigned big endian
|
||||||
optional bytes toBin = 5; // recipient address (20 bytes, legacy firmware)
|
optional string to = 11 [default='']; // recipient address
|
||||||
optional string toHex = 11; // recipient address (hex string, newer firmware)
|
optional bytes value = 6 [default='']; // <=256 bit unsigned big endian (in wei)
|
||||||
optional bytes value = 6; // <=256 bit unsigned big endian (in wei)
|
optional bytes data_initial_chunk = 7 [default='']; // The initial data chunk (<= 1024 bytes)
|
||||||
optional bytes data_initial_chunk = 7; // The initial data chunk (<= 1024 bytes)
|
optional uint32 data_length = 8 [default=0]; // Length of transaction payload
|
||||||
optional uint32 data_length = 8; // Length of transaction payload
|
required uint64 chain_id = 9; // Chain Id for EIP 155
|
||||||
optional uint32 chain_id = 9; // Chain Id for EIP 155
|
optional uint32 tx_type = 10; // Used for Wanchain
|
||||||
optional uint32 tx_type = 10; // (only for Wanchain)
|
optional EthereumDefinitions definitions = 12; // network and/or token definitions for tx
|
||||||
|
optional bool chunkify = 13; // display the address in chunks of 4 characters
|
||||||
|
optional common.PaymentRequest payment_req = 14 [(experimental_field)=true]; // SLIP-24 payment request
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Ask device to sign EIP1559 transaction
|
||||||
|
* Note: the first at most 1024 bytes of data MUST be transmitted as part of this message.
|
||||||
|
* @start
|
||||||
|
* @next EthereumTxRequest
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message EthereumSignTxEIP1559 {
|
||||||
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
|
required bytes nonce = 2; // <=256 bit unsigned big endian
|
||||||
|
required bytes max_gas_fee = 3; // <=256 bit unsigned big endian (in wei)
|
||||||
|
required bytes max_priority_fee = 4; // <=256 bit unsigned big endian (in wei)
|
||||||
|
required bytes gas_limit = 5; // <=256 bit unsigned big endian
|
||||||
|
optional string to = 6 [default='']; // recipient address
|
||||||
|
required bytes value = 7; // <=256 bit unsigned big endian (in wei)
|
||||||
|
optional bytes data_initial_chunk = 8 [default='']; // The initial data chunk (<= 1024 bytes)
|
||||||
|
required uint32 data_length = 9; // Length of transaction payload
|
||||||
|
required uint64 chain_id = 10; // Chain Id for EIP 155
|
||||||
|
repeated EthereumAccessList access_list = 11; // Access List
|
||||||
|
optional EthereumDefinitions definitions = 12; // network and/or token definitions for tx
|
||||||
|
optional bool chunkify = 13; // display the address in chunks of 4 characters
|
||||||
|
optional common.PaymentRequest payment_req = 14 [(experimental_field)=true]; // SLIP-24 payment request
|
||||||
|
|
||||||
|
message EthereumAccessList {
|
||||||
|
required string address = 1;
|
||||||
|
repeated bytes storage_keys = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -95,7 +124,7 @@ message EthereumTxRequest {
|
||||||
* @next EthereumTxRequest
|
* @next EthereumTxRequest
|
||||||
*/
|
*/
|
||||||
message EthereumTxAck {
|
message EthereumTxAck {
|
||||||
optional bytes data_chunk = 1; // Bytes from transaction payload (<= 1024 bytes)
|
required bytes data_chunk = 1; // Bytes from transaction payload (<= 1024 bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -105,8 +134,10 @@ message EthereumTxAck {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumSignMessage {
|
message EthereumSignMessage {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
optional bytes message = 2; // message to be signed
|
required bytes message = 2; // message to be signed
|
||||||
|
optional bytes encoded_network = 3; // encoded Ethereum network, see external-definitions.md for details
|
||||||
|
optional bool chunkify = 4; // display the address in chunks of 4 characters
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,9 +145,8 @@ message EthereumSignMessage {
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message EthereumMessageSignature {
|
message EthereumMessageSignature {
|
||||||
optional bytes addressBin = 1; // address used to sign the message (20 bytes, legacy firmware)
|
required bytes signature = 2; // signature of the message
|
||||||
optional bytes signature = 2; // signature of the message
|
required string address = 3; // address used to sign the message
|
||||||
optional string addressHex = 3; // address used to sign the message (hex string, newer firmware)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -126,8 +156,39 @@ message EthereumMessageSignature {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumVerifyMessage {
|
message EthereumVerifyMessage {
|
||||||
optional bytes addressBin = 1; // address to verify (20 bytes, legacy firmware)
|
required bytes signature = 2; // signature to verify
|
||||||
optional bytes signature = 2; // signature to verify
|
required bytes message = 3; // message to verify
|
||||||
optional bytes message = 3; // message to verify
|
required string address = 4; // address to verify
|
||||||
optional string addressHex = 4; // address to verify (hex string, newer firmware)
|
optional bool chunkify = 5; // display the address in chunks of 4 characters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Ask device to sign hash of typed data
|
||||||
|
* @start
|
||||||
|
* @next EthereumTypedDataSignature
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message EthereumSignTypedHash {
|
||||||
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
|
required bytes domain_separator_hash = 2; // Hash of domainSeparator of typed data to be signed
|
||||||
|
optional bytes message_hash = 3; // Hash of the data of typed data to be signed (empty if domain-only data)
|
||||||
|
optional bytes encoded_network = 4; // encoded Ethereum network, see external-definitions.md for details
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response: Signed typed data
|
||||||
|
* @end
|
||||||
|
*/
|
||||||
|
message EthereumTypedDataSignature {
|
||||||
|
required bytes signature = 1; // signature of the typed data
|
||||||
|
required string address = 2; // address used to sign the typed data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains an encoded network and/or token definition. See external-definitions.md for details.
|
||||||
|
* @embed
|
||||||
|
*/
|
||||||
|
message EthereumDefinitions {
|
||||||
|
optional bytes encoded_network = 1; // encoded ethereum network
|
||||||
|
optional bytes encoded_token = 2; // encoded ethereum token
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue