Merge pull request #466 from LedgerHQ/feat/apa/nft_on_other_chains
NFT on other chains
8
.github/workflows/ci-workflow.yml
vendored
@@ -114,9 +114,9 @@ jobs:
|
||||
- name: Build testing binaries
|
||||
run: |
|
||||
mkdir tests/speculos/elfs
|
||||
make clean && make -j DEBUG=1 NFT_TESTING_KEY=1 BOLOS_SDK=$NANOS_SDK && mv bin/app.elf tests/speculos/elfs/nanos.elf
|
||||
make clean && make -j DEBUG=1 NFT_TESTING_KEY=1 BOLOS_SDK=$NANOX_SDK && mv bin/app.elf tests/speculos/elfs/nanox.elf
|
||||
make clean && make -j DEBUG=1 NFT_TESTING_KEY=1 BOLOS_SDK=$NANOSP_SDK && mv bin/app.elf tests/speculos/elfs/nanosp.elf
|
||||
make clean && make -j DEBUG=1 NFT_STAGING_KEY=1 BOLOS_SDK=$NANOS_SDK && mv bin/app.elf tests/speculos/elfs/nanos.elf
|
||||
make clean && make -j DEBUG=1 NFT_STAGING_KEY=1 BOLOS_SDK=$NANOX_SDK && mv bin/app.elf tests/speculos/elfs/nanox.elf
|
||||
make clean && make -j DEBUG=1 NFT_STAGING_KEY=1 BOLOS_SDK=$NANOSP_SDK && mv bin/app.elf tests/speculos/elfs/nanosp.elf
|
||||
|
||||
- name: Upload app binaries
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1
|
||||
with:
|
||||
upload_app_binaries_artifact: "ragger_elfs"
|
||||
flags: "DEBUG=1 CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1"
|
||||
flags: "DEBUG=1 CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
|
||||
|
||||
jobs-ragger-tests:
|
||||
name: Run Ragger tests
|
||||
|
||||
47
Makefile
@@ -136,25 +136,40 @@ endif
|
||||
endif
|
||||
|
||||
# Enables direct data signing without having to specify it in the settings. Useful when testing with speculos.
|
||||
ALLOW_DATA:=0
|
||||
ALLOW_DATA?=0
|
||||
ifneq ($(ALLOW_DATA),0)
|
||||
DEFINES += HAVE_ALLOW_DATA
|
||||
endif
|
||||
|
||||
# Bypass the signature verification for setExternalPlugin, setPlugin, provideERC20TokenInfo and provideNFTInfo calls
|
||||
BYPASS_SIGNATURES:=0
|
||||
BYPASS_SIGNATURES?=0
|
||||
ifneq ($(BYPASS_SIGNATURES),0)
|
||||
DEFINES += HAVE_BYPASS_SIGNATURES
|
||||
endif
|
||||
|
||||
# Enable the SET_PLUGIN test key
|
||||
SET_PLUGIN_TEST_KEY?=0
|
||||
ifneq ($(SET_PLUGIN_TEST_KEY),0)
|
||||
DEFINES += HAVE_SET_PLUGIN_TEST_KEY
|
||||
endif
|
||||
|
||||
# NFTs
|
||||
ifneq ($(TARGET_NAME),TARGET_NANOS)
|
||||
DEFINES += HAVE_NFT_SUPPORT
|
||||
# Enable the NFT testing key
|
||||
NFT_TESTING_KEY:=0
|
||||
ifneq ($(NFT_TESTING_KEY),0)
|
||||
DEFINES += HAVE_NFT_TESTING_KEY
|
||||
DEFINES += HAVE_NFT_SUPPORT
|
||||
NFT_TEST_KEY?=0
|
||||
ifneq ($(NFT_TEST_KEY),0)
|
||||
DEFINES += HAVE_NFT_TEST_KEY
|
||||
endif
|
||||
NFT_STAGING_KEY?=0
|
||||
ifneq ($(NFT_STAGING_KEY),0)
|
||||
# Key used by the staging backend
|
||||
DEFINES += HAVE_NFT_STAGING_KEY
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(filter $(DEFINES),HAVE_NFT_TEST_KEY))
|
||||
ifneq (, $(filter $(DEFINES),HAVE_NFT_STAGING_KEY))
|
||||
$(error Multiple alternative NFT keys set at once)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Dynamic memory allocator
|
||||
@@ -168,19 +183,25 @@ DEFINES += HAVE_EIP712_FULL_SUPPORT
|
||||
endif
|
||||
|
||||
# CryptoAssetsList key
|
||||
CAL_TEST_KEY:=0
|
||||
CAL_CI_KEY:=0
|
||||
CAL_TEST_KEY?=0
|
||||
ifneq ($(CAL_TEST_KEY),0)
|
||||
DEFINES += HAVE_CAL_TEST_KEY
|
||||
DEFINES += HAVE_CAL_TEST_KEY
|
||||
endif
|
||||
ifneq ($(CAL_CI_KEY),0)
|
||||
DEFINES += HAVE_CAL_CI_KEY
|
||||
CAL_STAGING_KEY?=0
|
||||
ifneq ($(CAL_STAGING_KEY),0)
|
||||
# Key used by the staging CAL
|
||||
DEFINES += HAVE_CAL_STAGING_KEY
|
||||
endif
|
||||
ifneq (,$(filter $(DEFINES),HAVE_CAL_TEST_KEY))
|
||||
ifneq (, $(filter $(DEFINES),HAVE_CAL_STAGING_KEY))
|
||||
$(error Multiple alternative CAL keys set at once)
|
||||
endif
|
||||
endif
|
||||
|
||||
# ENS
|
||||
ifneq ($(TARGET_NAME),TARGET_NANOS)
|
||||
DEFINES += HAVE_DOMAIN_NAME
|
||||
DOMAIN_NAME_TEST_KEY:=0
|
||||
DOMAIN_NAME_TEST_KEY?=0
|
||||
ifneq ($(DOMAIN_NAME_TEST_KEY),0)
|
||||
DEFINES += HAVE_DOMAIN_NAME_TEST_KEY
|
||||
endif
|
||||
|
||||
@@ -29,6 +29,7 @@ requires-python = ">=3.7"
|
||||
dependencies = [
|
||||
"ragger[speculos]",
|
||||
"simple-rlp",
|
||||
"pysha3",
|
||||
]
|
||||
|
||||
[tools.setuptools]
|
||||
|
||||
@@ -11,7 +11,14 @@ from .tlv import format_tlv
|
||||
|
||||
|
||||
WEI_IN_ETH = 1e+18
|
||||
GWEI_IN_ETH = 1e+9
|
||||
|
||||
class TxData:
|
||||
selector: bytes
|
||||
parameters: list[bytes]
|
||||
def __init__(self, selector: bytes, params: list[bytes]):
|
||||
self.selector = selector
|
||||
self.parameters = params
|
||||
|
||||
class StatusWord(IntEnum):
|
||||
OK = 0x9000
|
||||
@@ -96,31 +103,79 @@ class EthAppClient:
|
||||
def eip712_filtering_show_field(self, name: str, sig: bytes):
|
||||
return self._send(self._cmd_builder.eip712_filtering_show_field(name, sig))
|
||||
|
||||
def send_fund(self,
|
||||
bip32_path: str,
|
||||
nonce: int,
|
||||
gas_price: int,
|
||||
gas_limit: int,
|
||||
to: bytes,
|
||||
amount: float,
|
||||
chain_id: int):
|
||||
data: List[Union[int, bytes]] = list()
|
||||
data.append(nonce)
|
||||
data.append(gas_price)
|
||||
data.append(gas_limit)
|
||||
data.append(to)
|
||||
data.append(int(amount * WEI_IN_ETH))
|
||||
data.append(bytes())
|
||||
data.append(chain_id)
|
||||
data.append(bytes())
|
||||
data.append(bytes())
|
||||
|
||||
chunks = self._cmd_builder.sign(bip32_path, rlp.encode(data))
|
||||
def _sign(self, bip32_path: str, raw_tx: bytes):
|
||||
chunks = self._cmd_builder.sign(bip32_path, raw_tx)
|
||||
for chunk in chunks[:-1]:
|
||||
with self._send(chunk):
|
||||
pass
|
||||
return self._send(chunks[-1])
|
||||
|
||||
def _data_to_payload(self, data: TxData) -> bytes:
|
||||
payload = bytearray(data.selector)
|
||||
for param in data.parameters:
|
||||
payload += param.rjust(32, b'\x00')
|
||||
return payload
|
||||
|
||||
def _sign_common(self,
|
||||
tx: list,
|
||||
gas_price: float,
|
||||
gas_limit: int,
|
||||
destination: bytes,
|
||||
amount: float,
|
||||
data: TxData):
|
||||
tx.append(int(gas_price * GWEI_IN_ETH))
|
||||
tx.append(gas_limit)
|
||||
tx.append(destination)
|
||||
if amount > 0:
|
||||
tx.append(int(amount * WEI_IN_ETH))
|
||||
else:
|
||||
tx.append(bytes())
|
||||
if data is not None:
|
||||
tx.append(self._data_to_payload(data))
|
||||
else:
|
||||
tx.append(bytes())
|
||||
return tx
|
||||
|
||||
def sign_legacy(self,
|
||||
bip32_path: str,
|
||||
nonce: int,
|
||||
gas_price: float,
|
||||
gas_limit: int,
|
||||
destination: bytes,
|
||||
amount: float,
|
||||
chain_id: int,
|
||||
data: TxData = None):
|
||||
tx = list()
|
||||
tx.append(nonce)
|
||||
tx = self._sign_common(tx, gas_price, gas_limit, destination, amount, data)
|
||||
tx.append(chain_id)
|
||||
tx.append(bytes())
|
||||
tx.append(bytes())
|
||||
return self._sign(bip32_path, rlp.encode(tx))
|
||||
|
||||
def sign_1559(self,
|
||||
bip32_path: str,
|
||||
chain_id: int,
|
||||
nonce: int,
|
||||
max_prio_gas_price: float,
|
||||
max_gas_price: float,
|
||||
gas_limit: int,
|
||||
destination: bytes,
|
||||
amount: float,
|
||||
data: TxData = None,
|
||||
access_list = list()):
|
||||
tx = list()
|
||||
tx.append(chain_id)
|
||||
tx.append(nonce)
|
||||
tx.append(int(max_prio_gas_price * GWEI_IN_ETH))
|
||||
tx = self._sign_common(tx, max_gas_price, gas_limit, destination, amount, data)
|
||||
tx.append(access_list)
|
||||
tx.append(False)
|
||||
tx.append(bytes())
|
||||
tx.append(bytes())
|
||||
# prefix with transaction type
|
||||
return self._sign(bip32_path, b'\x02' + rlp.encode(tx))
|
||||
|
||||
def get_challenge(self):
|
||||
return self._send(self._cmd_builder.get_challenge())
|
||||
|
||||
@@ -151,3 +206,68 @@ class EthAppClient:
|
||||
with self._send(chunk):
|
||||
pass
|
||||
return self._send(chunks[-1])
|
||||
|
||||
def set_plugin(self,
|
||||
plugin_name: str,
|
||||
contract_addr: bytes,
|
||||
selector: bytes,
|
||||
chain_id: int,
|
||||
type_: int = 1,
|
||||
version: int = 1,
|
||||
key_id: int = 2,
|
||||
algo_id: int = 1,
|
||||
sig: Optional[bytes] = None):
|
||||
if sig is None:
|
||||
# Temporarily get a command with an empty signature to extract the payload and
|
||||
# compute the signature on it
|
||||
tmp = self._cmd_builder.set_plugin(type_,
|
||||
version,
|
||||
plugin_name,
|
||||
contract_addr,
|
||||
selector,
|
||||
chain_id,
|
||||
key_id,
|
||||
algo_id,
|
||||
bytes())
|
||||
# skip APDU header & empty sig
|
||||
sig = sign_data(Key.SET_PLUGIN, tmp[5:-1])
|
||||
return self._send(self._cmd_builder.set_plugin(type_,
|
||||
version,
|
||||
plugin_name,
|
||||
contract_addr,
|
||||
selector,
|
||||
chain_id,
|
||||
key_id,
|
||||
algo_id,
|
||||
sig))
|
||||
|
||||
def provide_nft_metadata(self,
|
||||
collection: str,
|
||||
addr: bytes,
|
||||
chain_id: int,
|
||||
type_: int = 1,
|
||||
version: int = 1,
|
||||
key_id: int = 1,
|
||||
algo_id: int = 1,
|
||||
sig: Optional[bytes] = None):
|
||||
if sig is None:
|
||||
# Temporarily get a command with an empty signature to extract the payload and
|
||||
# compute the signature on it
|
||||
tmp = self._cmd_builder.provide_nft_information(type_,
|
||||
version,
|
||||
collection,
|
||||
addr,
|
||||
chain_id,
|
||||
key_id,
|
||||
algo_id,
|
||||
bytes())
|
||||
# skip APDU header & empty sig
|
||||
sig = sign_data(Key.NFT, tmp[5:-1])
|
||||
return self._send(self._cmd_builder.provide_nft_information(type_,
|
||||
version,
|
||||
collection,
|
||||
addr,
|
||||
chain_id,
|
||||
key_id,
|
||||
algo_id,
|
||||
sig))
|
||||
|
||||
@@ -10,6 +10,8 @@ from .eip712 import EIP712FieldType
|
||||
class InsType(IntEnum):
|
||||
GET_PUBLIC_ADDR = 0x02
|
||||
SIGN = 0x04
|
||||
PROVIDE_NFT_INFORMATION = 0x14
|
||||
SET_PLUGIN = 0x16
|
||||
EIP712_SEND_STRUCT_DEF = 0x1a
|
||||
EIP712_SEND_STRUCT_IMPL = 0x1c
|
||||
EIP712_SEND_FILTERING = 0x1e
|
||||
@@ -219,3 +221,49 @@ class CommandBuilder:
|
||||
int(display),
|
||||
int(chaincode),
|
||||
payload)
|
||||
|
||||
def set_plugin(self,
|
||||
type_: int,
|
||||
version: int,
|
||||
plugin_name: str,
|
||||
contract_addr: bytes,
|
||||
selector: bytes,
|
||||
chain_id: int,
|
||||
key_id: int,
|
||||
algo_id: int,
|
||||
sig: bytes) -> bytes:
|
||||
payload = bytearray()
|
||||
payload.append(type_)
|
||||
payload.append(version)
|
||||
payload.append(len(plugin_name))
|
||||
payload += plugin_name.encode()
|
||||
payload += contract_addr
|
||||
payload += selector
|
||||
payload += struct.pack(">Q", chain_id)
|
||||
payload.append(key_id)
|
||||
payload.append(algo_id)
|
||||
payload.append(len(sig))
|
||||
payload += sig
|
||||
return self._serialize(InsType.SET_PLUGIN, 0x00, 0x00, payload)
|
||||
|
||||
def provide_nft_information(self,
|
||||
type_: int,
|
||||
version: int,
|
||||
collection_name: str,
|
||||
addr: bytes,
|
||||
chain_id: int,
|
||||
key_id: int,
|
||||
algo_id: int,
|
||||
sig: bytes):
|
||||
payload = bytearray()
|
||||
payload.append(type_)
|
||||
payload.append(version)
|
||||
payload.append(len(collection_name))
|
||||
payload += collection_name.encode()
|
||||
payload += addr
|
||||
payload += struct.pack(">Q", chain_id)
|
||||
payload.append(key_id)
|
||||
payload.append(algo_id)
|
||||
payload.append(len(sig))
|
||||
payload += sig
|
||||
return self._serialize(InsType.PROVIDE_NFT_INFORMATION, 0x00, 0x00, payload)
|
||||
|
||||
@@ -11,6 +11,8 @@ from typing import Dict
|
||||
class Key(Enum):
|
||||
CAL = auto()
|
||||
DOMAIN_NAME = auto()
|
||||
SET_PLUGIN = auto()
|
||||
NFT = auto()
|
||||
|
||||
|
||||
_keys: Dict[Key, SigningKey] = dict()
|
||||
|
||||
8
client/src/ledger_app_clients/ethereum/keychain/nft.pem
Normal file
@@ -0,0 +1,8 @@
|
||||
-----BEGIN EC PARAMETERS-----
|
||||
BgUrgQQACg==
|
||||
-----END EC PARAMETERS-----
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHQCAQEEIK69Gt4o0bzkOaEwUE5X2tI+Ks80FQi785Co+6woU9hioAcGBSuBBAAK
|
||||
oUQDQgAEPPtfsxkF9L052dU1pAwmqrUcXX0yGbKKyUK5gPsgbPswtRzC3iEZrAOO
|
||||
uw191lQXcCBKPO06eeKLMvu2cmRowA==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -0,0 +1,8 @@
|
||||
-----BEGIN EC PARAMETERS-----
|
||||
BgUrgQQACg==
|
||||
-----END EC PARAMETERS-----
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHQCAQEEIBErwcYvqeKSOlmQ/j3xPkVcwFf+j1aiMsA+RabczvN7oAcGBSuBBAAK
|
||||
oUQDQgAEwFW8Ts8FXi2FCF01Eno95nBcf4hQVc1wceh2cb8ZH+M8yPAavC8ofIGa
|
||||
FIq+G1gd8bSUCvXU3DpOa2AZF3ErNw==
|
||||
-----END EC PRIVATE KEY-----
|
||||
4
client/src/ledger_app_clients/ethereum/utils.py
Normal file
@@ -0,0 +1,4 @@
|
||||
import sha3
|
||||
|
||||
def get_selector_from_function(fn: str) -> bytes:
|
||||
return sha3.keccak_256(fn.encode()).digest()[0:4]
|
||||
@@ -528,7 +528,7 @@ The plugin names `ERC20`, `ERC721` and `ERC1155` are reserved. Additional plugin
|
||||
|
||||
The signature is computed on
|
||||
|
||||
type || version || len(pluginName) || pluginName || address || selector || chainId || keyId || algorithmId || len(signature) || signature
|
||||
type || version || len(pluginName) || pluginName || address || selector || chainId || keyId || algorithmId
|
||||
|
||||
#### Coding
|
||||
|
||||
|
||||
18
src/tokens.h
@@ -43,24 +43,20 @@ extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
|
||||
|
||||
#ifndef HAVE_TOKENS_LIST
|
||||
|
||||
#if defined(HAVE_CAL_TEST_KEY) && defined(HAVE_CAL_CI_KEY)
|
||||
#error "CAL key contradiction, two alternative keys selected at once"
|
||||
#endif
|
||||
|
||||
static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
|
||||
#if defined(HAVE_CAL_TEST_KEY)
|
||||
// test key 2019-01-11 03:07PM (erc20signer)
|
||||
0x04, 0x20, 0xda, 0x62, 0x00, 0x3c, 0x0c, 0xe0, 0x97, 0xe3, 0x36, 0x44, 0xa1, 0x0f,
|
||||
0xe4, 0xc3, 0x04, 0x54, 0x06, 0x9a, 0x44, 0x54, 0xf0, 0xfa, 0x9d, 0x4e, 0x84, 0xf4,
|
||||
0x50, 0x91, 0x42, 0x9b, 0x52, 0x20, 0xaf, 0x9e, 0x35, 0xc0, 0xb2, 0xd9, 0x28, 0x93,
|
||||
0x80, 0x13, 0x73, 0x07, 0xde, 0x4d, 0xd1, 0xd4, 0x18, 0x42, 0x8c, 0xf2, 0x1a, 0x93,
|
||||
0xb3, 0x35, 0x61, 0xbb, 0x09, 0xd8, 0x8f, 0xe5, 0x79
|
||||
#elif defined(HAVE_CAL_CI_KEY)
|
||||
0x04, 0x4c, 0xca, 0x8f, 0xad, 0x49, 0x6a, 0xa5, 0x04, 0x0a, 0x00, 0xa7, 0xeb, 0x2f,
|
||||
0x5c, 0xc3, 0xb8, 0x53, 0x76, 0xd8, 0x8b, 0xa1, 0x47, 0xa7, 0xd7, 0x05, 0x4a, 0x99,
|
||||
0xc6, 0x40, 0x56, 0x18, 0x87, 0xfe, 0x17, 0xa0, 0x96, 0xe3, 0x6c, 0x3b, 0x52, 0x3b,
|
||||
0x24, 0x4f, 0x3e, 0x2f, 0xf7, 0xf8, 0x40, 0xae, 0x26, 0xc4, 0xe7, 0x7a, 0xd3, 0xbc,
|
||||
0x73, 0x9a, 0xf5, 0xde, 0x6f, 0x2d, 0x77, 0xa7, 0xb6
|
||||
#elif defined(HAVE_CAL_STAGING_KEY)
|
||||
// staging key 2019-01-11 03:07PM (erc20signer)
|
||||
0x04, 0x20, 0xda, 0x62, 0x00, 0x3c, 0x0c, 0xe0, 0x97, 0xe3, 0x36, 0x44, 0xa1, 0x0f,
|
||||
0xe4, 0xc3, 0x04, 0x54, 0x06, 0x9a, 0x44, 0x54, 0xf0, 0xfa, 0x9d, 0x4e, 0x84, 0xf4,
|
||||
0x50, 0x91, 0x42, 0x9b, 0x52, 0x20, 0xaf, 0x9e, 0x35, 0xc0, 0xb2, 0xd9, 0x28, 0x93,
|
||||
0x80, 0x13, 0x73, 0x07, 0xde, 0x4d, 0xd1, 0xd4, 0x18, 0x42, 0x8c, 0xf2, 0x1a, 0x93,
|
||||
0xb3, 0x35, 0x61, 0xbb, 0x09, 0xd8, 0x8f, 0xe5, 0x79
|
||||
#else
|
||||
// production key 2019-01-11 03:07PM (erc20signer)
|
||||
0x04, 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9, 0x7c,
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
#define MIN_DER_SIG_SIZE 67
|
||||
#define MAX_DER_SIG_SIZE 72
|
||||
|
||||
#define TEST_NFT_METADATA_KEY 0
|
||||
#define PROD_NFT_METADATA_KEY 1
|
||||
#define STAGING_NFT_METADATA_KEY 0
|
||||
#define PROD_NFT_METADATA_KEY 1
|
||||
|
||||
#define ALGORITHM_ID_1 1
|
||||
|
||||
@@ -29,13 +29,19 @@
|
||||
#define VERSION_1 1
|
||||
|
||||
static const uint8_t LEDGER_NFT_METADATA_PUBLIC_KEY[] = {
|
||||
#ifdef HAVE_NFT_TESTING_KEY
|
||||
#if defined(HAVE_NFT_TEST_KEY)
|
||||
0x04, 0x3c, 0xfb, 0x5f, 0xb3, 0x19, 0x05, 0xf4, 0xbd, 0x39, 0xd9, 0xd5, 0x35, 0xa4,
|
||||
0x0c, 0x26, 0xaa, 0xb5, 0x1c, 0x5d, 0x7d, 0x32, 0x19, 0xb2, 0x8a, 0xc9, 0x42, 0xb9,
|
||||
0x80, 0xfb, 0x20, 0x6c, 0xfb, 0x30, 0xb5, 0x1c, 0xc2, 0xde, 0x21, 0x19, 0xac, 0x03,
|
||||
0x8e, 0xbb, 0x0d, 0x7d, 0xd6, 0x54, 0x17, 0x70, 0x20, 0x4a, 0x3c, 0xed, 0x3a, 0x79,
|
||||
0xe2, 0x8b, 0x32, 0xfb, 0xb6, 0x72, 0x64, 0x68, 0xc0
|
||||
#elif defined(HAVE_NFT_STAGING_KEY)
|
||||
0x04, 0xf5, 0x70, 0x0c, 0xa1, 0xe8, 0x74, 0x24, 0xc7, 0xc7, 0xd1, 0x19, 0xe7, 0xe3,
|
||||
0xc1, 0x89, 0xb1, 0x62, 0x50, 0x94, 0xdb, 0x6e, 0xa0, 0x40, 0x87, 0xc8, 0x30, 0x00,
|
||||
0x7d, 0x0b, 0x46, 0x9a, 0x53, 0x11, 0xee, 0x6a, 0x1a, 0xcd, 0x1d, 0xa5, 0xaa, 0xb0,
|
||||
0xf5, 0xc6, 0xdf, 0x13, 0x15, 0x8d, 0x28, 0xcc, 0x12, 0xd1, 0xdd, 0xa6, 0xec, 0xe9,
|
||||
0x46, 0xb8, 0x9d, 0x5c, 0x05, 0x49, 0x92, 0x59, 0xc4
|
||||
#else
|
||||
#else // production key
|
||||
0x04, 0x98, 0x8d, 0xa6, 0xb2, 0x46, 0xf2, 0x8e, 0x77, 0xc1, 0xba, 0xb6, 0x75, 0xcb,
|
||||
0x2a, 0x27, 0x44, 0xf7, 0xf5, 0xce, 0xc5, 0x6a, 0xe6, 0xe0, 0x32, 0x23, 0x33, 0x7b,
|
||||
0x57, 0x94, 0xcd, 0x6a, 0xe0, 0x7d, 0x48, 0xb3, 0x0d, 0xb9, 0xcc, 0xb4, 0x0f, 0x5a,
|
||||
@@ -140,13 +146,13 @@ void handleProvideNFTInformation(uint8_t p1,
|
||||
PRINTF("Address: %.*H\n", ADDRESS_LENGTH, workBuffer + offset);
|
||||
offset += ADDRESS_LENGTH;
|
||||
|
||||
uint64_t chainId = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
|
||||
uint64_t chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
|
||||
// this prints raw data, so to have a more meaningful print, display
|
||||
// the buffer before the endianness swap
|
||||
PRINTF("ChainID: %.*H\n", sizeof(chainId), (workBuffer + offset));
|
||||
if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) {
|
||||
PRINTF("Chain ID token mismatch\n");
|
||||
THROW(0x6A80);
|
||||
PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset));
|
||||
if (!chain_is_ethereum_compatible(&chain_id)) {
|
||||
PRINTF("Unsupported chain ID!\n");
|
||||
THROW(APDU_RESPONSE_INVALID_DATA);
|
||||
}
|
||||
offset += CHAIN_ID_SIZE;
|
||||
|
||||
@@ -156,8 +162,8 @@ void handleProvideNFTInformation(uint8_t p1,
|
||||
|
||||
PRINTF("KeyID: %d\n", keyId);
|
||||
switch (keyId) {
|
||||
#ifdef HAVE_NFT_TESTING_KEY
|
||||
case TEST_NFT_METADATA_KEY:
|
||||
#ifdef HAVE_NFT_STAGING_KEY
|
||||
case STAGING_NFT_METADATA_KEY:
|
||||
#endif
|
||||
case PROD_NFT_METADATA_KEY:
|
||||
rawKey = (uint8_t *) LEDGER_NFT_METADATA_PUBLIC_KEY;
|
||||
|
||||
@@ -46,7 +46,13 @@ typedef enum AlgorithmID {
|
||||
|
||||
// Only used for signing NFT plugins (ERC721 and ERC1155)
|
||||
static const uint8_t LEDGER_NFT_SELECTOR_PUBLIC_KEY[] = {
|
||||
#ifdef HAVE_NFT_TESTING_KEY
|
||||
#if defined(HAVE_SET_PLUGIN_TEST_KEY)
|
||||
0x04, 0xc0, 0x55, 0xbc, 0x4e, 0xcf, 0x05, 0x5e, 0x2d, 0x85, 0x08, 0x5d, 0x35, 0x12,
|
||||
0x7a, 0x3d, 0xe6, 0x70, 0x5c, 0x7f, 0x88, 0x50, 0x55, 0xcd, 0x70, 0x71, 0xe8, 0x76,
|
||||
0x71, 0xbf, 0x19, 0x1f, 0xe3, 0x3c, 0xc8, 0xf0, 0x1a, 0xbc, 0x2f, 0x28, 0x7c, 0x81,
|
||||
0x9a, 0x14, 0x8a, 0xbe, 0x1b, 0x58, 0x1d, 0xf1, 0xb4, 0x94, 0x0a, 0xf5, 0xd4, 0xdc,
|
||||
0x3a, 0x4e, 0x6b, 0x60, 0x19, 0x17, 0x71, 0x2b, 0x37
|
||||
#elif defined(HAVE_NFT_STAGING_KEY)
|
||||
0x04, 0xf5, 0x70, 0x0c, 0xa1, 0xe8, 0x74, 0x24, 0xc7, 0xc7, 0xd1, 0x19, 0xe7, 0xe3,
|
||||
0xc1, 0x89, 0xb1, 0x62, 0x50, 0x94, 0xdb, 0x6e, 0xa0, 0x40, 0x87, 0xc8, 0x30, 0x00,
|
||||
0x7d, 0x0b, 0x46, 0x9a, 0x53, 0x11, 0xee, 0x6a, 0x1a, 0xcd, 0x1d, 0xa5, 0xaa, 0xb0,
|
||||
@@ -169,13 +175,13 @@ void handleSetPlugin(uint8_t p1,
|
||||
PRINTF("Selector: %.*H\n", SELECTOR_SIZE, tokenContext->methodSelector);
|
||||
offset += SELECTOR_SIZE;
|
||||
|
||||
uint64_t chainId = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
|
||||
uint64_t chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
|
||||
// this prints raw data, so to have a more meaningful print, display
|
||||
// the buffer before the endianness swap
|
||||
PRINTF("ChainID: %.*H\n", sizeof(chainId), (workBuffer + offset));
|
||||
if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) {
|
||||
PRINTF("Chain ID token mismatch\n");
|
||||
THROW(0x6A80);
|
||||
PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset));
|
||||
if (!chain_is_ethereum_compatible(&chain_id)) {
|
||||
PRINTF("Unsupported chain ID!\n");
|
||||
THROW(APDU_RESPONSE_INVALID_DATA);
|
||||
}
|
||||
offset += CHAIN_ID_SIZE;
|
||||
|
||||
@@ -185,7 +191,7 @@ void handleSetPlugin(uint8_t p1,
|
||||
|
||||
PRINTF("KeyID: %d\n", keyId);
|
||||
switch (keyId) {
|
||||
#ifdef HAVE_NFT_TESTING_KEY
|
||||
#ifdef HAVE_NFT_STAGING_KEY
|
||||
case TEST_PLUGIN_KEY:
|
||||
#endif
|
||||
case PROD_PLUGIN_KEY:
|
||||
|
||||
@@ -108,7 +108,12 @@ static void handle_query_contract_id(void *parameters) {
|
||||
|
||||
switch (context->selectorIndex) {
|
||||
case SET_APPROVAL_FOR_ALL:
|
||||
#ifdef HAVE_NBGL
|
||||
strlcpy(msg->version, "manage", msg->versionLength);
|
||||
strlcat(msg->name, " allowance", msg->nameLength);
|
||||
#else
|
||||
strlcpy(msg->version, "Allowance", msg->versionLength);
|
||||
#endif
|
||||
break;
|
||||
case SAFE_TRANSFER:
|
||||
strlcpy(msg->version, "Transfer", msg->versionLength);
|
||||
|
||||
@@ -116,7 +116,12 @@ static void handle_query_contract_id(void *parameters) {
|
||||
switch (context->selectorIndex) {
|
||||
case SET_APPROVAL_FOR_ALL:
|
||||
case APPROVE:
|
||||
#ifdef HAVE_NBGL
|
||||
strlcpy(msg->version, "manage", msg->versionLength);
|
||||
strlcat(msg->name, " allowance", msg->nameLength);
|
||||
#else
|
||||
strlcpy(msg->version, "Allowance", msg->versionLength);
|
||||
#endif
|
||||
break;
|
||||
case SAFE_TRANSFER:
|
||||
case SAFE_TRANSFER_DATA:
|
||||
|
||||
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 372 B |
|
After Width: | Height: | Size: 537 B |
|
After Width: | Height: | Size: 592 B |
|
After Width: | Height: | Size: 823 B |
|
After Width: | Height: | Size: 494 B |
|
After Width: | Height: | Size: 436 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 372 B |
|
After Width: | Height: | Size: 537 B |
|
After Width: | Height: | Size: 538 B |
|
After Width: | Height: | Size: 804 B |
|
After Width: | Height: | Size: 494 B |
|
After Width: | Height: | Size: 411 B |
|
After Width: | Height: | Size: 459 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 372 B |
|
After Width: | Height: | Size: 537 B |
|
After Width: | Height: | Size: 538 B |
|
After Width: | Height: | Size: 846 B |
|
After Width: | Height: | Size: 494 B |
|
After Width: | Height: | Size: 383 B |
|
After Width: | Height: | Size: 436 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 328 B |
|
After Width: | Height: | Size: 537 B |
|
After Width: | Height: | Size: 592 B |
|
After Width: | Height: | Size: 823 B |
|
After Width: | Height: | Size: 264 B |
|
After Width: | Height: | Size: 322 B |
|
After Width: | Height: | Size: 436 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 365 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 328 B |
|
After Width: | Height: | Size: 537 B |
|
After Width: | Height: | Size: 592 B |
|
After Width: | Height: | Size: 823 B |
|
After Width: | Height: | Size: 264 B |
|
After Width: | Height: | Size: 322 B |
|
After Width: | Height: | Size: 436 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 328 B |
|
After Width: | Height: | Size: 537 B |
|
After Width: | Height: | Size: 538 B |
|
After Width: | Height: | Size: 804 B |
|
After Width: | Height: | Size: 264 B |
|
After Width: | Height: | Size: 322 B |
|
After Width: | Height: | Size: 411 B |
|
After Width: | Height: | Size: 459 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 328 B |
|
After Width: | Height: | Size: 537 B |
|
After Width: | Height: | Size: 538 B |
|
After Width: | Height: | Size: 846 B |
|
After Width: | Height: | Size: 264 B |
|
After Width: | Height: | Size: 322 B |
|
After Width: | Height: | Size: 383 B |
|
After Width: | Height: | Size: 436 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 345 B |
|
After Width: | Height: | Size: 602 B |
|
After Width: | Height: | Size: 592 B |
|
After Width: | Height: | Size: 823 B |
|
After Width: | Height: | Size: 436 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 345 B |
|
After Width: | Height: | Size: 602 B |
|
After Width: | Height: | Size: 533 B |
|
After Width: | Height: | Size: 804 B |