Merge Starkware branch
This commit is contained in:
35
Makefile
35
Makefile
@@ -25,11 +25,11 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS)
|
||||
# Allow the app to use path 45 for multi-sig (see BIP45).
|
||||
APP_LOAD_PARAMS += --path "45'"
|
||||
# Samsung temporary implementation for wallet ID on 0xda7aba5e/0xc1a551c5
|
||||
APP_LOAD_PARAMS += --path "1517992542'/1101353413'"
|
||||
#APP_LOAD_PARAMS += --path "1517992542'/1101353413'"
|
||||
|
||||
APPVERSION_M=1
|
||||
APPVERSION_N=2
|
||||
APPVERSION_P=13
|
||||
APPVERSION_N=3
|
||||
APPVERSION_P=7
|
||||
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
|
||||
APP_LOAD_FLAGS= --appFlags 0x240 --dep Ethereum:$(APPVERSION)
|
||||
|
||||
@@ -41,9 +41,25 @@ ifeq ($(CHAIN),ethereum)
|
||||
# Lock the application on its standard path for 1.5. Please complain if non compliant
|
||||
APP_LOAD_PARAMS += --path "44'/60'"
|
||||
DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAIN_KIND=CHAIN_KIND_ETHEREUM CHAIN_ID=0
|
||||
# Starkware integration
|
||||
APP_LOAD_PARAMS += --path "2645'/579218131'"
|
||||
DEFINES += HAVE_STARKWARE
|
||||
DEFINES += STARK_BIP32_PATH_0=0x80000A55 STARK_BIP32_PATH_1=0xA2862AD3
|
||||
APPNAME = "Ethereum"
|
||||
DEFINES_LIB=
|
||||
APP_LOAD_FLAGS=--appFlags 0xa40
|
||||
else ifeq ($(CHAIN),ropsten)
|
||||
APP_LOAD_PARAMS += --path "44'/60'"
|
||||
DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAIN_KIND=CHAIN_KIND_ETHEREUM CHAIN_ID=3
|
||||
# Starkware integration
|
||||
APP_LOAD_PARAMS += --path "2645'/579218131'"
|
||||
DEFINES += HAVE_STARKWARE
|
||||
# Keep for Starkware Ropsten tests
|
||||
DEFINES += HAVE_TOKENS_EXTRA_LIST
|
||||
DEFINES += STARK_BIP32_PATH_0=0x80000A55 STARK_BIP32_PATH_1=0xA2862AD3
|
||||
APPNAME = "Eth Ropsten"
|
||||
DEFINES_LIB=
|
||||
APP_LOAD_FLAGS=--appFlags 0xa40
|
||||
else ifeq ($(CHAIN),ellaism)
|
||||
APP_LOAD_PARAMS += --path "44'/163'"
|
||||
DEFINES += CHAINID_UPCASE=\"ELLA\" CHAINID_COINNAME=\"ELLA\" CHAIN_KIND=CHAIN_KIND_ELLAISM CHAIN_ID=64
|
||||
@@ -167,7 +183,7 @@ DEFINES += CHAINID_UPCASE=\"THUNDERCORE\" CHAINID_COINNAME=\"TT\" CHAIN_KIND=CHA
|
||||
APPNAME = "ThunderCore"
|
||||
else
|
||||
ifeq ($(filter clean,$(MAKECMDGOALS)),)
|
||||
$(error Unsupported CHAIN - use ethereum, ethereum_classic, expanse, poa, artis_sigma1, artis_tau1, rsk, rsk_testnet, ubiq, wanchain, kusd, musicoin, pirl, akroma, atheios, callisto, ethersocial, ellaism, ether1, ethergem, gochain, mix, reosc, hpb, tomochain, tobalaba, dexon, volta, ewc, webchain, thundercore)
|
||||
$(error Unsupported CHAIN - use ethereum, ropsten, ethereum_classic, expanse, poa, artis_sigma1, artis_tau1, rsk, rsk_testnet, ubiq, wanchain, kusd, musicoin, pirl, akroma, atheios, callisto, ethersocial, ellaism, ether1, ethergem, gochain, mix, reosc, hpb, tomochain, tobalaba, dexon, volta, ewc, webchain, thundercore)
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -196,7 +212,7 @@ all: default
|
||||
|
||||
DEFINES += OS_IO_SEPROXYHAL
|
||||
DEFINES += HAVE_BAGL HAVE_SPRINTF
|
||||
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
|
||||
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
|
||||
DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P)
|
||||
|
||||
# U2F
|
||||
@@ -225,12 +241,13 @@ DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX
|
||||
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX
|
||||
DEFINES += HAVE_UX_FLOW
|
||||
else
|
||||
DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128
|
||||
DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=72
|
||||
endif
|
||||
|
||||
# Enabling debug PRINTF
|
||||
DEBUG = 0
|
||||
DEBUG:=0
|
||||
ifneq ($(DEBUG),0)
|
||||
DEFINES += HAVE_STACK_OVERFLOW_CHECK
|
||||
ifeq ($(TARGET_NAME),TARGET_NANOX)
|
||||
DEFINES += HAVE_PRINTF PRINTF=mcu_usb_printf
|
||||
else
|
||||
@@ -278,7 +295,7 @@ LDLIBS += -lm -lgcc -lc
|
||||
include $(BOLOS_SDK)/Makefile.glyphs
|
||||
|
||||
### variables processed by the common makefile.rules of the SDK to grab source files and include dirs
|
||||
APP_SOURCE_PATH += src_common src
|
||||
APP_SOURCE_PATH += src_common src src_features
|
||||
SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f
|
||||
ifeq ($(TARGET_NAME),TARGET_NANOX)
|
||||
SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl
|
||||
@@ -310,4 +327,4 @@ include $(BOLOS_SDK)/Makefile.rules
|
||||
dep/%.d: %.c Makefile
|
||||
|
||||
listvariants:
|
||||
@echo VARIANTS CHAIN ethereum ethereum_classic expanse poa artis_sigma1 artis_tau1 rsk rsk_testnet ubiq wanchain kusd pirl akroma atheios callisto ethersocial ether1 gochain musicoin ethergem mix ellaism reosc hpb tomochain tobalaba dexon volta ewc webchain thundercore
|
||||
@echo VARIANTS CHAIN ethereum ropsten ethereum_classic expanse poa artis_sigma1 artis_tau1 rsk rsk_testnet ubiq wanchain kusd pirl akroma atheios callisto ethersocial ether1 gochain musicoin ethergem mix ellaism reosc hpb tomochain tobalaba dexon volta ewc webchain thundercore
|
||||
|
||||
BIN
blue_app_ropsten.gif
Normal file
BIN
blue_app_ropsten.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 405 B |
207
doc/eth_starkware_extensions.asc
Normal file
207
doc/eth_starkware_extensions.asc
Normal file
@@ -0,0 +1,207 @@
|
||||
Ethereum application : Starkware extensions
|
||||
============================================
|
||||
Ledger Firmware Team <hello@ledger.fr>
|
||||
Application version 1.3.0 - 15th of February 2020
|
||||
|
||||
## 1.3.0
|
||||
- Initial release
|
||||
|
||||
## About
|
||||
|
||||
This specification describes the APDU messages interface implementing the Starkware extensions for the Ethereum appilcation
|
||||
|
||||
## Modified general purpose APDUs
|
||||
|
||||
### GET APP CONFIGURATION
|
||||
|
||||
#### Description
|
||||
|
||||
This command returns specific application configuration
|
||||
|
||||
It is modified to notify Stark extensions support on flag 0x04
|
||||
|
||||
#### Coding
|
||||
|
||||
'Command'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
|
||||
| E0 | 06 | 00 | 00 | 00 | 04
|
||||
|==============================================================================================================================
|
||||
|
||||
'Input data'
|
||||
|
||||
None
|
||||
|
||||
'Output data'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *Description* | *Length*
|
||||
| Flags
|
||||
0x01 : arbitrary data signature enabled by user
|
||||
|
||||
0x02 : ERC 20 Token information needs to be provided externally
|
||||
|
||||
0x04 : Stark extensions are supported
|
||||
| 01
|
||||
| Application major version | 01
|
||||
| Application minor version | 01
|
||||
| Application patch version | 01
|
||||
|==============================================================================================================================
|
||||
|
||||
|
||||
## Additional APDUs
|
||||
|
||||
Additional APDUs use the APDU CLA F0
|
||||
|
||||
### GET STARK PUBLIC KEY
|
||||
|
||||
#### Description
|
||||
|
||||
This command returns the public Stark key (X and Y coordinates) for the given BIP 32 path.
|
||||
|
||||
The key can be optionally checked on the device before being returned - in that case, only the X coordinate is displayed, as this is what is used in the contract
|
||||
|
||||
#### Coding
|
||||
|
||||
'Command'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
|
||||
| F0 | 02 | 00 : return address
|
||||
|
||||
01 : display address and confirm before returning
|
||||
| 00 | variable | variable
|
||||
|==============================================================================================================================
|
||||
|
||||
'Input data'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *Description* | *Length*
|
||||
| Number of BIP 32 derivations to perform (max 10) | 1
|
||||
| First derivation index (big endian) | 4
|
||||
| ... | 4
|
||||
| Last derivation index (big endian) | 4
|
||||
|==============================================================================================================================
|
||||
|
||||
'Output data'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *Description* | *Length*
|
||||
| Stark key | 65
|
||||
|==============================================================================================================================
|
||||
|
||||
### SIGN STARK MESSAGE
|
||||
|
||||
#### Description
|
||||
|
||||
This command signs an order or a transfer on the Starkware curve.
|
||||
|
||||
The contract addressed associated to the token shall have be provisioned previously with the PROVIDE ERC 20 TOKEN INFORMATION command or this command will fail.
|
||||
|
||||
#### Coding
|
||||
|
||||
'Command'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
|
||||
| F0 | 04 |
|
||||
01 : sign a Stark Order
|
||||
|
||||
02 : sign a Stark Transfer
|
||||
|
||||
| 00 | variable | variable
|
||||
|==============================================================================================================================
|
||||
|
||||
'Input data for a Stark Order'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *Description* | *Length*
|
||||
| Number of BIP 32 derivations to perform (max 10) | 1
|
||||
| First derivation index (big endian) | 4
|
||||
| ... | 4
|
||||
| Last derivation index (big endian) | 4
|
||||
| Contract address of the token to be sold (or 00..00 for ETH) | 20
|
||||
| Quantization of the token to be sold (big endian) | 32
|
||||
| Contract address of the token to be bought (or 00..00 for ETH) | 20
|
||||
| Quantization of the token to be bought (big endian) | 32
|
||||
| ID of the source vault (big endian encoded) | 4
|
||||
| ID of the destination vault (big endian encoded) | 4
|
||||
| Amount to be sold (big endian encoded) | 8
|
||||
| Amount to buy (big endian encoded) | 8
|
||||
| Transaction nonce (big endian encoded) | 4
|
||||
| Transaction timestamp (big endian encoded) | 4
|
||||
|==============================================================================================================================
|
||||
|
||||
'Input data for a Stark Transfer'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *Description* | *Length*
|
||||
| Number of BIP 32 derivations to perform (max 10) | 1
|
||||
| First derivation index (big endian) | 4
|
||||
| ... | 4
|
||||
| Last derivation index (big endian) | 4
|
||||
| Contract address of the token to be transferred (or 00..00 for ETH) | 20
|
||||
| Quantization of the token to be transferred (big endian) | 32
|
||||
| Token target public key | 32
|
||||
| ID of the source vault (big endian encoded) | 4
|
||||
| ID of the destination vault (big endian encoded) | 4
|
||||
| Amount to be transferred (big endian encoded) | 8
|
||||
| Transaction nonce (big endian encoded) | 4
|
||||
| Transaction timestamp (big endian encoded) | 4
|
||||
|==============================================================================================================================
|
||||
|
||||
|
||||
'Output data'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *Description* | *Length*
|
||||
| RFU (00) | 1
|
||||
| r | 32
|
||||
| s | 32
|
||||
|==============================================================================================================================
|
||||
|
||||
|
||||
### PROVIDES QUANTUM
|
||||
|
||||
#### Description
|
||||
|
||||
This command provides quantization data used to compute a tokenId and provide additional information to the user before signing a transaction performing a deposit or withdrawal call on a Stark powered smart contract.
|
||||
|
||||
It shall be called following a PROVIDE ERC 20 TOKEN INFORMATION command called for the associated contract
|
||||
|
||||
#### Coding
|
||||
|
||||
'Command'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
|
||||
| F0 | 08 |
|
||||
00
|
||||
|
||||
| 00 | variable | variable
|
||||
|==============================================================================================================================
|
||||
|
||||
'Input data'
|
||||
|
||||
[width="80%"]
|
||||
|==============================================================================================================================
|
||||
| *Description* | *Length*
|
||||
| Contract address used in the next transaction | 20
|
||||
| Quantization to be used in the next transaction | 32
|
||||
|==============================================================================================================================
|
||||
|
||||
|
||||
'Output data'
|
||||
|
||||
None
|
||||
BIN
glyphs/blue_badge_ropsten.gif
Normal file
BIN
glyphs/blue_badge_ropsten.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 347 B |
BIN
glyphs/nanos_badge_ropsten.gif
Normal file
BIN
glyphs/nanos_badge_ropsten.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
nanos_app_ropsten.gif
Normal file
BIN
nanos_app_ropsten.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
nanox_app_ropsten.gif
Normal file
BIN
nanox_app_ropsten.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ropsten.png
Executable file
BIN
ropsten.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
58
src/apdu_constants.h
Normal file
58
src/apdu_constants.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
#define APP_FLAG_DATA_ALLOWED 0x01
|
||||
#define APP_FLAG_EXTERNAL_TOKEN_NEEDED 0x02
|
||||
#define APP_FLAG_STARKWARE 0x04
|
||||
|
||||
#define CLA 0xE0
|
||||
#define INS_GET_PUBLIC_KEY 0x02
|
||||
#define INS_SIGN 0x04
|
||||
#define INS_GET_APP_CONFIGURATION 0x06
|
||||
#define INS_SIGN_PERSONAL_MESSAGE 0x08
|
||||
#define INS_PROVIDE_ERC20_TOKEN_INFORMATION 0x0A
|
||||
#define P1_CONFIRM 0x01
|
||||
#define P1_NON_CONFIRM 0x00
|
||||
#define P2_NO_CHAINCODE 0x00
|
||||
#define P2_CHAINCODE 0x01
|
||||
#define P1_FIRST 0x00
|
||||
#define P1_MORE 0x80
|
||||
|
||||
#define COMMON_CLA 0xB0
|
||||
#define COMMON_INS_GET_WALLET_ID 0x04
|
||||
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#define STARKWARE_CLA 0xF0
|
||||
#define STARKWARE_INS_GET_PUBLIC_KEY 0x02
|
||||
#define STARKWARE_INS_SIGN_MESSAGE 0x04
|
||||
#define STARKWARE_INS_PROVIDE_QUANTUM 0x08
|
||||
|
||||
#define P1_STARK_ORDER 0x01
|
||||
#define P1_STARK_TRANSFER 0x02
|
||||
|
||||
#define STARK_ORDER_TYPE 0
|
||||
#define STARK_TRANSFER_TYPE 1
|
||||
|
||||
#endif
|
||||
|
||||
#define OFFSET_CLA 0
|
||||
#define OFFSET_INS 1
|
||||
#define OFFSET_P1 2
|
||||
#define OFFSET_P2 3
|
||||
#define OFFSET_LC 4
|
||||
#define OFFSET_CDATA 5
|
||||
|
||||
void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx);
|
||||
void handleProvideErc20TokenInformation(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx);
|
||||
void handleSign(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx);
|
||||
void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx);
|
||||
void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx);
|
||||
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
void handleStarkwareGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx);
|
||||
void handleStarkwareSignMessage(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx);
|
||||
void handleStarkwareProvideQuantum(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx);
|
||||
|
||||
#endif
|
||||
|
||||
2305
src/main.c
2305
src/main.c
File diff suppressed because it is too large
Load Diff
43
src/poorstream.c
Normal file
43
src/poorstream.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "poorstream.h"
|
||||
|
||||
void poorstream_init(poorstream_t *stream, uint8_t *buffer) {
|
||||
os_memset((void*)stream, 0, sizeof(poorstream_t));
|
||||
stream->pointer = buffer;
|
||||
}
|
||||
|
||||
void poorstream_flush(poorstream_t *stream) {
|
||||
//PRINTF("Flush\n");
|
||||
*(stream->pointer + 0) = (stream->accumulator >> 56);
|
||||
*(stream->pointer + 1) = (stream->accumulator >> 48);
|
||||
*(stream->pointer + 2) = (stream->accumulator >> 40);
|
||||
*(stream->pointer + 3) = (stream->accumulator >> 32);
|
||||
*(stream->pointer + 4) = (stream->accumulator >> 24);
|
||||
*(stream->pointer + 5) = (stream->accumulator >> 16);
|
||||
*(stream->pointer + 6) = (stream->accumulator >> 8);
|
||||
*(stream->pointer + 7) = (stream->accumulator >> 0);
|
||||
}
|
||||
|
||||
void poorstream_write_bits(poorstream_t *stream, uint64_t bits, uint32_t num_bits) {
|
||||
stream->offset += num_bits;
|
||||
if (stream->offset < 64) {
|
||||
stream->accumulator |= (bits << (64 - stream->offset));
|
||||
//PRINTF("ACC |= << %d\n", (64 - stream->offset));
|
||||
} else {
|
||||
stream->offset -= 64;
|
||||
stream->mask = ((1 << (num_bits - stream->offset)) - 1);
|
||||
//PRINTF("Mask %lx\n", stream->mask);
|
||||
//PRINTF("Offset %d\n", stream->offset);
|
||||
stream->accumulator |= ((bits >> stream->offset) & stream->mask);
|
||||
poorstream_flush(stream);
|
||||
stream->accumulator = 0;
|
||||
stream->pointer += 8;
|
||||
if (stream->offset) {
|
||||
stream->mask = ((1 << stream->offset) - 1);
|
||||
stream->accumulator |= ((bits & stream->mask) << (64 - stream->offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
21
src/poorstream.h
Normal file
21
src/poorstream.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef __POORSTREAM_H__
|
||||
#define __POORSTREAM_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "os.h"
|
||||
|
||||
typedef struct poorstream_t {
|
||||
uint8_t *pointer;
|
||||
uint32_t offset;
|
||||
uint64_t mask;
|
||||
uint64_t accumulator;
|
||||
} poorstream_t;
|
||||
|
||||
void poorstream_init(poorstream_t *stream, uint8_t *buffer);
|
||||
void poorstream_flush(poorstream_t *stream);
|
||||
void poorstream_write_bits(poorstream_t *stream, uint64_t bits, uint32_t num_bits);
|
||||
|
||||
#endif
|
||||
169
src/shared_context.h
Normal file
169
src/shared_context.h
Normal file
@@ -0,0 +1,169 @@
|
||||
#ifndef __SHARED_CONTEXT_H__
|
||||
|
||||
#define __SHARED_CONTEXT_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "cx.h"
|
||||
#include "os_io_seproxyhal.h"
|
||||
#include "ethUstream.h"
|
||||
#include "ethUtils.h"
|
||||
#include "uint256.h"
|
||||
#include "tokens.h"
|
||||
#include "chainConfig.h"
|
||||
|
||||
#define MAX_BIP32_PATH 10
|
||||
|
||||
#define MAX_TOKEN 2
|
||||
|
||||
#define WEI_TO_ETHER 18
|
||||
|
||||
#define N_storage (*(volatile internalStorage_t*) PIC(&N_storage_real))
|
||||
|
||||
typedef struct internalStorage_t {
|
||||
unsigned char dataAllowed;
|
||||
unsigned char contractDetails;
|
||||
uint8_t initialized;
|
||||
} internalStorage_t;
|
||||
|
||||
typedef struct tokenContext_t {
|
||||
#ifdef HAVE_STARKWARE
|
||||
uint8_t data[4 + 32 + 32 + 32 + 32];
|
||||
#else
|
||||
uint8_t data[4 + 32 + 32];
|
||||
#endif
|
||||
uint32_t dataFieldPos;
|
||||
#ifdef HAVE_STARKWARE
|
||||
uint8_t quantum[32];
|
||||
uint8_t quantumIndex;
|
||||
#endif
|
||||
} tokenContext_t;
|
||||
|
||||
typedef struct rawDataContext_t {
|
||||
uint8_t data[32];
|
||||
uint8_t fieldIndex;
|
||||
uint8_t fieldOffset;
|
||||
} rawDataContext_t;
|
||||
|
||||
typedef struct publicKeyContext_t {
|
||||
cx_ecfp_public_key_t publicKey;
|
||||
uint8_t address[41];
|
||||
uint8_t chainCode[32];
|
||||
bool getChaincode;
|
||||
} publicKeyContext_t;
|
||||
|
||||
typedef struct transactionContext_t {
|
||||
uint8_t pathLength;
|
||||
uint32_t bip32Path[MAX_BIP32_PATH];
|
||||
uint8_t hash[32];
|
||||
tokenDefinition_t tokens[MAX_TOKEN];
|
||||
uint8_t tokenSet[MAX_TOKEN];
|
||||
uint8_t currentTokenIndex;
|
||||
} transactionContext_t;
|
||||
|
||||
typedef struct messageSigningContext_t {
|
||||
uint8_t pathLength;
|
||||
uint32_t bip32Path[MAX_BIP32_PATH];
|
||||
uint8_t hash[32];
|
||||
uint32_t remainingLength;
|
||||
} messageSigningContext_t;
|
||||
|
||||
typedef union {
|
||||
publicKeyContext_t publicKeyContext;
|
||||
transactionContext_t transactionContext;
|
||||
messageSigningContext_t messageSigningContext;
|
||||
} tmpCtx_t;
|
||||
|
||||
typedef union {
|
||||
txContent_t txContent;
|
||||
cx_sha256_t sha2;
|
||||
char tmp[100];
|
||||
} tmpContent_t;
|
||||
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
typedef struct starkContext_t {
|
||||
uint8_t w1[32];
|
||||
uint8_t w2[32];
|
||||
uint8_t w3[32];
|
||||
} starkContext_t;
|
||||
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
tokenContext_t tokenContext;
|
||||
rawDataContext_t rawDataContext;
|
||||
#ifdef HAVE_STARKWARE
|
||||
starkContext_t starkContext;
|
||||
#endif
|
||||
} dataContext_t;
|
||||
|
||||
typedef enum {
|
||||
APP_STATE_IDLE,
|
||||
APP_STATE_SIGNING_TX,
|
||||
APP_STATE_SIGNING_MESSAGE
|
||||
} app_state_t;
|
||||
|
||||
typedef enum {
|
||||
CONTRACT_NONE,
|
||||
CONTRACT_ERC20,
|
||||
CONTRACT_ALLOWANCE,
|
||||
#ifdef HAVE_STARKWARE
|
||||
CONTRACT_STARKWARE_REGISTER,
|
||||
CONTRACT_STARKWARE_DEPOSIT_TOKEN,
|
||||
CONTRACT_STARKWARE_DEPOSIT_ETH,
|
||||
CONTRACT_STARKWARE_WITHDRAW,
|
||||
CONTRACT_STARKWARE_DEPOSIT_CANCEL,
|
||||
CONTRACT_STARKWARE_DEPOSIT_RECLAIM,
|
||||
CONTRACT_STARKWARE_FULL_WITHDRAWAL,
|
||||
CONTRACT_STARKWARE_FREEZE,
|
||||
CONTRACT_STARKWARE_ESCAPE,
|
||||
CONTRACT_STARKWARE_VERIFY_ESCAPE
|
||||
#endif
|
||||
} contract_call_t;
|
||||
|
||||
typedef struct strData_t {
|
||||
char fullAddress[43];
|
||||
char fullAmount[50];
|
||||
char maxFee[50];
|
||||
} strData_t;
|
||||
|
||||
typedef struct strDataTmp_t {
|
||||
char tmp[100];
|
||||
char tmp2[40];
|
||||
} strDataTmp_t;
|
||||
|
||||
typedef union {
|
||||
strData_t common;
|
||||
strDataTmp_t tmp;
|
||||
} strings_t;
|
||||
|
||||
extern chain_config_t *chainConfig;
|
||||
|
||||
extern tmpCtx_t tmpCtx;
|
||||
extern txContext_t txContext;
|
||||
extern tmpContent_t tmpContent;
|
||||
extern dataContext_t dataContext;
|
||||
extern strings_t strings;
|
||||
extern cx_sha3_t sha3;
|
||||
extern const internalStorage_t N_storage_real;
|
||||
|
||||
#ifdef TARGET_BLUE
|
||||
extern bagl_element_t tmp_element;
|
||||
extern char addressSummary[32];
|
||||
#endif
|
||||
|
||||
extern bool dataPresent;
|
||||
extern uint8_t appState;
|
||||
extern contract_call_t contractProvisioned;
|
||||
#ifdef HAVE_STARKWARE
|
||||
extern bool quantumSet;
|
||||
#endif
|
||||
|
||||
void reset_app_context(void);
|
||||
|
||||
#endif // __SHARED_CONTEXT_H__
|
||||
|
||||
85
src/stark_crypto.c
Normal file
85
src/stark_crypto.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "stark_utils.h"
|
||||
#include "ui_callbacks.h"
|
||||
#include "utils.h"
|
||||
|
||||
static unsigned char const C_cx_Stark256_n[] = {
|
||||
//n: 0x0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xb7, 0x81, 0x12, 0x6d, 0xca, 0xe7, 0xb2, 0x32, 0x1e, 0x66, 0xa2, 0x41, 0xad, 0xc6, 0x4d, 0x2f};
|
||||
|
||||
// C_cx_secp256k1_n - (C_cx_secp256k1_n % C_cx_Stark256_n)
|
||||
static unsigned char const STARK_DERIVE_BIAS[] = {
|
||||
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7,
|
||||
0x38, 0xa1, 0x3b, 0x4b, 0x92, 0x0e, 0x94, 0x11, 0xae, 0x6d, 0xa5, 0xf4, 0x0b, 0x03, 0x58, 0xb1
|
||||
};
|
||||
|
||||
void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_t *privateKeyData) {
|
||||
#if 0
|
||||
// Sanity check
|
||||
if (bip32Path[0] != STARK_BIP32_PATH_0) {
|
||||
PRINTF("Invalid Stark derivation path %d\n", bip32Path[0]);
|
||||
THROW(0x6a80);
|
||||
}
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1, bip32Path, bip32PathLength, privateKeyData, NULL);
|
||||
PRINTF("Private key before processing %.*H\n", 32, privateKeyData);
|
||||
// TODO - support additional schemes
|
||||
cx_math_modm(privateKeyData, 32, C_cx_Stark256_n, 32);
|
||||
PRINTF("Private key after processing %.*H\n", 32, privateKeyData);
|
||||
#else
|
||||
uint8_t tmp[33];
|
||||
uint8_t index = 0;
|
||||
// Sanity check
|
||||
if ((bip32PathLength < 2) || (bip32Path[0] != STARK_BIP32_PATH_0) || (bip32Path[1] != STARK_BIP32_PATH_1)) {
|
||||
PRINTF("Invalid Stark derivation path %d %d\n", bip32Path[0], bip32Path[1]);
|
||||
THROW(0x6a80);
|
||||
}
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1, bip32Path, bip32PathLength, tmp, NULL);
|
||||
PRINTF("Private key before processing %.*H\n", 32, tmp);
|
||||
for(;;) {
|
||||
tmp[32] = index;
|
||||
cx_hash_sha256(tmp, 33, privateKeyData, 32);
|
||||
if (cx_math_cmp(privateKeyData, STARK_DERIVE_BIAS, 32) < 0) {
|
||||
cx_math_modm(privateKeyData, 32, C_cx_Stark256_n, 32);
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void stark_get_amount_string(uint8_t *contractAddress, uint8_t *quantum256, uint8_t *amount64, char *tmp100, char *target100) {
|
||||
uint256_t amountPre, quantum, amount;
|
||||
uint8_t decimals;
|
||||
char *ticker = (char*)PIC(chainConfig->coinName);
|
||||
|
||||
PRINTF("stark_get_amount_string %.*H\n", 20, contractAddress);
|
||||
|
||||
if (allzeroes(contractAddress, 20)) {
|
||||
decimals = WEI_TO_ETHER;
|
||||
PRINTF("stark_get_amount_string - ETH\n");
|
||||
}
|
||||
else {
|
||||
tokenDefinition_t *token = getKnownToken(contractAddress);
|
||||
if (token == NULL) { // caught earlier
|
||||
THROW(0x6A80);
|
||||
}
|
||||
decimals = token->decimals;
|
||||
ticker = (char*)token->ticker;
|
||||
PRINTF("stark_get_amount_string - decimals %d ticker %s\n", decimals, ticker);
|
||||
}
|
||||
convertUint256BE(amount64, 8, &amountPre);
|
||||
readu256BE(quantum256, &quantum);
|
||||
mul256(&amountPre, &quantum, &amount);
|
||||
tostring256(&amount, 10, tmp100, 100);
|
||||
PRINTF("stark_get_amount_string - mul256 %s\n", tmp100);
|
||||
strcpy(target100, ticker);
|
||||
adjustDecimals(tmp100, strlen(tmp100), target100 + strlen(ticker), 100, decimals);
|
||||
PRINTF("get_amount_string %s\n", target100);
|
||||
}
|
||||
|
||||
|
||||
#endif // HAVE_STARK
|
||||
25
src/stark_crypto.h
Normal file
25
src/stark_crypto.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef __STARK_CRYPTO_H__
|
||||
#define __STARK_CRYPTO_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "cx.h"
|
||||
|
||||
|
||||
/* EC points */
|
||||
#define FIELD_ELEMENT_SIZE (32)
|
||||
#define EC_POINT_SIZE (2 * FIELD_ELEMENT_SIZE + 1)
|
||||
typedef unsigned char FieldElement[FIELD_ELEMENT_SIZE];
|
||||
typedef unsigned char ECPoint[EC_POINT_SIZE];
|
||||
|
||||
void pedersen(FieldElement res, /* out */
|
||||
FieldElement a, FieldElement b);
|
||||
|
||||
int stark_sign(uint8_t *signautre, /* out */
|
||||
uint8_t *privateKeyData, FieldElement token1,
|
||||
FieldElement token2, FieldElement msg);
|
||||
|
||||
#endif
|
||||
141
src/stark_utils.c
Normal file
141
src/stark_utils.c
Normal file
@@ -0,0 +1,141 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "stark_crypto.h"
|
||||
#include "ethUtils.h"
|
||||
|
||||
#include "os_io_seproxyhal.h"
|
||||
|
||||
#define SIGNATURE_MAX_LEN (72)
|
||||
|
||||
static const ECPoint PEDERSEN_SHIFT[] = { {
|
||||
0x04,
|
||||
|
||||
0x04, 0x9e, 0xe3, 0xeb, 0xa8, 0xc1, 0x60, 0x07, 0x00, 0xee, 0x1b,
|
||||
0x87, 0xeb, 0x59, 0x9f, 0x16, 0x71, 0x6b, 0x0b, 0x10, 0x22, 0x94,
|
||||
0x77, 0x33, 0x55, 0x1f, 0xde, 0x40, 0x50, 0xca, 0x68, 0x04,
|
||||
|
||||
0x03, 0xca, 0x0c, 0xfe, 0x4b, 0x3b, 0xc6, 0xdd, 0xf3, 0x46, 0xd4,
|
||||
0x9d, 0x06, 0xea, 0x0e, 0xd3, 0x4e, 0x62, 0x10, 0x62, 0xc0, 0xe0,
|
||||
0x56, 0xc1, 0xd0, 0x40, 0x5d, 0x26, 0x6e, 0x10, 0x26, 0x8a,
|
||||
}};
|
||||
|
||||
static const ECPoint PEDERSEN_POINTS[4] = {
|
||||
{
|
||||
0x04,
|
||||
|
||||
0x02, 0x34, 0x28, 0x7d, 0xcb, 0xaf, 0xfe, 0x7f, 0x96, 0x9c, 0x74,
|
||||
0x86, 0x55, 0xfc, 0xa9, 0xe5, 0x8f, 0xa8, 0x12, 0x0b, 0x6d, 0x56,
|
||||
0xeb, 0x0c, 0x10, 0x80, 0xd1, 0x79, 0x57, 0xeb, 0xe4, 0x7b,
|
||||
|
||||
0x03, 0xb0, 0x56, 0xf1, 0x00, 0xf9, 0x6f, 0xb2, 0x1e, 0x88, 0x95,
|
||||
0x27, 0xd4, 0x1f, 0x4e, 0x39, 0x94, 0x01, 0x35, 0xdd, 0x7a, 0x6c,
|
||||
0x94, 0xcc, 0x6e, 0xd0, 0x26, 0x8e, 0xe8, 0x9e, 0x56, 0x15,
|
||||
},
|
||||
{
|
||||
0x04,
|
||||
|
||||
0x04, 0xfa, 0x56, 0xf3, 0x76, 0xc8, 0x3d, 0xb3, 0x3f, 0x9d, 0xab,
|
||||
0x26, 0x56, 0x55, 0x8f, 0x33, 0x99, 0x09, 0x9e, 0xc1, 0xde, 0x5e,
|
||||
0x30, 0x18, 0xb7, 0xa6, 0x93, 0x2d, 0xba, 0x8a, 0xa3, 0x78,
|
||||
|
||||
0x03, 0xfa, 0x09, 0x84, 0xc9, 0x31, 0xc9, 0xe3, 0x81, 0x13, 0xe0,
|
||||
0xc0, 0xe4, 0x7e, 0x44, 0x01, 0x56, 0x27, 0x61, 0xf9, 0x2a, 0x7a,
|
||||
0x23, 0xb4, 0x51, 0x68, 0xf4, 0xe8, 0x0f, 0xf5, 0xb5, 0x4d,
|
||||
},
|
||||
{
|
||||
0x04,
|
||||
|
||||
0x04, 0xba, 0x4c, 0xc1, 0x66, 0xbe, 0x8d, 0xec, 0x76, 0x49, 0x10,
|
||||
0xf7, 0x5b, 0x45, 0xf7, 0x4b, 0x40, 0xc6, 0x90, 0xc7, 0x47, 0x09,
|
||||
0xe9, 0x0f, 0x3a, 0xa3, 0x72, 0xf0, 0xbd, 0x2d, 0x69, 0x97,
|
||||
|
||||
0x00, 0x40, 0x30, 0x1c, 0xf5, 0xc1, 0x75, 0x1f, 0x4b, 0x97, 0x1e,
|
||||
0x46, 0xc4, 0xed, 0xe8, 0x5f, 0xca, 0xc5, 0xc5, 0x9a, 0x5c, 0xe5,
|
||||
0xae, 0x7c, 0x48, 0x15, 0x1f, 0x27, 0xb2, 0x4b, 0x21, 0x9c,
|
||||
},
|
||||
{
|
||||
0x04,
|
||||
|
||||
0x05, 0x43, 0x02, 0xdc, 0xb0, 0xe6, 0xcc, 0x1c, 0x6e, 0x44, 0xcc,
|
||||
0xa8, 0xf6, 0x1a, 0x63, 0xbb, 0x2c, 0xa6, 0x50, 0x48, 0xd5, 0x3f,
|
||||
0xb3, 0x25, 0xd3, 0x6f, 0xf1, 0x2c, 0x49, 0xa5, 0x82, 0x02,
|
||||
|
||||
0x01, 0xb7, 0x7b, 0x3e, 0x37, 0xd1, 0x35, 0x04, 0xb3, 0x48, 0x04,
|
||||
0x62, 0x68, 0xd8, 0xae, 0x25, 0xce, 0x98, 0xad, 0x78, 0x3c, 0x25,
|
||||
0x56, 0x1a, 0x87, 0x9d, 0xcc, 0x77, 0xe9, 0x9c, 0x24, 0x26,
|
||||
}};
|
||||
|
||||
void accum_ec_mul(ECPoint *hash, uint8_t *buf, int len, int pedersen_idx) {
|
||||
ECPoint tmp;
|
||||
if (!allzeroes(buf, len)) {
|
||||
memcpy(tmp, PEDERSEN_POINTS[pedersen_idx], sizeof(ECPoint));
|
||||
io_seproxyhal_io_heartbeat();
|
||||
cx_ecfp_scalar_mult(CX_CURVE_Stark256, tmp, sizeof(ECPoint), buf, len);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
cx_ecfp_add_point(CX_CURVE_Stark256, *hash, *hash, tmp, sizeof(ECPoint));
|
||||
}
|
||||
}
|
||||
|
||||
void pedersen(FieldElement res, /* out */
|
||||
FieldElement a, FieldElement b) {
|
||||
ECPoint hash;
|
||||
|
||||
memcpy(hash, PEDERSEN_SHIFT, sizeof(hash));
|
||||
|
||||
accum_ec_mul(&hash, a, 1, 1);
|
||||
accum_ec_mul(&hash, a+1, FIELD_ELEMENT_SIZE-1, 0);
|
||||
accum_ec_mul(&hash, b, 1, 3);
|
||||
accum_ec_mul(&hash, b+1, FIELD_ELEMENT_SIZE-1, 2);
|
||||
|
||||
memcpy(res, hash + 1, FIELD_ELEMENT_SIZE);
|
||||
}
|
||||
|
||||
int stark_sign(uint8_t *signature, /* out */
|
||||
uint8_t *privateKeyData,
|
||||
FieldElement token1,
|
||||
FieldElement token2,
|
||||
FieldElement msg) {
|
||||
unsigned int info = 0;
|
||||
FieldElement hash;
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
PRINTF("Stark sign msg w1 %.*H\n", 32, token1);
|
||||
PRINTF("Stark sign msg w2 %.*H\n", 32, token2);
|
||||
PRINTF("Stark sign w3 %.*H\n", 32, msg);
|
||||
pedersen(hash, token1, token2);
|
||||
PRINTF("Pedersen hash 1 %.*H\n", 32, hash);
|
||||
pedersen(hash, hash, msg);
|
||||
PRINTF("Pedersen hash 2 %.*H\n", 32, hash);
|
||||
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
int signatureLength = cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
|
||||
hash, sizeof(hash), signature, SIGNATURE_MAX_LEN, &info);
|
||||
PRINTF("Stark signature %.*H\n", signatureLength, signature);
|
||||
return signatureLength;
|
||||
}
|
||||
|
||||
// ERC20Token(address)
|
||||
static const uint8_t ERC20_SELECTOR[] = { 0xf4, 0x72, 0x61, 0xb0 };
|
||||
// ETH()
|
||||
static const uint8_t ETH_SELECTOR[] = { 0x83, 0x22, 0xff, 0xf2 };
|
||||
|
||||
void compute_token_id(cx_sha3_t *sha3, uint8_t *contractAddress, uint8_t *quantum, uint8_t *output) {
|
||||
uint8_t tmp[36];
|
||||
cx_keccak_init(sha3, 256);
|
||||
if ((contractAddress != NULL) && (!allzeroes(contractAddress, 20))) {
|
||||
PRINTF("compute_token_id for %.*H\n", 20, contractAddress);
|
||||
os_memset(tmp, 0, sizeof(tmp));
|
||||
os_memmove(tmp, ERC20_SELECTOR, 4);
|
||||
os_memmove(tmp + 16, contractAddress, 20);
|
||||
cx_hash((cx_hash_t*)sha3, 0, tmp, sizeof(tmp), NULL, 0);
|
||||
}
|
||||
else {
|
||||
PRINTF("compute_token_id for ETH\n");
|
||||
cx_hash((cx_hash_t*)sha3, 0, ETH_SELECTOR, sizeof(ETH_SELECTOR), NULL, 0);
|
||||
}
|
||||
PRINTF("compute_token_id quantum %.*H\n", 32, quantum);
|
||||
cx_hash((cx_hash_t*)sha3, CX_LAST, quantum, 32, output, 32);
|
||||
output[0] &= 0x03;
|
||||
PRINTF("compute_token_id computed token %.*H\n", 32, output);
|
||||
}
|
||||
|
||||
#endif // HAVE_STARK
|
||||
25
src/stark_utils.h
Normal file
25
src/stark_utils.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef __STARK_UTILS_H__
|
||||
#define __STARK_UTILS_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "cx.h"
|
||||
#include "stark_crypto.h"
|
||||
|
||||
void compute_token_id(cx_sha3_t *sha3, uint8_t *contractAddress, uint8_t *quantum, uint8_t *output);
|
||||
|
||||
void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_t *privateKeyData);
|
||||
|
||||
void stark_get_amount_string(uint8_t *contractAddress, uint8_t *quantum256, uint8_t *amount64, char *tmp100, char *target100);
|
||||
|
||||
int stark_sign(uint8_t *signature, /* out */
|
||||
uint8_t *privateKeyData,
|
||||
FieldElement token1,
|
||||
FieldElement token2,
|
||||
FieldElement msg);
|
||||
|
||||
#endif
|
||||
|
||||
15
src/tokens.c
15
src/tokens.c
@@ -15,6 +15,21 @@
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#ifdef HAVE_TOKENS_EXTRA_LIST
|
||||
|
||||
#include "tokens.h"
|
||||
|
||||
const tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA] = {
|
||||
|
||||
{{0x4c,0x5f,0x66,0x59,0x61,0x97,0xa8,0x6f,0xb3,0x0a,0x24,0x35,0xe2,0xef,0x4d,0xdc,0xb3,0x93,0x42,0xc9}, "tUSDT ", 6},
|
||||
{{0xcd,0x07,0x7a,0xbe,0xdd,0x83,0x1a,0x34,0x43,0xff,0xbe,0x24,0xfb,0x76,0x66,0x1b,0xbb,0x17,0xeb,0x69}, "tZRX ", 18},
|
||||
{{0x40,0xd8,0x97,0x85,0x00,0xbf,0x68,0x32,0x4a,0x51,0x53,0x3c,0xd6,0xa2,0x1e,0x3e,0x59,0xbe,0x32,0x4a}, "tBTC ", 18},
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOKENS_LIST
|
||||
|
||||
#include "tokens.h"
|
||||
|
||||
13
src/tokens.h
13
src/tokens.h
@@ -21,11 +21,22 @@
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct tokenDefinition_t {
|
||||
#ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR
|
||||
uint8_t contractName[20];
|
||||
#endif
|
||||
uint8_t address[20];
|
||||
uint8_t ticker[10];
|
||||
uint8_t ticker[12]; // 10 characters + ' \0'
|
||||
uint8_t decimals;
|
||||
} tokenDefinition_t;
|
||||
|
||||
#ifdef HAVE_TOKENS_EXTRA_LIST
|
||||
|
||||
#define NUM_TOKENS_EXTRA 3
|
||||
|
||||
extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOKENS_LIST
|
||||
|
||||
#define NUM_TOKENS_AKROMA 0
|
||||
|
||||
564
src/ui_blue.c
Normal file
564
src/ui_blue.c
Normal file
@@ -0,0 +1,564 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
#ifdef TARGET_BLUE
|
||||
|
||||
#include "ui_blue.h"
|
||||
#include "ui_callbacks.h"
|
||||
#include "glyphs.h"
|
||||
|
||||
#define BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH 10
|
||||
#define BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH 8
|
||||
#define MAX_CHAR_PER_LINE 25
|
||||
|
||||
void io_seproxyhal_io_heartbeat(void) {
|
||||
}
|
||||
|
||||
bagl_element_t tmp_element;
|
||||
|
||||
const bagl_element_t* ui_menu_item_out_over(const bagl_element_t* e) {
|
||||
// the selection rectangle is after the none|touchable
|
||||
e = (const bagl_element_t*)(((unsigned int)e)+sizeof(bagl_element_t));
|
||||
return e;
|
||||
}
|
||||
|
||||
unsigned int map_color(unsigned int color) {
|
||||
switch(color) {
|
||||
case COLOR_APP:
|
||||
return chainConfig->color_header;
|
||||
|
||||
case COLOR_APP_LIGHT:
|
||||
return chainConfig->color_dashboard;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
void copy_element_and_map_coin_colors(const bagl_element_t* element) {
|
||||
os_memmove(&tmp_element, element, sizeof(bagl_element_t));
|
||||
tmp_element.component.fgcolor = map_color(tmp_element.component.fgcolor);
|
||||
tmp_element.component.bgcolor = map_color(tmp_element.component.bgcolor);
|
||||
tmp_element.overfgcolor = map_color(tmp_element.overfgcolor);
|
||||
tmp_element.overbgcolor = map_color(tmp_element.overbgcolor);
|
||||
}
|
||||
|
||||
const bagl_element_t *ui_idle_blue_prepro(const bagl_element_t *element) {
|
||||
copy_element_and_map_coin_colors(element);
|
||||
if (element->component.userid == 0x01) {
|
||||
tmp_element.text = chainConfig->header_text;
|
||||
}
|
||||
return &tmp_element;
|
||||
}
|
||||
|
||||
const bagl_element_t ui_idle_blue[9] = {
|
||||
// type userid x y w h str rad fill fg bg fid iid txt touchparams... ]
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1, 0x000000, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
// erase screen (only under the status bar)
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
/// TOP STATUS BAR
|
||||
{{BAGL_LABELINE , 0x01, 0, 45, 320, 30, 0, 0, BAGL_FILL, 0xFFFFFF, COLOR_APP, BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, CHAINID_UPCASE, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 0, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, BAGL_FONT_SYMBOLS_0_SETTINGS, 0, COLOR_APP, 0xFFFFFF, io_seproxyhal_touch_settings, NULL, NULL},
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 264, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, BAGL_FONT_SYMBOLS_0_DASHBOARD, 0, COLOR_APP, 0xFFFFFF, io_seproxyhal_touch_exit, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 0, 270, 320, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_LIGHT_16_22PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Open your wallet", 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x00, 0, 308, 320, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Connect your Ledger Blue and open your", 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x00, 0, 331, 320, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "preferred wallet to view your accounts.", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 0, 450, 320, 14, 0, 0, 0 , 0x999999, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_8_11PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Validation requests will show automatically.", 10, 0, COLOR_BG_1, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
unsigned int ui_idle_blue_button(unsigned int button_mask, unsigned int button_mask_counter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const bagl_element_t * ui_settings_blue_toggle_data(const bagl_element_t * e) {
|
||||
// swap setting and request redraw of settings elements
|
||||
uint8_t setting = N_storage.dataAllowed?0:1;
|
||||
nvm_write(&N_storage.dataAllowed, (void*)&setting, sizeof(uint8_t));
|
||||
|
||||
// only refresh settings mutable drawn elements
|
||||
UX_REDISPLAY_IDX(7);
|
||||
|
||||
// won't redisplay the bagl_none
|
||||
return 0;
|
||||
}
|
||||
|
||||
const bagl_element_t * ui_settings_blue_toggle_details(const bagl_element_t * e) {
|
||||
// swap setting and request redraw of settings elements
|
||||
uint8_t setting = N_storage.contractDetails?0:1;
|
||||
nvm_write(&N_storage.contractDetails, (void*)&setting, sizeof(uint8_t));
|
||||
|
||||
// only refresh settings mutable drawn elements
|
||||
UX_REDISPLAY_IDX(7);
|
||||
|
||||
// won't redisplay the bagl_none
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// don't perform any draw/color change upon finger event over settings
|
||||
const bagl_element_t* ui_settings_out_over(const bagl_element_t* e) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int ui_settings_back_callback(const bagl_element_t* e) {
|
||||
// go back to idle
|
||||
ui_idle();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const bagl_element_t ui_settings_blue[13] = {
|
||||
// type userid x y w h str rad fill fg bg fid iid txt touchparams... ]
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1, 0x000000, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
// erase screen (only under the status bar)
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
/// TOP STATUS BAR
|
||||
{{BAGL_LABELINE , 0x00, 0, 45, 320, 30, 0, 0, BAGL_FILL, 0xFFFFFF, COLOR_APP, BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "SETTINGS", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 0, 19, 50, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, BAGL_FONT_SYMBOLS_0_LEFT, 0, COLOR_APP, 0xFFFFFF, ui_settings_back_callback, NULL, NULL},
|
||||
//{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 264, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, BAGL_FONT_SYMBOLS_0_DASHBOARD, 0, COLOR_APP, 0xFFFFFF, io_seproxyhal_touch_exit, NULL, NULL},
|
||||
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 30, 105, 160, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, "Contract data", 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x00, 30, 126, 260, 30, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, 0 }, "Allow contract data in transactions", 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_NONE | BAGL_FLAG_TOUCHABLE , 0x00, 0, 78, 320, 68, 0, 0, BAGL_FILL, 0xFFFFFF, 0x000000, 0 , 0 }, NULL, 0, 0xEEEEEE, 0x000000, ui_settings_blue_toggle_data, ui_settings_out_over, ui_settings_out_over },
|
||||
|
||||
{{BAGL_RECTANGLE, 0x00, 30, 146, 260, 1, 1, 0, 0, 0xEEEEEE, COLOR_BG_1, 0, 0}, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE, 0x00, 30, 174, 160, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0}, "Display data", 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE, 0x00, 30, 195, 260, 30, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, 0}, "Display contract data details", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_NONE | BAGL_FLAG_TOUCHABLE, 0x00, 0, 147, 320, 68, 0, 0, BAGL_FILL, 0xFFFFFF, 0x000000, 0, 0}, NULL, 0, 0xEEEEEE, 0x000000, ui_settings_blue_toggle_details, ui_settings_out_over, ui_settings_out_over},
|
||||
|
||||
{{BAGL_ICON, 0x02, 258, 167, 32, 18, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, 0, 0}, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_ICON , 0x01, 258, 98, 32, 18, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, 0, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
const bagl_element_t * ui_settings_blue_prepro(const bagl_element_t * e) {
|
||||
copy_element_and_map_coin_colors(e);
|
||||
// none elements are skipped
|
||||
if ((e->component.type&(~BAGL_FLAG_TOUCHABLE)) == BAGL_NONE) {
|
||||
return 0;
|
||||
}
|
||||
// swap icon buffer to be displayed depending on if corresponding setting is enabled or not.
|
||||
if (e->component.userid) {
|
||||
switch(e->component.userid) {
|
||||
case 0x01:
|
||||
// swap icon content
|
||||
if (N_storage.dataAllowed) {
|
||||
tmp_element.text = &C_icon_toggle_set;
|
||||
}
|
||||
else {
|
||||
tmp_element.text = &C_icon_toggle_reset;
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
// swap icon content
|
||||
if (N_storage.contractDetails) {
|
||||
tmp_element.text = &C_icon_toggle_set;
|
||||
}
|
||||
else {
|
||||
tmp_element.text = &C_icon_toggle_reset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return &tmp_element;
|
||||
}
|
||||
|
||||
unsigned int ui_settings_blue_button(unsigned int button_mask, unsigned int button_mask_counter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// reuse addressSummary for each line content
|
||||
const char* ui_details_title;
|
||||
const char* ui_details_content;
|
||||
typedef void (*callback_t)(void);
|
||||
callback_t ui_details_back_callback;
|
||||
|
||||
const bagl_element_t* ui_details_blue_back_callback(const bagl_element_t* element) {
|
||||
ui_details_back_callback();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const bagl_element_t ui_details_blue[16] = {
|
||||
// erase screen (only under the status bar)
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1, 0x000000, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
/// TOP STATUS BAR
|
||||
{{BAGL_LABELINE , 0x01, 0, 45, 320, 30, 0, 0, BAGL_FILL, 0xFFFFFF, COLOR_APP, BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 0, 19, 50, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, BAGL_FONT_SYMBOLS_0_LEFT, 0, COLOR_APP, 0xFFFFFF, ui_details_blue_back_callback, NULL, NULL},
|
||||
//{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 264, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, " " /*BAGL_FONT_SYMBOLS_0_DASHBOARD*/, 0, COLOR_APP, 0xFFFFFF, io_seproxyhal_touch_exit, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 30, 106, 320, 30, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0 }, "VALUE", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x10, 30, 136, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x11, 30, 159, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x12, 30, 182, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x13, 30, 205, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x14, 30, 228, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x15, 30, 251, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x16, 30, 274, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x17, 30, 297, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x18, 30, 320, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
//"..." at the end if too much
|
||||
{{BAGL_LABELINE , 0x19, 30, 343, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 0, 450, 320, 14, 0, 0, 0 , 0x999999, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_8_11PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Review the whole value before continuing.", 10, 0, COLOR_BG_1, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
const bagl_element_t* ui_details_blue_prepro(const bagl_element_t* element) {
|
||||
copy_element_and_map_coin_colors(element);
|
||||
if (element->component.userid == 1) {
|
||||
tmp_element.text = ui_details_title;
|
||||
return &tmp_element;
|
||||
}
|
||||
else if(element->component.userid > 0) {
|
||||
unsigned int length = strlen(ui_details_content);
|
||||
if (length >= (element->component.userid & 0xF) * MAX_CHAR_PER_LINE) {
|
||||
os_memset(addressSummary, 0, MAX_CHAR_PER_LINE+1);
|
||||
os_memmove(addressSummary, ui_details_content+(element->component.userid & 0xF) * MAX_CHAR_PER_LINE, MIN(length - (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, MAX_CHAR_PER_LINE));
|
||||
return &tmp_element;
|
||||
}
|
||||
// nothing to draw for this line
|
||||
return 0;
|
||||
}
|
||||
return &tmp_element;
|
||||
}
|
||||
|
||||
unsigned int ui_details_blue_button(unsigned int button_mask, unsigned int button_mask_counter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ui_details_init(const char* title, const char* content, callback_t back_callback) {
|
||||
ui_details_title = title;
|
||||
ui_details_content = content;
|
||||
ui_details_back_callback = back_callback;
|
||||
UX_DISPLAY(ui_details_blue, ui_details_blue_prepro);
|
||||
}
|
||||
|
||||
void ui_approval_blue_init(void);
|
||||
|
||||
bagl_element_callback_t ui_approval_blue_ok;
|
||||
bagl_element_callback_t ui_approval_blue_cancel;
|
||||
|
||||
const bagl_element_t* ui_approval_blue_ok_callback(const bagl_element_t* e) {
|
||||
return ui_approval_blue_ok(e);
|
||||
}
|
||||
|
||||
const bagl_element_t* ui_approval_blue_cancel_callback(const bagl_element_t* e) {
|
||||
return ui_approval_blue_cancel(e);
|
||||
}
|
||||
|
||||
ui_approval_blue_state_t G_ui_approval_blue_state;
|
||||
// pointer to value to be displayed
|
||||
const char* ui_approval_blue_values[3];
|
||||
// variable part of the structure
|
||||
const char* const ui_approval_blue_details_name[][5] = {
|
||||
/*APPROVAL_TRANSACTION*/
|
||||
{"AMOUNT", "ADDRESS", "MAX FEES","CONFIRM TRANSACTION","Transaction details",},
|
||||
|
||||
/*APPROVAL_MESSAGE*/
|
||||
{"HASH", NULL, NULL, "SIGN MESSAGE", "Message signature", },
|
||||
};
|
||||
|
||||
const bagl_element_t* ui_approval_blue_1_details(const bagl_element_t* e) {
|
||||
if (strlen(ui_approval_blue_values[0])*BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH >= 160) {
|
||||
// display details screen
|
||||
ui_details_init(ui_approval_blue_details_name[G_ui_approval_blue_state][0], ui_approval_blue_values[0], ui_approval_blue_init);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
const bagl_element_t* ui_approval_blue_2_details(const bagl_element_t* e) {
|
||||
if (strlen(ui_approval_blue_values[1])*BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH >= 160) {
|
||||
ui_details_init(ui_approval_blue_details_name[G_ui_approval_blue_state][1], ui_approval_blue_values[1], ui_approval_blue_init);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
const bagl_element_t* ui_approval_blue_3_details(const bagl_element_t* e) {
|
||||
if (strlen(ui_approval_blue_values[2])*BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH >= 160) {
|
||||
ui_details_init(ui_approval_blue_details_name[G_ui_approval_blue_state][2], ui_approval_blue_values[2], ui_approval_blue_init);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
const bagl_element_t ui_approval_blue[29] = {
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1, 0x000000, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
// erase screen (only under the status bar)
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
/// TOP STATUS BAR
|
||||
{{BAGL_LABELINE , 0x60, 0, 45, 320, 30, 0, 0, BAGL_FILL, 0xFFFFFF, COLOR_APP, BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
// BADGE_TRANSACTION.GIF
|
||||
{{BAGL_ICON , 0x40, 30, 98, 50, 50, 0, 0, BAGL_FILL, 0 , COLOR_BG_1, 0 , 0 } , &C_badge_transaction, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
{{BAGL_LABELINE , 0x50, 100, 117, 320, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 100, 138, 320, 30, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, 0 }, "Check and confirm values", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
|
||||
{{BAGL_LABELINE , 0x70, 30, 196, 100, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL}, // AMOUNT
|
||||
// x-18 when ...
|
||||
{{BAGL_LABELINE , 0x10, 130, 200, 160, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_LIGHT_16_22PX|BAGL_FONT_ALIGNMENT_RIGHT, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL}, // fullAmount
|
||||
{{BAGL_LABELINE , 0x20, 284, 196, 6, 16, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_RIGHT, 0 }, BAGL_FONT_SYMBOLS_0_MINIRIGHT, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_NONE | BAGL_FLAG_TOUCHABLE , 0x00, 0, 168, 320, 48, 0, 9, BAGL_FILL, 0xFFFFFF, 0x000000, 0 , 0 }, NULL, 0, 0xEEEEEE, 0x000000, ui_approval_blue_1_details, ui_menu_item_out_over, ui_menu_item_out_over },
|
||||
{{BAGL_RECTANGLE , 0x20, 0, 168, 5, 48, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BG_1, 0 , 0 }, NULL, 0, 0x41CCB4, 0, NULL, NULL, NULL },
|
||||
|
||||
{{BAGL_RECTANGLE , 0x31, 30, 216, 260, 1, 1, 0, 0 , 0xEEEEEE, COLOR_BG_1, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
|
||||
{{BAGL_LABELINE , 0x71, 30, 245, 100, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL}, // ADDRESS
|
||||
// x-18 when ...
|
||||
{{BAGL_LABELINE , 0x11, 130, 245, 160, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX|BAGL_FONT_ALIGNMENT_RIGHT, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL}, // fullAddress
|
||||
{{BAGL_LABELINE , 0x21, 284, 245, 6, 16, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_RIGHT, 0 }, BAGL_FONT_SYMBOLS_0_MINIRIGHT, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_NONE | BAGL_FLAG_TOUCHABLE , 0x00, 0, 217, 320, 48, 0, 9, BAGL_FILL, 0xFFFFFF, 0x000000, 0 , 0 }, NULL, 0, 0xEEEEEE, 0x000000, ui_approval_blue_2_details, ui_menu_item_out_over, ui_menu_item_out_over },
|
||||
{{BAGL_RECTANGLE , 0x21, 0, 217, 5, 48, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BG_1, 0 , 0 }, NULL, 0, 0x41CCB4, 0, NULL, NULL, NULL },
|
||||
|
||||
{{BAGL_RECTANGLE , 0x32, 30, 265, 260, 1, 1, 0, 0 , 0xEEEEEE, COLOR_BG_1, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
|
||||
{{BAGL_LABELINE , 0x72, 30, 294, 100, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL}, // MAX FEES
|
||||
// x-18 when ...
|
||||
{{BAGL_LABELINE , 0x12, 130, 294, 160, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX|BAGL_FONT_ALIGNMENT_RIGHT, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL}, //maxFee
|
||||
{{BAGL_LABELINE , 0x22, 284, 294, 6, 16, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_RIGHT, 0 }, BAGL_FONT_SYMBOLS_0_MINIRIGHT, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_NONE | BAGL_FLAG_TOUCHABLE , 0x00, 0, 266, 320, 48, 0, 9, BAGL_FILL, 0xFFFFFF, 0x000000, 0 , 0 }, NULL, 0, 0xEEEEEE, 0x000000, ui_approval_blue_3_details, ui_menu_item_out_over, ui_menu_item_out_over },
|
||||
{{BAGL_RECTANGLE , 0x22, 0, 266, 5, 48, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BG_1, 0 , 0 }, NULL, 0, 0x41CCB4, 0, NULL, NULL, NULL },
|
||||
|
||||
{{BAGL_RECTANGLE, 0x90, 30, 314, 260, 1, 1, 0, 0, 0xEEEEEE, COLOR_BG_1, 0, 0}, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE, 0x90, 30, 343, 120, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0}, "CONTRACT DATA", 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE, 0x90, 133, 343, 140, 30, 0, 0, BAGL_FILL, 0x666666, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX | BAGL_FONT_ALIGNMENT_RIGHT, 0}, "Present", 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_ICON, 0x90, 278, 333, 12, 12, 0, 0, BAGL_FILL, 0, COLOR_BG_1, 0, 0}, &C_icon_warning, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 40, 414, 115, 36, 0,18, BAGL_FILL, 0xCCCCCC, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, "REJECT", 0, 0xB7B7B7, COLOR_BG_1, ui_approval_blue_cancel_callback, NULL, NULL},
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 165, 414, 115, 36, 0,18, BAGL_FILL, 0x41ccb4, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, "CONFIRM", 0, 0x3ab7a2, COLOR_BG_1, ui_approval_blue_ok_callback, NULL, NULL},
|
||||
|
||||
};
|
||||
|
||||
const bagl_element_t* ui_approval_blue_prepro(const bagl_element_t* element) {
|
||||
copy_element_and_map_coin_colors(element);
|
||||
if (element->component.userid == 0) {
|
||||
return &tmp_element;
|
||||
}
|
||||
// none elements are skipped
|
||||
if ((element->component.type&(~BAGL_FLAG_TOUCHABLE)) == BAGL_NONE) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
switch(element->component.userid&0xF0) {
|
||||
|
||||
// icon
|
||||
case 0x40:
|
||||
return &tmp_element;
|
||||
break;
|
||||
|
||||
// TITLE
|
||||
case 0x60:
|
||||
tmp_element.text = ui_approval_blue_details_name[G_ui_approval_blue_state][3];
|
||||
return &tmp_element;
|
||||
break;
|
||||
|
||||
// SUBLINE
|
||||
case 0x50:
|
||||
tmp_element.text = ui_approval_blue_details_name[G_ui_approval_blue_state][4];
|
||||
return &tmp_element;
|
||||
|
||||
// details label
|
||||
case 0x70:
|
||||
if (!ui_approval_blue_details_name[G_ui_approval_blue_state][element->component.userid&0xF]) {
|
||||
return NULL;
|
||||
}
|
||||
tmp_element.text = ui_approval_blue_details_name[G_ui_approval_blue_state][element->component.userid&0xF];
|
||||
return &tmp_element;
|
||||
|
||||
// detail value
|
||||
case 0x10:
|
||||
// won't display
|
||||
if (!ui_approval_blue_details_name[G_ui_approval_blue_state][element->component.userid&0xF]) {
|
||||
return NULL;
|
||||
}
|
||||
// always display the value
|
||||
tmp_element.text = ui_approval_blue_values[(element->component.userid&0xF)];
|
||||
|
||||
// x -= 18 when overflow is detected
|
||||
if (strlen(ui_approval_blue_values[(element->component.userid&0xF)])*BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH >= 160) {
|
||||
tmp_element.component.x -= 18;
|
||||
}
|
||||
return &tmp_element;
|
||||
break;
|
||||
|
||||
// right arrow and left selection rectangle
|
||||
case 0x20:
|
||||
if (!ui_approval_blue_details_name[G_ui_approval_blue_state][element->component.userid&0xF]) {
|
||||
return NULL;
|
||||
}
|
||||
if (strlen(ui_approval_blue_values[(element->component.userid&0xF)])*BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH < 160) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// horizontal delimiter
|
||||
case 0x30:
|
||||
return ui_approval_blue_details_name[G_ui_approval_blue_state][element->component.userid&0xF]!=NULL?&tmp_element:NULL;
|
||||
|
||||
case 0x90:
|
||||
return (dataPresent && !N_storage.contractDetails);
|
||||
}
|
||||
}
|
||||
return &tmp_element;
|
||||
}
|
||||
unsigned int ui_approval_blue_button(unsigned int button_mask, unsigned int button_mask_counter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const bagl_element_t ui_address_blue[8] = {
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1, 0x000000, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
|
||||
// erase screen (only under the status bar)
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
/// TOP STATUS BAR
|
||||
{{BAGL_LABELINE , 0x00, 0, 45, 320, 30, 0, 0, BAGL_FILL, 0xFFFFFF, COLOR_APP, BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "CONFIRM ACCOUNT", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
//{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 264, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, " " /*BAGL_FONT_SYMBOLS_0_DASHBOARD*/, 0, COLOR_APP, 0xFFFFFF, io_seproxyhal_touch_exit, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 30, 106, 320, 30, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0 }, "ACCOUNT", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x10, 30, 136, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x11, 30, 159, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 40, 414, 115, 36, 0,18, BAGL_FILL, 0xCCCCCC, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, "REJECT", 0, 0xB7B7B7, COLOR_BG_1, io_seproxyhal_touch_address_cancel, NULL, NULL},
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 165, 414, 115, 36, 0,18, BAGL_FILL, 0x41ccb4, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, "CONFIRM", 0, 0x3ab7a2, COLOR_BG_1, io_seproxyhal_touch_address_ok, NULL, NULL},
|
||||
};
|
||||
|
||||
unsigned int ui_address_blue_prepro(const bagl_element_t* element) {
|
||||
copy_element_and_map_coin_colors(element);
|
||||
if(element->component.userid > 0) {
|
||||
unsigned int length = strlen(strings.common.fullAddress);
|
||||
if (length >= (element->component.userid & 0xF) * MAX_CHAR_PER_LINE) {
|
||||
os_memset(addressSummary, 0, MAX_CHAR_PER_LINE+1);
|
||||
os_memmove(addressSummary, strings.common.fullAddress+(element->component.userid & 0xF) * MAX_CHAR_PER_LINE, MIN(length - (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, MAX_CHAR_PER_LINE));
|
||||
return &tmp_element;
|
||||
}
|
||||
// nothing to draw for this line
|
||||
return 0;
|
||||
}
|
||||
return &tmp_element;
|
||||
}
|
||||
|
||||
unsigned int ui_address_blue_button(unsigned int button_mask, unsigned int button_mask_counter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const bagl_element_t ui_data_selector_blue[7] = {
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1, 0x000000, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
|
||||
// erase screen (only under the status bar)
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
/// TOP STATUS BAR
|
||||
{{BAGL_LABELINE , 0x00, 0, 45, 320, 30, 0, 0, BAGL_FILL, 0xFFFFFF, COLOR_APP, BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "CONFIRM SELECTOR", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
//{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 264, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, " " /*BAGL_FONT_SYMBOLS_0_DASHBOARD*/, 0, COLOR_APP, 0xFFFFFF, io_seproxyhal_touch_exit, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 30, 106, 320, 30, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0 }, "SELECTOR", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x10, 30, 136, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, strings.tmp.tmp, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 40, 414, 115, 36, 0,18, BAGL_FILL, 0xCCCCCC, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, "REJECT", 0, 0xB7B7B7, COLOR_BG_1, io_seproxyhal_touch_data_cancel, NULL, NULL},
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 165, 414, 115, 36, 0,18, BAGL_FILL, 0x41ccb4, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, "CONFIRM", 0, 0x3ab7a2, COLOR_BG_1, io_seproxyhal_touch_data_ok, NULL, NULL},
|
||||
};
|
||||
|
||||
unsigned int ui_data_selector_blue_prepro(const bagl_element_t* element) {
|
||||
copy_element_and_map_coin_colors(element);
|
||||
if(element->component.userid > 0) {
|
||||
unsigned int length = strlen(strings.tmp.tmp);
|
||||
unsigned int offset = (element->component.userid & 0xF) * 24;
|
||||
if (length >= offset) {
|
||||
unsigned int copyLength = ((offset + 24) > length ? length - offset : 24);
|
||||
os_memset(addressSummary, 0, 25);
|
||||
os_memmove(addressSummary, strings.tmp.tmp + offset, copyLength);
|
||||
return &tmp_element;
|
||||
}
|
||||
// nothing to draw for this line
|
||||
return 0;
|
||||
}
|
||||
return &tmp_element;
|
||||
}
|
||||
|
||||
unsigned int ui_data_selector_blue_button(unsigned int button_mask, unsigned int button_mask_counter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const bagl_element_t ui_data_parameter_blue[11] = {
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1, 0x000000, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL },
|
||||
|
||||
|
||||
// erase screen (only under the status bar)
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0 , 0 }, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
/// TOP STATUS BAR
|
||||
{{BAGL_LABELINE , 0x00, 0, 45, 320, 30, 0, 0, BAGL_FILL, 0xFFFFFF, COLOR_APP, BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "CONFIRM PARAMETER", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
//{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 264, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, " " /*BAGL_FONT_SYMBOLS_0_DASHBOARD*/, 0, COLOR_APP, 0xFFFFFF, io_seproxyhal_touch_exit, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 30, 106, 320, 30, 0, 0, BAGL_FILL, 0x999999, COLOR_BG_1, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0 }, "PARAMETER", 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_LABELINE , 0x00, 30, 136, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, strings.tmp.tmp2, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x10, 30, 159, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x11, 30, 182, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x12, 30, 205, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
{{BAGL_LABELINE , 0x13, 30, 228, 260, 30, 0, 0, BAGL_FILL, 0x000000, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0 }, addressSummary, 0, 0, 0, NULL, NULL, NULL},
|
||||
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 40, 414, 115, 36, 0,18, BAGL_FILL, 0xCCCCCC, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, "REJECT", 0, 0xB7B7B7, COLOR_BG_1, io_seproxyhal_touch_data_cancel, NULL, NULL},
|
||||
{{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 165, 414, 115, 36, 0,18, BAGL_FILL, 0x41ccb4, COLOR_BG_1, BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, "CONFIRM", 0, 0x3ab7a2, COLOR_BG_1, io_seproxyhal_touch_data_ok, NULL, NULL},
|
||||
};
|
||||
|
||||
unsigned int ui_data_parameter_blue_prepro(const bagl_element_t* element) {
|
||||
copy_element_and_map_coin_colors(element);
|
||||
if(element->component.userid > 0) {
|
||||
unsigned int pos = (element->component.userid & 0xF);
|
||||
unsigned int i;
|
||||
unsigned int offset = 0;
|
||||
unsigned int copyLength;
|
||||
for (i=0; i<pos; i++) {
|
||||
offset += local_strchr(strings.tmp.tmp + offset, ':');
|
||||
if (offset < 0) {
|
||||
THROW(EXCEPTION);
|
||||
}
|
||||
offset = offset + 1;
|
||||
}
|
||||
if (pos == 3) {
|
||||
copyLength = strlen(strings.tmp.tmp) - offset;
|
||||
}
|
||||
else {
|
||||
unsigned int endOffset;
|
||||
endOffset = offset + local_strchr(strings.tmp.tmp + offset, ':');
|
||||
copyLength = endOffset - offset;
|
||||
}
|
||||
os_memmove(addressSummary, strings.tmp.tmp + offset, copyLength);
|
||||
addressSummary[copyLength] = '\0';
|
||||
}
|
||||
return &tmp_element;
|
||||
}
|
||||
|
||||
unsigned int ui_data_parameter_blue_button(unsigned int button_mask, unsigned int button_mask_counter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
45
src/ui_blue.h
Normal file
45
src/ui_blue.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
#include "os_io_seproxyhal.h"
|
||||
|
||||
typedef enum {
|
||||
APPROVAL_TRANSACTION,
|
||||
APPROVAL_MESSAGE,
|
||||
} ui_approval_blue_state_t;
|
||||
|
||||
#define COLOR_BG_1 0xF9F9F9
|
||||
#define COLOR_APP 0x0ebdcf
|
||||
#define COLOR_APP_LIGHT 0x87dee6
|
||||
|
||||
extern const bagl_element_t ui_idle_blue[9];
|
||||
unsigned int ui_idle_blue_button(unsigned int button_mask, unsigned int button_mask_counter);
|
||||
const bagl_element_t *ui_idle_blue_prepro(const bagl_element_t *element);
|
||||
|
||||
extern const bagl_element_t ui_settings_blue[13];
|
||||
unsigned int ui_settings_blue_button(unsigned int button_mask, unsigned int button_mask_counter);
|
||||
const bagl_element_t * ui_settings_blue_prepro(const bagl_element_t * e);
|
||||
|
||||
extern const bagl_element_t ui_details_blue[16];
|
||||
unsigned int ui_details_blue_button(unsigned int button_mask, unsigned int button_mask_counter);
|
||||
const bagl_element_t* ui_details_blue_prepro(const bagl_element_t* element);
|
||||
|
||||
extern const bagl_element_t ui_approval_blue[29];
|
||||
unsigned int ui_approval_blue_button(unsigned int button_mask, unsigned int button_mask_counter);
|
||||
const bagl_element_t* ui_approval_blue_prepro(const bagl_element_t* element);
|
||||
|
||||
extern const bagl_element_t ui_address_blue[8];
|
||||
unsigned int ui_address_blue_button(unsigned int button_mask, unsigned int button_mask_counter);
|
||||
unsigned int ui_address_blue_prepro(const bagl_element_t* element);
|
||||
|
||||
extern const bagl_element_t ui_data_selector_blue[7];
|
||||
unsigned int ui_data_selector_blue_button(unsigned int button_mask, unsigned int button_mask_counter);
|
||||
unsigned int ui_data_selector_blue_prepro(const bagl_element_t* element);
|
||||
|
||||
extern const bagl_element_t ui_data_parameter_blue[11];
|
||||
unsigned int ui_data_parameter_blue_button(unsigned int button_mask, unsigned int button_mask_counter);
|
||||
unsigned int ui_data_parameter_blue_prepro(const bagl_element_t* element);
|
||||
|
||||
extern bagl_element_callback_t ui_approval_blue_ok;
|
||||
extern bagl_element_callback_t ui_approval_blue_cancel;
|
||||
extern ui_approval_blue_state_t G_ui_approval_blue_state;
|
||||
extern const char* ui_approval_blue_values[3];
|
||||
20
src/ui_callbacks.h
Normal file
20
src/ui_callbacks.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e);
|
||||
unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e);
|
||||
unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e);
|
||||
unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e);
|
||||
unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e);
|
||||
unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e);
|
||||
unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e);
|
||||
unsigned int io_seproxyhal_touch_signMessage_cancel(const bagl_element_t *e);
|
||||
unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e);
|
||||
unsigned int io_seproxyhal_touch_data_cancel(const bagl_element_t *e);
|
||||
|
||||
void ui_idle(void);
|
||||
|
||||
void io_seproxyhal_send_status(uint32_t sw);
|
||||
void format_signature_out(const uint8_t* signature);
|
||||
void finalizeParsing(bool direct);
|
||||
tokenDefinition_t* getKnownToken(uint8_t *contractAddress);
|
||||
|
||||
131
src/ui_flow.c
Normal file
131
src/ui_flow.c
Normal file
@@ -0,0 +1,131 @@
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
#ifdef HAVE_UX_FLOW
|
||||
|
||||
void display_settings(void);
|
||||
void switch_settings_contract_data(void);
|
||||
void switch_settings_display_data(void);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_idle_flow_1_step,
|
||||
nn, //pnn,
|
||||
{
|
||||
//"", //&C_icon_dashboard,
|
||||
"Application",
|
||||
"is ready",
|
||||
});
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_idle_flow_2_step,
|
||||
bn,
|
||||
{
|
||||
"Version",
|
||||
APPVERSION,
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_idle_flow_3_step,
|
||||
pb,
|
||||
display_settings(),
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Settings",
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_idle_flow_4_step,
|
||||
pb,
|
||||
os_sched_exit(-1),
|
||||
{
|
||||
&C_icon_dashboard_x,
|
||||
"Quit",
|
||||
});
|
||||
const ux_flow_step_t * const ux_idle_flow [] = {
|
||||
&ux_idle_flow_1_step,
|
||||
&ux_idle_flow_2_step,
|
||||
&ux_idle_flow_3_step,
|
||||
&ux_idle_flow_4_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#if defined(TARGET_NANOS)
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_settings_flow_1_step,
|
||||
bnnn_paging,
|
||||
switch_settings_contract_data(),
|
||||
{
|
||||
.title = "Contract data",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_settings_flow_2_step,
|
||||
bnnn_paging,
|
||||
switch_settings_display_data(),
|
||||
{
|
||||
.title = "Debug data",
|
||||
.text = strings.common.fullAddress + 20
|
||||
});
|
||||
|
||||
#else
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_settings_flow_1_step,
|
||||
bnnn,
|
||||
switch_settings_contract_data(),
|
||||
{
|
||||
"Contract data",
|
||||
"Allow contract data",
|
||||
"in transactions",
|
||||
strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_settings_flow_2_step,
|
||||
bnnn,
|
||||
switch_settings_display_data(),
|
||||
{
|
||||
"Debug data",
|
||||
"Display contract data",
|
||||
"details",
|
||||
strings.common.fullAddress + 20
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_settings_flow_3_step,
|
||||
pb,
|
||||
ui_idle(),
|
||||
{
|
||||
&C_icon_back_x,
|
||||
"Back",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_settings_flow [] = {
|
||||
&ux_settings_flow_1_step,
|
||||
&ux_settings_flow_2_step,
|
||||
&ux_settings_flow_3_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
void display_settings() {
|
||||
strcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed"));
|
||||
strcpy(strings.common.fullAddress + 20, (N_storage.contractDetails ? "Displayed" : "NOT Displayed"));
|
||||
ux_flow_init(0, ux_settings_flow, NULL);
|
||||
}
|
||||
|
||||
void switch_settings_contract_data() {
|
||||
uint8_t value = (N_storage.dataAllowed ? 0 : 1);
|
||||
nvm_write((void*)&N_storage.dataAllowed, (void*)&value, sizeof(uint8_t));
|
||||
display_settings();
|
||||
}
|
||||
|
||||
void switch_settings_display_data() {
|
||||
uint8_t value = (N_storage.contractDetails ? 0 : 1);
|
||||
nvm_write((void*)&N_storage.contractDetails, (void*)&value, sizeof(uint8_t));
|
||||
display_settings();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
46
src/ui_flow.h
Normal file
46
src/ui_flow.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
#include "os_io_seproxyhal.h"
|
||||
|
||||
extern const ux_flow_step_t * const ux_idle_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_settings_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_display_public_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_confirm_selector_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_confirm_parameter_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_approval_tx_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_approval_tx_data_warning_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_approval_allowance_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_sign_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_display_stark_public_flow [];
|
||||
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
extern const ux_flow_step_t * const ux_stark_limit_order_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_stark_transfer_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_stark_self_transfer_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_approval_starkware_register_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_approval_starkware_deposit_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_approval_starkware_withdraw_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_approval_starkware_verify_vault_id_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_approval_starkware_escape_flow [];
|
||||
|
||||
extern const ux_flow_step_t * const ux_approval_starkware_verify_escape_flow [];
|
||||
|
||||
#endif
|
||||
|
||||
@@ -201,8 +201,8 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
|
||||
break;
|
||||
}
|
||||
if (eip1191) {
|
||||
snprintf(tmp, sizeof(tmp), "%d0x", chainConfig->chainId);
|
||||
offset = strlen(tmp);
|
||||
snprintf((char*)tmp, sizeof(tmp), "%d0x", chainConfig->chainId);
|
||||
offset = strlen((char*)tmp);
|
||||
}
|
||||
for (i = 0; i < 20; i++) {
|
||||
uint8_t digit = address[i];
|
||||
|
||||
@@ -51,4 +51,22 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
|
||||
bool adjustDecimals(char *src, uint32_t srcLength, char *target,
|
||||
uint32_t targetLength, uint8_t decimals);
|
||||
|
||||
#endif /* _ETHUTILS_H_ */
|
||||
inline int allzeroes(uint8_t *buf, int n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (buf[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline int ismaxint(uint8_t *buf, int n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (buf[i] != 0xff) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* _ETHUTILS_H_ */
|
||||
|
||||
73
src_features/erc20_approval/ui_flow_erc20_approval.c
Normal file
73
src_features/erc20_approval/ui_flow_erc20_approval.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_approval_allowance_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_allowance_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Allowance",
|
||||
.text = " "
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_allowance_3_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Contract Name",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_allowance_4_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Amount",
|
||||
.text = strings.common.fullAmount
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_allowance_5_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Max Fees",
|
||||
.text = strings.common.maxFee,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_allowance_6_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_tx_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_allowance_7_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_approval_allowance_flow [] = {
|
||||
&ux_approval_allowance_1_step,
|
||||
&ux_approval_allowance_2_step,
|
||||
&ux_approval_allowance_3_step,
|
||||
&ux_approval_allowance_4_step,
|
||||
&ux_approval_allowance_5_step,
|
||||
&ux_approval_allowance_6_step,
|
||||
&ux_approval_allowance_7_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
29
src_features/getAppConfiguration/cmd_getAppConfiguration.c
Normal file
29
src_features/getAppConfiguration/cmd_getAppConfiguration.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "shared_context.h"
|
||||
#include "apdu_constants.h"
|
||||
#ifdef TARGET_BLUE
|
||||
#include "ui_blue.h"
|
||||
#endif
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ui_flow.h"
|
||||
#endif
|
||||
|
||||
void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
UNUSED(p1);
|
||||
UNUSED(p2);
|
||||
UNUSED(workBuffer);
|
||||
UNUSED(dataLength);
|
||||
UNUSED(flags);
|
||||
G_io_apdu_buffer[0] = (N_storage.dataAllowed ? APP_FLAG_DATA_ALLOWED : 0x00);
|
||||
#ifndef HAVE_TOKENS_LIST
|
||||
G_io_apdu_buffer[0] |= APP_FLAG_EXTERNAL_TOKEN_NEEDED;
|
||||
#endif
|
||||
#ifdef HAVE_STARKWARE
|
||||
G_io_apdu_buffer[0] |= APP_FLAG_STARKWARE;
|
||||
#endif
|
||||
G_io_apdu_buffer[1] = LEDGER_MAJOR_VERSION;
|
||||
G_io_apdu_buffer[2] = LEDGER_MINOR_VERSION;
|
||||
G_io_apdu_buffer[3] = LEDGER_PATCH_VERSION;
|
||||
*tx = 4;
|
||||
THROW(0x9000);
|
||||
}
|
||||
|
||||
76
src_features/getPublicKey/cmd_getPublicKey.c
Normal file
76
src_features/getPublicKey/cmd_getPublicKey.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "shared_context.h"
|
||||
#include "apdu_constants.h"
|
||||
#ifdef TARGET_BLUE
|
||||
#include "ui_blue.h"
|
||||
#endif
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ui_flow.h"
|
||||
#endif
|
||||
#include "feature_getPublicKey.h"
|
||||
|
||||
void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
UNUSED(dataLength);
|
||||
uint8_t privateKeyData[32];
|
||||
uint32_t bip32Path[MAX_BIP32_PATH];
|
||||
uint32_t i;
|
||||
uint8_t bip32PathLength = *(dataBuffer++);
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
reset_app_context();
|
||||
if ((bip32PathLength < 0x01) ||
|
||||
(bip32PathLength > MAX_BIP32_PATH)) {
|
||||
PRINTF("Invalid path\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if ((p2 != P2_CHAINCODE) && (p2 != P2_NO_CHAINCODE)) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
for (i = 0; i < bip32PathLength; i++) {
|
||||
bip32Path[i] = U4BE(dataBuffer, 0);
|
||||
dataBuffer += 4;
|
||||
}
|
||||
tmpCtx.publicKeyContext.getChaincode = (p2 == P2_CHAINCODE);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1, bip32Path, bip32PathLength, privateKeyData, (tmpCtx.publicKeyContext.getChaincode ? tmpCtx.publicKeyContext.chainCode : NULL));
|
||||
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
cx_ecfp_generate_pair(CX_CURVE_256K1, &tmpCtx.publicKeyContext.publicKey, &privateKey, 1);
|
||||
os_memset(&privateKey, 0, sizeof(privateKey));
|
||||
os_memset(privateKeyData, 0, sizeof(privateKeyData));
|
||||
io_seproxyhal_io_heartbeat();
|
||||
getEthAddressStringFromKey(&tmpCtx.publicKeyContext.publicKey, tmpCtx.publicKeyContext.address, &sha3);
|
||||
#ifndef NO_CONSENT
|
||||
if (p1 == P1_NON_CONFIRM)
|
||||
#endif // NO_CONSENT
|
||||
{
|
||||
*tx = set_result_get_publicKey();
|
||||
THROW(0x9000);
|
||||
}
|
||||
#ifndef NO_CONSENT
|
||||
else
|
||||
{
|
||||
/*
|
||||
addressSummary[0] = '0';
|
||||
addressSummary[1] = 'x';
|
||||
os_memmove((unsigned char *)(addressSummary + 2), tmpCtx.publicKeyContext.address, 4);
|
||||
os_memmove((unsigned char *)(addressSummary + 6), "...", 3);
|
||||
os_memmove((unsigned char *)(addressSummary + 9), tmpCtx.publicKeyContext.address + 40 - 4, 4);
|
||||
addressSummary[13] = '\0';
|
||||
*/
|
||||
|
||||
// prepare for a UI based reply
|
||||
#if defined(TARGET_BLUE)
|
||||
snprintf(strings.common.fullAddress, sizeof(strings.common.fullAddress), "0x%.*s", 40, tmpCtx.publicKeyContext.address);
|
||||
UX_DISPLAY(ui_address_blue, ui_address_blue_prepro);
|
||||
#else
|
||||
snprintf(strings.common.fullAddress, sizeof(strings.common.fullAddress), "0x%.*s", 40, tmpCtx.publicKeyContext.address);
|
||||
ux_flow_init(0, ux_display_public_flow, NULL);
|
||||
#endif // #if TARGET_ID
|
||||
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
}
|
||||
#endif // NO_CONSENT
|
||||
}
|
||||
|
||||
4
src_features/getPublicKey/feature_getPublicKey.h
Normal file
4
src_features/getPublicKey/feature_getPublicKey.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
uint32_t set_result_get_publicKey(void);
|
||||
|
||||
17
src_features/getPublicKey/logic_getPublicKey.c
Normal file
17
src_features/getPublicKey/logic_getPublicKey.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
uint32_t set_result_get_publicKey() {
|
||||
uint32_t tx = 0;
|
||||
G_io_apdu_buffer[tx++] = 65;
|
||||
os_memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.publicKey.W, 65);
|
||||
tx += 65;
|
||||
G_io_apdu_buffer[tx++] = 40;
|
||||
os_memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.address, 40);
|
||||
tx += 40;
|
||||
if (tmpCtx.publicKeyContext.getChaincode) {
|
||||
os_memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.chainCode, 32);
|
||||
tx += 32;
|
||||
}
|
||||
return tx;
|
||||
}
|
||||
|
||||
27
src_features/getPublicKey/ui_common_getPublicKey.c
Normal file
27
src_features/getPublicKey/ui_common_getPublicKey.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "shared_context.h"
|
||||
#include "feature_getPublicKey.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e) {
|
||||
uint32_t tx = set_result_get_publicKey();
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e) {
|
||||
G_io_apdu_buffer[0] = 0x69;
|
||||
G_io_apdu_buffer[1] = 0x85;
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
47
src_features/getPublicKey/ui_flow_getPublicKey.c
Normal file
47
src_features/getPublicKey/ui_flow_getPublicKey.c
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
#ifdef HAVE_UX_FLOW
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_display_public_flow_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Verify",
|
||||
"address",
|
||||
});
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_display_public_flow_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Address",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_display_public_flow_3_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_address_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Approve",
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_display_public_flow_4_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_address_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_display_public_flow [] = {
|
||||
&ux_display_public_flow_1_step,
|
||||
&ux_display_public_flow_2_step,
|
||||
&ux_display_public_flow_3_step,
|
||||
&ux_display_public_flow_4_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
179
src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c
Normal file
179
src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c
Normal file
@@ -0,0 +1,179 @@
|
||||
#include "shared_context.h"
|
||||
#include "apdu_constants.h"
|
||||
#ifdef TARGET_BLUE
|
||||
#include "ui_blue.h"
|
||||
#endif
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ui_flow.h"
|
||||
#endif
|
||||
|
||||
static const uint8_t const TOKEN_SIGNATURE_PUBLIC_KEY[] = {
|
||||
// production key 2019-01-11 03:07PM (erc20signer)
|
||||
0x04,
|
||||
|
||||
0x5e,0x6c,0x10,0x20,0xc1,0x4d,0xc4,0x64,
|
||||
0x42,0xfe,0x89,0xf9,0x7c,0x0b,0x68,0xcd,
|
||||
0xb1,0x59,0x76,0xdc,0x24,0xf2,0x4c,0x31,
|
||||
0x6e,0x7b,0x30,0xfe,0x4e,0x8c,0xc7,0x6b,
|
||||
|
||||
0x14,0x89,0x15,0x0c,0x21,0x51,0x4e,0xbf,
|
||||
0x44,0x0f,0xf5,0xde,0xa5,0x39,0x3d,0x83,
|
||||
0xde,0x53,0x58,0xcd,0x09,0x8f,0xce,0x8f,
|
||||
0xd0,0xf8,0x1d,0xaa,0x94,0x97,0x91,0x83
|
||||
};
|
||||
|
||||
#ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR
|
||||
|
||||
void handleProvideErc20TokenInformation(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
UNUSED(p1);
|
||||
UNUSED(p2);
|
||||
UNUSED(flags);
|
||||
uint32_t offset = 0;
|
||||
uint8_t tickerLength, contractNameLength;
|
||||
uint32_t chainId;
|
||||
uint8_t hash[32];
|
||||
cx_sha256_t sha256;
|
||||
cx_ecfp_public_key_t tokenKey;
|
||||
|
||||
cx_sha256_init(&sha256);
|
||||
|
||||
tmpCtx.transactionContext.currentTokenIndex = (tmpCtx.transactionContext.currentTokenIndex + 1) % MAX_TOKEN;
|
||||
tokenDefinition_t* token = &tmpCtx.transactionContext.tokens[tmpCtx.transactionContext.currentTokenIndex];
|
||||
|
||||
if (dataLength < 1) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
tickerLength = workBuffer[offset++];
|
||||
dataLength--;
|
||||
if ((tickerLength + 2) >= sizeof(token->ticker)) { // +2 because ' \0' is appended to ticker
|
||||
THROW(0x6A80);
|
||||
}
|
||||
if (dataLength < tickerLength + 1) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
cx_hash((cx_hash_t*)&sha256, 0, workBuffer + offset, tickerLength, NULL, 0);
|
||||
os_memmove(token->ticker, workBuffer + offset, tickerLength);
|
||||
token->ticker[tickerLength] = ' ';
|
||||
token->ticker[tickerLength + 1] = '\0';
|
||||
offset += tickerLength;
|
||||
dataLength -= tickerLength;
|
||||
|
||||
contractNameLength = workBuffer[offset++];
|
||||
dataLength--;
|
||||
if (dataLength < contractNameLength + 20 + 4 + 4) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
cx_hash((cx_hash_t*)&sha256, CX_LAST, workBuffer + offset, contractNameLength + 20 + 4 + 4, hash, 32);
|
||||
os_memmove(token->contractName, workBuffer + offset, MIN(contractNameLength, sizeof(token->contractName)-1));
|
||||
token->contractName[MIN(contractNameLength, sizeof(token->contractName)-1)] = '\0';
|
||||
offset += contractNameLength;
|
||||
dataLength -= contractNameLength;
|
||||
|
||||
os_memmove(token->address, workBuffer + offset, 20);
|
||||
offset += 20;
|
||||
dataLength -= 20;
|
||||
token->decimals = U4BE(workBuffer, offset);
|
||||
offset += 4;
|
||||
dataLength -= 4;
|
||||
chainId = U4BE(workBuffer, offset);
|
||||
if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) {
|
||||
PRINTF("ChainId token mismatch\n");
|
||||
THROW(0x6A80);
|
||||
}
|
||||
offset += 4;
|
||||
dataLength -= 4;
|
||||
cx_ecfp_init_public_key(CX_CURVE_256K1, TOKEN_SIGNATURE_PUBLIC_KEY, sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), &tokenKey);
|
||||
if (!cx_ecdsa_verify(&tokenKey, CX_LAST, CX_SHA256, hash, 32, workBuffer + offset, dataLength)) {
|
||||
PRINTF("Invalid token signature\n");
|
||||
THROW(0x6A80);
|
||||
}
|
||||
tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1;
|
||||
THROW(0x9000);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void handleProvideErc20TokenInformation(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
UNUSED(p1);
|
||||
UNUSED(p2);
|
||||
UNUSED(flags);
|
||||
uint32_t offset = 0;
|
||||
uint8_t tickerLength;
|
||||
uint32_t chainId;
|
||||
uint8_t hash[32];
|
||||
cx_ecfp_public_key_t tokenKey;
|
||||
|
||||
|
||||
tmpCtx.transactionContext.currentTokenIndex = (tmpCtx.transactionContext.currentTokenIndex + 1) % MAX_TOKEN;
|
||||
tokenDefinition_t* token = &tmpCtx.transactionContext.tokens[tmpCtx.transactionContext.currentTokenIndex];
|
||||
|
||||
PRINTF("Provisioning currentTokenIndex %d\n", tmpCtx.transactionContext.currentTokenIndex);
|
||||
|
||||
if (dataLength < 1) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
tickerLength = workBuffer[offset++];
|
||||
dataLength--;
|
||||
if ((tickerLength + 1) >= sizeof(token->ticker)) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
if (dataLength < tickerLength + 20 + 4 + 4) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash, 32);
|
||||
os_memmove(token->ticker, workBuffer + offset, tickerLength);
|
||||
token->ticker[tickerLength] = ' ';
|
||||
token->ticker[tickerLength + 1] = '\0';
|
||||
offset += tickerLength;
|
||||
dataLength -= tickerLength;
|
||||
os_memmove(token->address, workBuffer + offset, 20);
|
||||
offset += 20;
|
||||
dataLength -= 20;
|
||||
token->decimals = U4BE(workBuffer, offset);
|
||||
offset += 4;
|
||||
dataLength -= 4;
|
||||
chainId = U4BE(workBuffer, offset);
|
||||
if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) {
|
||||
PRINTF("ChainId token mismatch\n");
|
||||
THROW(0x6A80);
|
||||
}
|
||||
offset += 4;
|
||||
dataLength -= 4;
|
||||
|
||||
#ifdef HAVE_TOKENS_EXTRA_LIST
|
||||
tokenDefinition_t *currentToken = NULL;
|
||||
uint32_t index;
|
||||
for (index=0; index < NUM_TOKENS_EXTRA; index++) {
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_EXTRA[index]);
|
||||
if (os_memcmp(currentToken->address, token->address, 20) == 0) {
|
||||
strcpy((char*)token->ticker, (char*)currentToken->ticker);
|
||||
token->decimals = currentToken->decimals;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index < NUM_TOKENS_EXTRA) {
|
||||
PRINTF("Descriptor whitelisted\n");
|
||||
}
|
||||
else {
|
||||
cx_ecfp_init_public_key(CX_CURVE_256K1, TOKEN_SIGNATURE_PUBLIC_KEY, sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), &tokenKey);
|
||||
if (!cx_ecdsa_verify(&tokenKey, CX_LAST, CX_SHA256, hash, 32, workBuffer + offset, dataLength)) {
|
||||
PRINTF("Invalid token signature\n");
|
||||
THROW(0x6A80);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
cx_ecfp_init_public_key(CX_CURVE_256K1, TOKEN_SIGNATURE_PUBLIC_KEY, sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), &tokenKey);
|
||||
if (!cx_ecdsa_verify(&tokenKey, CX_LAST, CX_SHA256, hash, 32, workBuffer + offset, dataLength)) {
|
||||
PRINTF("Invalid token signature\n");
|
||||
THROW(0x6A80);
|
||||
}
|
||||
#endif
|
||||
|
||||
tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1;
|
||||
THROW(0x9000);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
105
src_features/signMessage/cmd_signMessage.c
Normal file
105
src_features/signMessage/cmd_signMessage.c
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "shared_context.h"
|
||||
#include "apdu_constants.h"
|
||||
#include "utils.h"
|
||||
#ifdef TARGET_BLUE
|
||||
#include "ui_blue.h"
|
||||
#endif
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ui_flow.h"
|
||||
#endif
|
||||
|
||||
static const char const SIGN_MAGIC[] = "\x19"
|
||||
"Ethereum Signed Message:\n";
|
||||
|
||||
void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
UNUSED(tx);
|
||||
uint8_t hashMessage[32];
|
||||
if (p1 == P1_FIRST) {
|
||||
char tmp[11];
|
||||
uint32_t index;
|
||||
uint32_t base = 10;
|
||||
uint8_t pos = 0;
|
||||
uint32_t i;
|
||||
if (dataLength < 1) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
if (appState != APP_STATE_IDLE) {
|
||||
reset_app_context();
|
||||
}
|
||||
appState = APP_STATE_SIGNING_MESSAGE;
|
||||
tmpCtx.messageSigningContext.pathLength = workBuffer[0];
|
||||
if ((tmpCtx.messageSigningContext.pathLength < 0x01) ||
|
||||
(tmpCtx.messageSigningContext.pathLength > MAX_BIP32_PATH)) {
|
||||
PRINTF("Invalid path\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
workBuffer++;
|
||||
dataLength--;
|
||||
for (i = 0; i < tmpCtx.messageSigningContext.pathLength; i++) {
|
||||
if (dataLength < 4) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
tmpCtx.messageSigningContext.bip32Path[i] = U4BE(workBuffer, 0);
|
||||
workBuffer += 4;
|
||||
dataLength -= 4;
|
||||
}
|
||||
if (dataLength < 4) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
tmpCtx.messageSigningContext.remainingLength = U4BE(workBuffer, 0);
|
||||
workBuffer += 4;
|
||||
dataLength -= 4;
|
||||
// Initialize message header + length
|
||||
cx_keccak_init(&sha3, 256);
|
||||
cx_hash((cx_hash_t *)&sha3, 0, (uint8_t*)SIGN_MAGIC, sizeof(SIGN_MAGIC) - 1, NULL, 0);
|
||||
for (index = 1; (((index * base) <= tmpCtx.messageSigningContext.remainingLength) &&
|
||||
(((index * base) / base) == index));
|
||||
index *= base);
|
||||
for (; index; index /= base) {
|
||||
tmp[pos++] = '0' + ((tmpCtx.messageSigningContext.remainingLength / index) % base);
|
||||
}
|
||||
tmp[pos] = '\0';
|
||||
cx_hash((cx_hash_t *)&sha3, 0, (uint8_t*)tmp, pos, NULL, 0);
|
||||
cx_sha256_init(&tmpContent.sha2);
|
||||
}
|
||||
else if (p1 != P1_MORE) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if (p2 != 0) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_MESSAGE)) {
|
||||
PRINTF("Signature not initialized\n");
|
||||
THROW(0x6985);
|
||||
}
|
||||
if (dataLength > tmpCtx.messageSigningContext.remainingLength) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
cx_hash((cx_hash_t *)&sha3, 0, workBuffer, dataLength, NULL, 0);
|
||||
cx_hash((cx_hash_t *)&tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0);
|
||||
tmpCtx.messageSigningContext.remainingLength -= dataLength;
|
||||
if (tmpCtx.messageSigningContext.remainingLength == 0) {
|
||||
cx_hash((cx_hash_t *)&sha3, CX_LAST, workBuffer, 0, tmpCtx.messageSigningContext.hash, 32);
|
||||
cx_hash((cx_hash_t *)&tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32);
|
||||
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "%.*H", sizeof(hashMessage), hashMessage);
|
||||
|
||||
#ifdef NO_CONSENT
|
||||
io_seproxyhal_touch_signMessage_ok(NULL);
|
||||
#else //NO_CONSENT
|
||||
#if defined(TARGET_BLUE)
|
||||
ui_approval_message_sign_blue_init();
|
||||
#else
|
||||
ux_flow_init(0, ux_sign_flow, NULL);
|
||||
#endif // #if TARGET_ID
|
||||
#endif // NO_CONSENT
|
||||
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
|
||||
} else {
|
||||
THROW(0x9000);
|
||||
}
|
||||
}
|
||||
|
||||
53
src_features/signMessage/ui_common_signMessage.c
Normal file
53
src_features/signMessage/ui_common_signMessage.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) {
|
||||
uint8_t privateKeyData[32];
|
||||
uint8_t signature[100];
|
||||
uint8_t signatureLength;
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
uint32_t tx = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
os_perso_derive_node_bip32(
|
||||
CX_CURVE_256K1, tmpCtx.messageSigningContext.bip32Path,
|
||||
tmpCtx.messageSigningContext.pathLength, privateKeyData, NULL);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
|
||||
os_memset(privateKeyData, 0, sizeof(privateKeyData));
|
||||
unsigned int info = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
signatureLength =
|
||||
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
|
||||
tmpCtx.messageSigningContext.hash,
|
||||
sizeof(tmpCtx.messageSigningContext.hash), signature, sizeof(signature), &info);
|
||||
os_memset(&privateKey, 0, sizeof(privateKey));
|
||||
G_io_apdu_buffer[0] = 27;
|
||||
if (info & CX_ECCINFO_PARITY_ODD) {
|
||||
G_io_apdu_buffer[0]++;
|
||||
}
|
||||
if (info & CX_ECCINFO_xGTn) {
|
||||
G_io_apdu_buffer[0] += 2;
|
||||
}
|
||||
format_signature_out(signature);
|
||||
tx = 65;
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_signMessage_cancel(const bagl_element_t *e) {
|
||||
reset_app_context();
|
||||
G_io_apdu_buffer[0] = 0x69;
|
||||
G_io_apdu_buffer[1] = 0x85;
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
45
src_features/signMessage/ui_flow_signMessage.c
Normal file
45
src_features/signMessage/ui_flow_signMessage.c
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_sign_flow_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_certificate,
|
||||
"Sign",
|
||||
"message",
|
||||
});
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_sign_flow_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Message hash",
|
||||
.text = strings.tmp.tmp,
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_sign_flow_3_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_signMessage_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Sign",
|
||||
"message",
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_sign_flow_4_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_signMessage_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Cancel",
|
||||
"signature",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_sign_flow [] = {
|
||||
&ux_sign_flow_1_step,
|
||||
&ux_sign_flow_2_step,
|
||||
&ux_sign_flow_3_step,
|
||||
&ux_sign_flow_4_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
81
src_features/signTx/cmd_signTx.c
Normal file
81
src_features/signTx/cmd_signTx.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include "shared_context.h"
|
||||
#include "apdu_constants.h"
|
||||
#ifdef TARGET_BLUE
|
||||
#include "ui_blue.h"
|
||||
#endif
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ui_flow.h"
|
||||
#endif
|
||||
#include "feature_signTx.h"
|
||||
|
||||
void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
UNUSED(tx);
|
||||
parserStatus_e txResult;
|
||||
uint32_t i;
|
||||
if (p1 == P1_FIRST) {
|
||||
if (dataLength < 1) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
if (appState != APP_STATE_IDLE) {
|
||||
reset_app_context();
|
||||
}
|
||||
appState = APP_STATE_SIGNING_TX;
|
||||
tmpCtx.transactionContext.pathLength = workBuffer[0];
|
||||
if ((tmpCtx.transactionContext.pathLength < 0x01) ||
|
||||
(tmpCtx.transactionContext.pathLength > MAX_BIP32_PATH)) {
|
||||
PRINTF("Invalid path\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
workBuffer++;
|
||||
dataLength--;
|
||||
for (i = 0; i < tmpCtx.transactionContext.pathLength; i++) {
|
||||
if (dataLength < 4) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
tmpCtx.transactionContext.bip32Path[i] = U4BE(workBuffer, 0);
|
||||
workBuffer += 4;
|
||||
dataLength -= 4;
|
||||
}
|
||||
dataPresent = false;
|
||||
contractProvisioned = CONTRACT_NONE;
|
||||
initTx(&txContext, &sha3, &tmpContent.txContent, customProcessor, NULL);
|
||||
}
|
||||
else
|
||||
if (p1 != P1_MORE) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if (p2 != 0) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_TX)) {
|
||||
PRINTF("Signature not initialized\n");
|
||||
THROW(0x6985);
|
||||
}
|
||||
if (txContext.currentField == TX_RLP_NONE) {
|
||||
PRINTF("Parser not initialized\n");
|
||||
THROW(0x6985);
|
||||
}
|
||||
txResult = processTx(&txContext, workBuffer, dataLength, (chainConfig->kind == CHAIN_KIND_WANCHAIN ? TX_FLAG_TYPE : 0));
|
||||
switch (txResult) {
|
||||
case USTREAM_SUSPENDED:
|
||||
break;
|
||||
case USTREAM_FINISHED:
|
||||
break;
|
||||
case USTREAM_PROCESSING:
|
||||
THROW(0x9000);
|
||||
case USTREAM_FAULT:
|
||||
THROW(0x6A80);
|
||||
default:
|
||||
PRINTF("Unexpected parser status\n");
|
||||
THROW(0x6A80);
|
||||
}
|
||||
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
|
||||
if (txResult == USTREAM_FINISHED) {
|
||||
finalizeParsing(false);
|
||||
}
|
||||
}
|
||||
|
||||
5
src_features/signTx/feature_signTx.h
Normal file
5
src_features/signTx/feature_signTx.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
customStatus_e customProcessor(txContext_t *context);
|
||||
void finalizeParsing(bool direct);
|
||||
|
||||
484
src_features/signTx/logic_signTx.c
Normal file
484
src_features/signTx/logic_signTx.c
Normal file
@@ -0,0 +1,484 @@
|
||||
#include "shared_context.h"
|
||||
#include "utils.h"
|
||||
#include "ui_callbacks.h"
|
||||
#ifdef TARGET_BLUE
|
||||
#include "ui_blue.h"
|
||||
#endif
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ui_flow.h"
|
||||
#endif
|
||||
#ifdef HAVE_STARKWARE
|
||||
#include "stark_utils.h"
|
||||
#endif
|
||||
|
||||
#define TOKEN_TRANSFER_DATA_SIZE 4 + 32 + 32
|
||||
static const uint8_t const TOKEN_TRANSFER_ID[] = { 0xa9, 0x05, 0x9c, 0xbb };
|
||||
|
||||
#define ALLOWANCE_DATA_SIZE 4 + 32 + 32
|
||||
static const uint8_t const ALLOWANCE_ID[] = { 0x09, 0x5e, 0xa7, 0xb3 };
|
||||
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#define STARKWARE_REGISTER_DATA_SIZE 4 + 32
|
||||
static const uint8_t const STARKWARE_REGISTER_ID[] = { 0x76, 0x57, 0x18, 0xd7 };
|
||||
#define STARKWARE_DEPOSIT_TOKEN_DATA_SIZE 4 + 32 + 32 + 32
|
||||
static const uint8_t const STARKWARE_DEPOSIT_TOKEN_ID[] = { 0x00, 0xae, 0xef, 0x8a };
|
||||
#define STARKWARE_DEPOSIT_ETH_DATA_SIZE 4 + 32 + 32
|
||||
static const uint8_t const STARKWARE_DEPOSIT_ETH_ID[] = { 0xe2, 0xbb, 0xb1, 0x58 };
|
||||
#define STARKWARE_DEPOSIT_CANCEL_DATA_SIZE 4 + 32 + 32
|
||||
static const uint8_t const STARKWARE_DEPOSIT_CANCEL_ID[] = { 0xc7, 0xfb, 0x11, 0x7c };
|
||||
#define STARKWARE_DEPOSIT_RECLAIM_DATA_SIZE 4 + 32 + 32
|
||||
static const uint8_t const STARKWARE_DEPOSIT_RECLAIM_ID[] = { 0x4e, 0xab, 0x38, 0xf4 };
|
||||
#define STARKWARE_WITHDRAW_DATA_SIZE 4 + 32
|
||||
static const uint8_t const STARKWARE_WITHDRAW_ID[] = { 0x2e, 0x1a, 0x7d, 0x4d };
|
||||
#define STARKWARE_FULL_WITHDRAWAL_DATA_SIZE 4 + 32
|
||||
static const uint8_t const STARKWARE_FULL_WITHDRAWAL_ID[] = { 0x27, 0x6d, 0xd1, 0xde };
|
||||
#define STARKWARE_FREEZE_DATA_SIZE 4 + 32
|
||||
static const uint8_t const STARKWARE_FREEZE_ID[] = { 0xb9, 0x10, 0x72, 0x09 };
|
||||
#define STARKWARE_ESCAPE_DATA_SIZE 4 + 32 + 32 + 32 + 32
|
||||
static const uint8_t const STARKWARE_ESCAPE_ID[] = { 0x9e, 0x3a, 0xda, 0xc4 };
|
||||
static const uint8_t const STARKWARE_VERIFY_ESCAPE_ID[] = { 0x2d, 0xd5, 0x30, 0x06 };
|
||||
|
||||
#endif
|
||||
|
||||
uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
|
||||
uint32_t i;
|
||||
for (i=0; i<8; i++) {
|
||||
if (parameter[i] != 0x00) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 8) {
|
||||
result[0] = '0';
|
||||
result[1] = '0';
|
||||
result[2] = '\0';
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
array_hexstr(result, parameter + i, 8 - i);
|
||||
return ((8 - i) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
customStatus_e customProcessor(txContext_t *context) {
|
||||
if ((context->currentField == TX_RLP_DATA) &&
|
||||
(context->currentFieldLength != 0)) {
|
||||
dataPresent = true;
|
||||
// If handling a new contract rather than a function call, abort immediately
|
||||
if (tmpContent.txContent.destinationLength == 0) {
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
if (context->currentFieldPos == 0) {
|
||||
// If handling the beginning of the data field, assume that the function selector is present
|
||||
if (context->commandLength < 4) {
|
||||
PRINTF("Missing function selector\n");
|
||||
return CUSTOM_FAULT;
|
||||
}
|
||||
// Initial check to see if the call can be processed
|
||||
if ((context->currentFieldLength == TOKEN_TRANSFER_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, TOKEN_TRANSFER_ID, 4) == 0) &&
|
||||
(getKnownToken(tmpContent.txContent.destination) != NULL)) {
|
||||
contractProvisioned = CONTRACT_ERC20;
|
||||
}
|
||||
else
|
||||
if ((context->currentFieldLength == ALLOWANCE_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, ALLOWANCE_ID, 4) == 0)) {
|
||||
contractProvisioned = CONTRACT_ALLOWANCE;
|
||||
}
|
||||
#ifdef HAVE_STARKWARE
|
||||
else
|
||||
if ((context->currentFieldLength >= STARKWARE_REGISTER_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, STARKWARE_REGISTER_ID, 4) == 0)) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_REGISTER;
|
||||
}
|
||||
else
|
||||
if ((context->currentFieldLength == STARKWARE_DEPOSIT_ETH_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, STARKWARE_DEPOSIT_ETH_ID, 4) == 0)) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_DEPOSIT_ETH;
|
||||
}
|
||||
else
|
||||
if ((context->currentFieldLength == STARKWARE_DEPOSIT_TOKEN_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, STARKWARE_DEPOSIT_TOKEN_ID, 4) == 0) &&
|
||||
quantumSet) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_DEPOSIT_TOKEN;
|
||||
}
|
||||
else
|
||||
if ((context->currentFieldLength == STARKWARE_WITHDRAW_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, STARKWARE_WITHDRAW_ID, 4) == 0) &&
|
||||
quantumSet) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_WITHDRAW;
|
||||
}
|
||||
else
|
||||
if ((context->currentFieldLength == STARKWARE_DEPOSIT_CANCEL_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, STARKWARE_DEPOSIT_CANCEL_ID, 4) == 0)) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_DEPOSIT_CANCEL;
|
||||
}
|
||||
else
|
||||
if ((context->currentFieldLength == STARKWARE_DEPOSIT_RECLAIM_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, STARKWARE_DEPOSIT_RECLAIM_ID, 4) == 0)) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_DEPOSIT_RECLAIM;
|
||||
}
|
||||
else
|
||||
if ((context->currentFieldLength == STARKWARE_FULL_WITHDRAWAL_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, STARKWARE_FULL_WITHDRAWAL_ID, 4) == 0)) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_FULL_WITHDRAWAL;
|
||||
}
|
||||
else
|
||||
if ((context->currentFieldLength == STARKWARE_FREEZE_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, STARKWARE_FREEZE_ID, 4) == 0)) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_FREEZE;
|
||||
}
|
||||
else
|
||||
if ((context->currentFieldLength == STARKWARE_ESCAPE_DATA_SIZE) &&
|
||||
(os_memcmp(context->workBuffer, STARKWARE_ESCAPE_ID, 4) == 0) &&
|
||||
quantumSet) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_ESCAPE;
|
||||
}
|
||||
else
|
||||
if (os_memcmp(context->workBuffer, STARKWARE_VERIFY_ESCAPE_ID, 4) == 0) {
|
||||
contractProvisioned = CONTRACT_STARKWARE_VERIFY_ESCAPE;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
// Sanity check
|
||||
// Also handle exception that only need to process the beginning of the data
|
||||
if ((contractProvisioned != CONTRACT_NONE) &&
|
||||
#ifdef HAVE_STARKWARE
|
||||
(contractProvisioned != CONTRACT_STARKWARE_VERIFY_ESCAPE) &&
|
||||
(contractProvisioned != CONTRACT_STARKWARE_REGISTER) &&
|
||||
#endif
|
||||
(context->currentFieldLength > sizeof(dataContext.tokenContext.data))) {
|
||||
PRINTF("Data field overflow - dropping customization\n");
|
||||
contractProvisioned = CONTRACT_NONE;
|
||||
}
|
||||
PRINTF("contractProvisioned %d\n", contractProvisioned);
|
||||
if (contractProvisioned != CONTRACT_NONE) {
|
||||
if (context->currentFieldPos < context->currentFieldLength) {
|
||||
uint32_t copySize = MIN(context->commandLength,
|
||||
context->currentFieldLength - context->currentFieldPos);
|
||||
// Handle the case where we only need to handle the beginning of the data parameter
|
||||
if ((context->currentFieldPos + copySize) < sizeof(dataContext.tokenContext.data)) {
|
||||
copyTxData(context,
|
||||
dataContext.tokenContext.data + context->currentFieldPos,
|
||||
copySize);
|
||||
}
|
||||
else {
|
||||
if (context->currentFieldPos < sizeof(dataContext.tokenContext.data)) {
|
||||
uint32_t copySize2 = sizeof(dataContext.tokenContext.data) - context->currentFieldPos;
|
||||
copyTxData(context,
|
||||
dataContext.tokenContext.data + context->currentFieldPos,
|
||||
copySize2);
|
||||
copySize -= copySize2;
|
||||
}
|
||||
copyTxData(context, NULL, copySize);
|
||||
}
|
||||
}
|
||||
if (context->currentFieldPos == context->currentFieldLength) {
|
||||
context->currentField++;
|
||||
context->processingField = false;
|
||||
}
|
||||
return CUSTOM_HANDLED;
|
||||
}
|
||||
else {
|
||||
uint32_t blockSize;
|
||||
uint32_t copySize;
|
||||
uint32_t fieldPos = context->currentFieldPos;
|
||||
if (fieldPos == 0) {
|
||||
if (!N_storage.dataAllowed) {
|
||||
PRINTF("Data field forbidden\n");
|
||||
return CUSTOM_FAULT;
|
||||
}
|
||||
if (!N_storage.contractDetails) {
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
dataContext.rawDataContext.fieldIndex = 0;
|
||||
dataContext.rawDataContext.fieldOffset = 0;
|
||||
blockSize = 4;
|
||||
}
|
||||
else {
|
||||
if (!N_storage.contractDetails) {
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
blockSize = 32 - (dataContext.rawDataContext.fieldOffset % 32);
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if ((context->currentFieldLength - fieldPos) < blockSize) {
|
||||
PRINTF("Unconsistent data\n");
|
||||
return CUSTOM_FAULT;
|
||||
}
|
||||
|
||||
copySize = (context->commandLength < blockSize ? context->commandLength : blockSize);
|
||||
copyTxData(context,
|
||||
dataContext.rawDataContext.data + dataContext.rawDataContext.fieldOffset,
|
||||
copySize);
|
||||
|
||||
if (context->currentFieldPos == context->currentFieldLength) {
|
||||
context->currentField++;
|
||||
context->processingField = false;
|
||||
}
|
||||
|
||||
dataContext.rawDataContext.fieldOffset += copySize;
|
||||
|
||||
if (copySize == blockSize) {
|
||||
// Can display
|
||||
if (fieldPos != 0) {
|
||||
dataContext.rawDataContext.fieldIndex++;
|
||||
}
|
||||
dataContext.rawDataContext.fieldOffset = 0;
|
||||
if (fieldPos == 0) {
|
||||
array_hexstr(strings.tmp.tmp, dataContext.rawDataContext.data, 4);
|
||||
#if defined(TARGET_BLUE)
|
||||
UX_DISPLAY(ui_data_selector_blue, ui_data_selector_blue_prepro);
|
||||
#else
|
||||
ux_flow_init(0, ux_confirm_selector_flow, NULL);
|
||||
#endif // #if TARGET_ID
|
||||
}
|
||||
else {
|
||||
uint32_t offset = 0;
|
||||
uint32_t i;
|
||||
snprintf(strings.tmp.tmp2, sizeof(strings.tmp.tmp2), "Field %d", dataContext.rawDataContext.fieldIndex);
|
||||
for (i=0; i<4; i++) {
|
||||
offset += splitBinaryParameterPart(strings.tmp.tmp + offset, dataContext.rawDataContext.data + 8 * i);
|
||||
if (i != 3) {
|
||||
strings.tmp.tmp[offset++] = ':';
|
||||
}
|
||||
}
|
||||
#if defined(TARGET_BLUE)
|
||||
UX_DISPLAY(ui_data_parameter_blue, ui_data_parameter_blue_prepro);
|
||||
#else
|
||||
ux_flow_init(0, ux_confirm_parameter_flow, NULL);
|
||||
#endif // #if TARGET_ID
|
||||
}
|
||||
}
|
||||
else {
|
||||
return CUSTOM_HANDLED;
|
||||
}
|
||||
|
||||
return CUSTOM_SUSPENDED;
|
||||
}
|
||||
}
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
|
||||
void finalizeParsing(bool direct) {
|
||||
uint256_t gasPrice, startGas, uint256;
|
||||
uint32_t i;
|
||||
uint8_t address[41];
|
||||
uint8_t decimals = WEI_TO_ETHER;
|
||||
uint8_t *ticker = (uint8_t *)PIC(chainConfig->coinName);
|
||||
uint8_t *feeTicker = (uint8_t *)PIC(chainConfig->coinName);
|
||||
uint8_t tickerOffset = 0;
|
||||
|
||||
// Verify the chain
|
||||
if (chainConfig->chainId != 0) {
|
||||
uint32_t v = getV(&tmpContent.txContent);
|
||||
if (chainConfig->chainId != v) {
|
||||
reset_app_context();
|
||||
PRINTF("Invalid chainId %d expected %d\n", v, chainConfig->chainId);
|
||||
if (direct) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
else {
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Store the hash
|
||||
cx_hash((cx_hash_t *)&sha3, CX_LAST, tmpCtx.transactionContext.hash, 0, tmpCtx.transactionContext.hash, 32);
|
||||
#ifdef HAVE_STARKWARE
|
||||
if ((contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_ETH) ||
|
||||
(contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_TOKEN) ||
|
||||
(contractProvisioned == CONTRACT_STARKWARE_WITHDRAW) ||
|
||||
(contractProvisioned == CONTRACT_STARKWARE_ESCAPE)) {
|
||||
// For a deposit / withdrawal / escape, check if the token ID is known or can't parse
|
||||
uint8_t tokenIdOffset = (4 + ((contractProvisioned == CONTRACT_STARKWARE_ESCAPE) ? 32 + 32 : 0));
|
||||
if (quantumSet) {
|
||||
tokenDefinition_t *currentToken = NULL;
|
||||
if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) {
|
||||
currentToken = &tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex];
|
||||
}
|
||||
compute_token_id(&sha3,
|
||||
(currentToken != NULL ? currentToken->address : NULL),
|
||||
dataContext.tokenContext.quantum, G_io_apdu_buffer + 100);
|
||||
if (os_memcmp(dataContext.tokenContext.data + tokenIdOffset, G_io_apdu_buffer + 100, 32) != 0) {
|
||||
PRINTF("Token ID not matching - computed %.*H\n", 32, G_io_apdu_buffer + 100);
|
||||
PRINTF("Current quantum %.*H\n", 32, dataContext.tokenContext.quantum);
|
||||
PRINTF("Requested %.*H\n", 32, dataContext.tokenContext.data + tokenIdOffset);
|
||||
contractProvisioned = CONTRACT_NONE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PRINTF("Quantum not set\n");
|
||||
contractProvisioned = CONTRACT_NONE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// If there is a token to process, check if it is well known
|
||||
if ((contractProvisioned == CONTRACT_ERC20) || (contractProvisioned == CONTRACT_ALLOWANCE)) {
|
||||
tokenDefinition_t *currentToken = getKnownToken(tmpContent.txContent.destination);
|
||||
if (currentToken != NULL) {
|
||||
dataPresent = false;
|
||||
decimals = currentToken->decimals;
|
||||
ticker = currentToken->ticker;
|
||||
tmpContent.txContent.destinationLength = 20;
|
||||
os_memmove(tmpContent.txContent.destination, dataContext.tokenContext.data + 4 + 12, 20);
|
||||
os_memmove(tmpContent.txContent.value.value, dataContext.tokenContext.data + 4 + 32, 32);
|
||||
tmpContent.txContent.value.length = 32;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (dataPresent && contractProvisioned == CONTRACT_NONE && !N_storage.dataAllowed) {
|
||||
reset_app_context();
|
||||
PRINTF("Data field forbidden\n");
|
||||
if (direct) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
else {
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add address
|
||||
if (tmpContent.txContent.destinationLength != 0) {
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination, address, &sha3);
|
||||
/*
|
||||
addressSummary[0] = '0';
|
||||
addressSummary[1] = 'x';
|
||||
os_memmove((unsigned char *)(addressSummary + 2), address, 4);
|
||||
os_memmove((unsigned char *)(addressSummary + 6), "...", 3);
|
||||
os_memmove((unsigned char *)(addressSummary + 9), address + 40 - 4, 4);
|
||||
addressSummary[13] = '\0';
|
||||
*/
|
||||
|
||||
strings.common.fullAddress[0] = '0';
|
||||
strings.common.fullAddress[1] = 'x';
|
||||
os_memmove((unsigned char *)strings.common.fullAddress+2, address, 40);
|
||||
strings.common.fullAddress[42] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef TARGET_BLUE
|
||||
os_memmove((void*)addressSummary, CONTRACT_ADDRESS, sizeof(CONTRACT_ADDRESS));
|
||||
#endif
|
||||
strcpy(strings.common.fullAddress, "Contract");
|
||||
}
|
||||
if ((contractProvisioned == CONTRACT_NONE) || (contractProvisioned == CONTRACT_ERC20) ||
|
||||
(contractProvisioned == CONTRACT_ALLOWANCE)) {
|
||||
// Add amount in ethers or tokens
|
||||
if ((contractProvisioned == CONTRACT_ALLOWANCE) && ismaxint(tmpContent.txContent.value.value, 32)) {
|
||||
strcpy((char*)G_io_apdu_buffer, "Unlimited");
|
||||
}
|
||||
else {
|
||||
convertUint256BE(tmpContent.txContent.value.value, tmpContent.txContent.value.length, &uint256);
|
||||
tostring256(&uint256, 10, (char *)(G_io_apdu_buffer + 100), 100);
|
||||
i = 0;
|
||||
while (G_io_apdu_buffer[100 + i]) {
|
||||
i++;
|
||||
}
|
||||
adjustDecimals((char *)(G_io_apdu_buffer + 100), i, (char *)G_io_apdu_buffer, 100, decimals);
|
||||
}
|
||||
i = 0;
|
||||
tickerOffset = 0;
|
||||
while (ticker[tickerOffset]) {
|
||||
strings.common.fullAmount[tickerOffset] = ticker[tickerOffset];
|
||||
tickerOffset++;
|
||||
}
|
||||
while (G_io_apdu_buffer[i]) {
|
||||
strings.common.fullAmount[tickerOffset + i] = G_io_apdu_buffer[i];
|
||||
i++;
|
||||
}
|
||||
strings.common.fullAmount[tickerOffset + i] = '\0';
|
||||
}
|
||||
// Compute maximum fee
|
||||
PRINTF("Max fee\n");
|
||||
PRINTF("Gasprice %.*H\n", tmpContent.txContent.gasprice.length, tmpContent.txContent.gasprice.value);
|
||||
PRINTF("Startgas %.*H\n", tmpContent.txContent.startgas.length, tmpContent.txContent.startgas.value);
|
||||
convertUint256BE(tmpContent.txContent.gasprice.value, tmpContent.txContent.gasprice.length, &gasPrice);
|
||||
convertUint256BE(tmpContent.txContent.startgas.value, tmpContent.txContent.startgas.length, &startGas);
|
||||
mul256(&gasPrice, &startGas, &uint256);
|
||||
tostring256(&uint256, 10, (char *)(G_io_apdu_buffer + 100), 100);
|
||||
i = 0;
|
||||
while (G_io_apdu_buffer[100 + i]) {
|
||||
i++;
|
||||
}
|
||||
adjustDecimals((char *)(G_io_apdu_buffer + 100), i, (char *)G_io_apdu_buffer, 100, WEI_TO_ETHER);
|
||||
i = 0;
|
||||
tickerOffset=0;
|
||||
while (feeTicker[tickerOffset]) {
|
||||
strings.common.maxFee[tickerOffset] = feeTicker[tickerOffset];
|
||||
tickerOffset++;
|
||||
}
|
||||
tickerOffset++;
|
||||
while (G_io_apdu_buffer[i]) {
|
||||
strings.common.maxFee[tickerOffset + i] = G_io_apdu_buffer[i];
|
||||
i++;
|
||||
}
|
||||
strings.common.maxFee[tickerOffset + i] = '\0';
|
||||
|
||||
#ifdef NO_CONSENT
|
||||
io_seproxyhal_touch_tx_ok(NULL);
|
||||
#else // NO_CONSENT
|
||||
#if defined(TARGET_BLUE)
|
||||
ui_approval_transaction_blue_init();
|
||||
#else
|
||||
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_REGISTER) {
|
||||
ux_flow_init(0, ux_approval_starkware_register_flow, NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_TOKEN) {
|
||||
ux_flow_init(0, ux_approval_starkware_deposit_flow, NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_ETH) {
|
||||
ux_flow_init(0, ux_approval_starkware_deposit_flow, NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if ((contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_CANCEL) ||
|
||||
(contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_RECLAIM) ||
|
||||
(contractProvisioned == CONTRACT_STARKWARE_FULL_WITHDRAWAL) ||
|
||||
(contractProvisioned == CONTRACT_STARKWARE_FREEZE)) {
|
||||
ux_flow_init(0, ux_approval_starkware_verify_vault_id_flow, NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_WITHDRAW) {
|
||||
ux_flow_init(0, ux_approval_starkware_withdraw_flow, NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_ESCAPE) {
|
||||
ux_flow_init(0, ux_approval_starkware_escape_flow, NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_VERIFY_ESCAPE) {
|
||||
ux_flow_init(0, ux_approval_starkware_verify_escape_flow, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (contractProvisioned == CONTRACT_ALLOWANCE) {
|
||||
ux_flow_init(0, ux_approval_allowance_flow, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ux_flow_init(0,
|
||||
((dataPresent && !N_storage.contractDetails) ? ux_approval_tx_data_warning_flow : ux_approval_tx_flow),
|
||||
NULL);
|
||||
#endif // #if TARGET_ID
|
||||
#endif // NO_CONSENT
|
||||
}
|
||||
|
||||
103
src_features/signTx/ui_common_signTx.c
Normal file
103
src_features/signTx/ui_common_signTx.c
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "shared_context.h"
|
||||
#include "utils.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
|
||||
uint8_t privateKeyData[32];
|
||||
uint8_t signature[100];
|
||||
uint8_t signatureLength;
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
uint32_t tx = 0;
|
||||
uint32_t v = getV(&tmpContent.txContent);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1, tmpCtx.transactionContext.bip32Path,
|
||||
tmpCtx.transactionContext.pathLength,
|
||||
privateKeyData, NULL);
|
||||
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32,
|
||||
&privateKey);
|
||||
os_memset(privateKeyData, 0, sizeof(privateKeyData));
|
||||
unsigned int info = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
signatureLength =
|
||||
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
|
||||
tmpCtx.transactionContext.hash,
|
||||
sizeof(tmpCtx.transactionContext.hash), signature, sizeof(signature), &info);
|
||||
os_memset(&privateKey, 0, sizeof(privateKey));
|
||||
// Parity is present in the sequence tag in the legacy API
|
||||
if (tmpContent.txContent.vLength == 0) {
|
||||
// Legacy API
|
||||
G_io_apdu_buffer[0] = 27;
|
||||
}
|
||||
else {
|
||||
// New API
|
||||
// Note that this is wrong for a large v, but the client can always recover
|
||||
G_io_apdu_buffer[0] = (v * 2) + 35;
|
||||
}
|
||||
if (info & CX_ECCINFO_PARITY_ODD) {
|
||||
G_io_apdu_buffer[0]++;
|
||||
}
|
||||
if (info & CX_ECCINFO_xGTn) {
|
||||
G_io_apdu_buffer[0] += 2;
|
||||
}
|
||||
format_signature_out(signature);
|
||||
tx = 65;
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) {
|
||||
reset_app_context();
|
||||
G_io_apdu_buffer[0] = 0x69;
|
||||
G_io_apdu_buffer[1] = 0x85;
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) {
|
||||
parserStatus_e txResult = USTREAM_FINISHED;
|
||||
txResult = continueTx(&txContext);
|
||||
switch (txResult) {
|
||||
case USTREAM_SUSPENDED:
|
||||
break;
|
||||
case USTREAM_FINISHED:
|
||||
break;
|
||||
case USTREAM_PROCESSING:
|
||||
io_seproxyhal_send_status(0x9000);
|
||||
ui_idle();
|
||||
break;
|
||||
case USTREAM_FAULT:
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
break;
|
||||
default:
|
||||
PRINTF("Unexpected parser status\n");
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
}
|
||||
|
||||
if (txResult == USTREAM_FINISHED) {
|
||||
finalizeParsing(false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_data_cancel(const bagl_element_t *e) {
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6985);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
165
src_features/signTx/ui_flow_signTx.c
Normal file
165
src_features/signTx/ui_flow_signTx.c
Normal file
@@ -0,0 +1,165 @@
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
#ifdef HAVE_UX_FLOW
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_confirm_selector_flow_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Verify",
|
||||
"selector",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_confirm_selector_flow_2_step,
|
||||
bn,
|
||||
{
|
||||
"Selector",
|
||||
strings.tmp.tmp
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_confirm_selector_flow_3_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_data_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Approve",
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_confirm_selector_flow_4_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_data_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_confirm_selector_flow [] = {
|
||||
&ux_confirm_selector_flow_1_step,
|
||||
&ux_confirm_selector_flow_2_step,
|
||||
&ux_confirm_selector_flow_3_step,
|
||||
&ux_confirm_selector_flow_4_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_confirm_parameter_flow_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Verify",
|
||||
strings.tmp.tmp2
|
||||
});
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_confirm_parameter_flow_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Parameter",
|
||||
.text = strings.tmp.tmp,
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_confirm_parameter_flow_3_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_data_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Approve",
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_confirm_parameter_flow_4_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_data_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_confirm_parameter_flow [] = {
|
||||
&ux_confirm_parameter_flow_1_step,
|
||||
&ux_confirm_parameter_flow_2_step,
|
||||
&ux_confirm_parameter_flow_3_step,
|
||||
&ux_confirm_parameter_flow_4_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
UX_FLOW_DEF_NOCB(ux_approval_tx_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_tx_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Amount",
|
||||
.text = strings.common.fullAmount
|
||||
});
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_tx_3_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Address",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_tx_4_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Max Fees",
|
||||
.text = strings.common.maxFee,
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_tx_5_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_tx_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_tx_6_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_approval_tx_data_warning_step,
|
||||
pbb,
|
||||
{
|
||||
&C_icon_warning,
|
||||
"Data",
|
||||
"Present",
|
||||
});
|
||||
|
||||
|
||||
const ux_flow_step_t * const ux_approval_tx_flow [] = {
|
||||
&ux_approval_tx_1_step,
|
||||
&ux_approval_tx_2_step,
|
||||
&ux_approval_tx_3_step,
|
||||
&ux_approval_tx_4_step,
|
||||
&ux_approval_tx_5_step,
|
||||
&ux_approval_tx_6_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
const ux_flow_step_t * const ux_approval_tx_data_warning_flow [] = {
|
||||
&ux_approval_tx_1_step,
|
||||
&ux_approval_tx_data_warning_step,
|
||||
&ux_approval_tx_2_step,
|
||||
&ux_approval_tx_3_step,
|
||||
&ux_approval_tx_4_step,
|
||||
&ux_approval_tx_5_step,
|
||||
&ux_approval_tx_6_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
126
src_features/stark_contract_deposit/ui_flow_stark_deposit.c
Normal file
126
src_features/stark_contract_deposit/ui_flow_stark_deposit.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
#include "utils.h"
|
||||
|
||||
void prepare_deposit_3() {
|
||||
uint8_t address[41];
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination, address, &sha3);
|
||||
strings.common.fullAddress[0] = '0';
|
||||
strings.common.fullAddress[1] = 'x';
|
||||
os_memmove((unsigned char *)strings.common.fullAddress+2, address, 40);
|
||||
strings.common.fullAddress[42] = '\0';
|
||||
}
|
||||
|
||||
void prepare_deposit_4() {
|
||||
snprintf(strings.common.fullAddress, 10, "%d", U4BE(dataContext.tokenContext.data, 4 + 32 + 32 - 4));
|
||||
}
|
||||
|
||||
void prepare_deposit_5() {
|
||||
uint256_t amount, amountPre, quantum;
|
||||
uint8_t decimals;
|
||||
char *ticker = (char*)PIC(chainConfig->coinName);
|
||||
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_ETH) {
|
||||
decimals = WEI_TO_ETHER;
|
||||
convertUint256BE(tmpContent.txContent.value.value, tmpContent.txContent.value.length, &amountPre);
|
||||
}
|
||||
else {
|
||||
tokenDefinition_t *token = &tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex];
|
||||
decimals = token->decimals;
|
||||
ticker = (char*)token->ticker;
|
||||
readu256BE(dataContext.tokenContext.data + 4 + 32 + 32, &amountPre);
|
||||
}
|
||||
readu256BE(dataContext.tokenContext.quantum, &quantum);
|
||||
mul256(&amountPre, &quantum, &amount);
|
||||
tostring256(&amount, 10, (char*)(G_io_apdu_buffer + 100), 100);
|
||||
strcpy(strings.common.fullAmount, ticker);
|
||||
adjustDecimals((char*)(G_io_apdu_buffer + 100), strlen((char*)(G_io_apdu_buffer + 100)), strings.common.fullAmount + strlen(ticker), 50 - strlen(ticker), decimals);
|
||||
}
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_approval_starkware_deposit_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_deposit_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Deposit",
|
||||
.text = " "
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_deposit_3_step,
|
||||
bnnn_paging,
|
||||
prepare_deposit_3(),
|
||||
{
|
||||
.title = "Contract Name",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_deposit_4_step,
|
||||
bnnn_paging,
|
||||
prepare_deposit_4(),
|
||||
{
|
||||
.title = "Token Account",
|
||||
.text = strings.common.fullAddress
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_deposit_5_step,
|
||||
bnnn_paging,
|
||||
prepare_deposit_5(),
|
||||
{
|
||||
.title = "Amount",
|
||||
.text = strings.common.fullAmount
|
||||
});
|
||||
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_deposit_6_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Max Fees",
|
||||
.text = strings.common.maxFee,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_deposit_7_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_tx_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_deposit_8_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_approval_starkware_deposit_flow [] = {
|
||||
&ux_approval_starkware_deposit_1_step,
|
||||
&ux_approval_starkware_deposit_2_step,
|
||||
&ux_approval_starkware_deposit_3_step,
|
||||
&ux_approval_starkware_deposit_4_step,
|
||||
&ux_approval_starkware_deposit_5_step,
|
||||
&ux_approval_starkware_deposit_6_step,
|
||||
&ux_approval_starkware_deposit_7_step,
|
||||
&ux_approval_starkware_deposit_8_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
136
src_features/stark_contract_escape/ui_flow_stark_escape.c
Normal file
136
src_features/stark_contract_escape/ui_flow_stark_escape.c
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
void prepare_escape_3() {
|
||||
uint8_t address[41];
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination, address, &sha3);
|
||||
strings.common.fullAddress[0] = '0';
|
||||
strings.common.fullAddress[1] = 'x';
|
||||
os_memmove((unsigned char *)strings.common.fullAddress+2, address, 40);
|
||||
strings.common.fullAddress[42] = '\0';
|
||||
}
|
||||
|
||||
void prepare_escape_4() {
|
||||
uint256_t amount, amountPre, quantum;
|
||||
uint8_t decimals;
|
||||
char *ticker = (char*)PIC(chainConfig->coinName);
|
||||
|
||||
if (dataContext.tokenContext.quantumIndex == MAX_TOKEN) {
|
||||
decimals = WEI_TO_ETHER;
|
||||
}
|
||||
else {
|
||||
tokenDefinition_t *token = &tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex];
|
||||
decimals = token->decimals;
|
||||
ticker = (char*)token->ticker;
|
||||
}
|
||||
readu256BE(dataContext.tokenContext.data + 4 + 32 + 32 + 32, &amountPre);
|
||||
readu256BE(dataContext.tokenContext.quantum, &quantum);
|
||||
mul256(&amountPre, &quantum, &amount);
|
||||
tostring256(&amount, 10, (char*)(G_io_apdu_buffer + 100), 100);
|
||||
strcpy(strings.common.fullAmount, ticker);
|
||||
adjustDecimals((char*)(G_io_apdu_buffer + 100), strlen((char*)(G_io_apdu_buffer + 100)), strings.common.fullAmount + strlen(ticker), 50 - strlen(ticker), decimals);
|
||||
}
|
||||
|
||||
void prepare_escape_5() {
|
||||
snprintf(strings.tmp.tmp, 70, "0x%.*H", 32, dataContext.tokenContext.data + 4 + 32);
|
||||
}
|
||||
|
||||
void prepare_escape_6() {
|
||||
snprintf(strings.common.fullAddress, 10, "%d", U4BE(dataContext.tokenContext.data, 4 + 32 - 4));
|
||||
}
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_approval_starkware_escape_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_escape_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Escape",
|
||||
.text = " "
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_escape_3_step,
|
||||
bnnn_paging,
|
||||
prepare_escape_3(),
|
||||
{
|
||||
.title = "Contract Name",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_escape_4_step,
|
||||
bnnn_paging,
|
||||
prepare_escape_4(),
|
||||
{
|
||||
.title = "Amount",
|
||||
.text = strings.common.fullAmount
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_escape_5_step,
|
||||
bnnn_paging,
|
||||
prepare_escape_5(),
|
||||
{
|
||||
.title = "Master Account",
|
||||
.text = strings.tmp.tmp
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_escape_6_step,
|
||||
bnnn_paging,
|
||||
prepare_escape_6(),
|
||||
{
|
||||
.title = "Token Account",
|
||||
.text = strings.common.fullAddress
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_escape_7_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Max Fees",
|
||||
.text = strings.common.maxFee,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_escape_8_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_tx_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_escape_9_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_approval_starkware_escape_flow [] = {
|
||||
&ux_approval_starkware_escape_1_step,
|
||||
&ux_approval_starkware_escape_2_step,
|
||||
&ux_approval_starkware_escape_3_step,
|
||||
&ux_approval_starkware_escape_4_step,
|
||||
&ux_approval_starkware_escape_5_step,
|
||||
&ux_approval_starkware_escape_6_step,
|
||||
&ux_approval_starkware_escape_7_step,
|
||||
&ux_approval_starkware_escape_8_step,
|
||||
&ux_approval_starkware_escape_9_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
124
src_features/stark_contract_register/ui_flow_stark_register.c
Normal file
124
src_features/stark_contract_register/ui_flow_stark_register.c
Normal file
@@ -0,0 +1,124 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
void prepare_register_3() {
|
||||
uint8_t address[41];
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination, address, &sha3);
|
||||
strings.common.fullAddress[0] = '0';
|
||||
strings.common.fullAddress[1] = 'x';
|
||||
os_memmove((unsigned char *)strings.common.fullAddress+2, address, 40);
|
||||
strings.common.fullAddress[42] = '\0';
|
||||
}
|
||||
|
||||
void prepare_register_4() {
|
||||
uint8_t privateKeyData[32];
|
||||
uint8_t address[41];
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
cx_ecfp_public_key_t publicKey;
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1, tmpCtx.transactionContext.bip32Path,
|
||||
tmpCtx.transactionContext.pathLength,
|
||||
privateKeyData, NULL);
|
||||
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
cx_ecfp_generate_pair(CX_CURVE_256K1, &publicKey, &privateKey, 1);
|
||||
os_memset(&privateKey, 0, sizeof(privateKey));
|
||||
os_memset(privateKeyData, 0, sizeof(privateKeyData));
|
||||
io_seproxyhal_io_heartbeat();
|
||||
getEthAddressStringFromKey(&publicKey, address, &sha3);
|
||||
strings.common.fullAddress[0] = '0';
|
||||
strings.common.fullAddress[1] = 'x';
|
||||
os_memmove((unsigned char *)strings.common.fullAddress+2, address, 40);
|
||||
strings.common.fullAddress[42] = '\0';
|
||||
}
|
||||
|
||||
void prepare_register_5() {
|
||||
snprintf(strings.tmp.tmp, 70, "0x%.*H", 32, dataContext.tokenContext.data + 4);
|
||||
}
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_approval_starkware_register_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_register_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Registration",
|
||||
.text = " "
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_register_3_step,
|
||||
bnnn_paging,
|
||||
prepare_register_3(),
|
||||
{
|
||||
.title = "Contract Name",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_register_4_step,
|
||||
bnnn_paging,
|
||||
prepare_register_4(),
|
||||
{
|
||||
.title = "From ETH address",
|
||||
.text = strings.common.fullAddress
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_register_5_step,
|
||||
bnnn_paging,
|
||||
prepare_register_5(),
|
||||
{
|
||||
.title = "Master account",
|
||||
.text = strings.tmp.tmp
|
||||
});
|
||||
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_register_6_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Max Fees",
|
||||
.text = strings.common.maxFee,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_register_7_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_tx_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_register_8_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_approval_starkware_register_flow [] = {
|
||||
&ux_approval_starkware_register_1_step,
|
||||
&ux_approval_starkware_register_2_step,
|
||||
&ux_approval_starkware_register_3_step,
|
||||
&ux_approval_starkware_register_4_step,
|
||||
&ux_approval_starkware_register_5_step,
|
||||
&ux_approval_starkware_register_6_step,
|
||||
&ux_approval_starkware_register_7_step,
|
||||
&ux_approval_starkware_register_8_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
void prepare_verify_escape_3() {
|
||||
uint8_t address[41];
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination, address, &sha3);
|
||||
strings.common.fullAddress[0] = '0';
|
||||
strings.common.fullAddress[1] = 'x';
|
||||
os_memmove((unsigned char *)strings.common.fullAddress+2, address, 40);
|
||||
strings.common.fullAddress[42] = '\0';
|
||||
}
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_approval_starkware_verify_escape_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_verify_escape_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Verify Escape",
|
||||
.text = " "
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_verify_escape_3_step,
|
||||
bnnn_paging,
|
||||
prepare_verify_escape_3(),
|
||||
{
|
||||
.title = "Contract Name",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_verify_escape_4_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Max Fees",
|
||||
.text = strings.common.maxFee,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_verify_escape_5_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_tx_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_verify_escape_6_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_approval_starkware_verify_escape_flow [] = {
|
||||
&ux_approval_starkware_verify_escape_1_step,
|
||||
&ux_approval_starkware_verify_escape_2_step,
|
||||
&ux_approval_starkware_verify_escape_3_step,
|
||||
&ux_approval_starkware_verify_escape_4_step,
|
||||
&ux_approval_starkware_verify_escape_5_step,
|
||||
&ux_approval_starkware_verify_escape_6_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
void prepare_verify_vault_id_2() {
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_CANCEL) {
|
||||
strcpy(strings.common.fullAddress, "Cancel Deposit");
|
||||
}
|
||||
else
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_RECLAIM) {
|
||||
strcpy(strings.common.fullAddress, "Reclaim Deposit");
|
||||
}
|
||||
else
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_FULL_WITHDRAWAL) {
|
||||
strcpy(strings.common.fullAddress, "Full Withdrawal");
|
||||
}
|
||||
else
|
||||
if (contractProvisioned == CONTRACT_STARKWARE_FREEZE) {
|
||||
strcpy(strings.common.fullAddress, "Freeze");
|
||||
}
|
||||
}
|
||||
|
||||
void prepare_verify_vault_id_3() {
|
||||
uint8_t address[41];
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination, address, &sha3);
|
||||
strings.common.fullAddress[0] = '0';
|
||||
strings.common.fullAddress[1] = 'x';
|
||||
os_memmove((unsigned char *)strings.common.fullAddress+2, address, 40);
|
||||
strings.common.fullAddress[42] = '\0';
|
||||
}
|
||||
|
||||
void prepare_verify_vault_id_4() {
|
||||
uint8_t offset = 0;
|
||||
if ((contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_CANCEL) || (contractProvisioned == CONTRACT_STARKWARE_DEPOSIT_RECLAIM)) {
|
||||
offset = 32;
|
||||
}
|
||||
snprintf(strings.common.fullAddress, 10, "%d", U4BE(dataContext.tokenContext.data, 4 + offset + 32 - 4));
|
||||
}
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_approval_starkware_verify_vault_id_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_verify_vault_id_2_step,
|
||||
bnnn_paging,
|
||||
prepare_verify_vault_id_2(),
|
||||
{
|
||||
.title = strings.common.fullAddress,
|
||||
.text = " "
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_verify_vault_id_3_step,
|
||||
bnnn_paging,
|
||||
prepare_verify_vault_id_3(),
|
||||
{
|
||||
.title = "Contract Name",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_verify_vault_id_4_step,
|
||||
bnnn_paging,
|
||||
prepare_verify_vault_id_4(),
|
||||
{
|
||||
.title = "Token Account",
|
||||
.text = strings.common.fullAddress
|
||||
});
|
||||
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_verify_vault_id_5_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Max Fees",
|
||||
.text = strings.common.maxFee,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_verify_vault_id_6_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_tx_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_verify_vault_id_7_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_approval_starkware_verify_vault_id_flow [] = {
|
||||
&ux_approval_starkware_verify_vault_id_1_step,
|
||||
&ux_approval_starkware_verify_vault_id_2_step,
|
||||
&ux_approval_starkware_verify_vault_id_3_step,
|
||||
&ux_approval_starkware_verify_vault_id_4_step,
|
||||
&ux_approval_starkware_verify_vault_id_5_step,
|
||||
&ux_approval_starkware_verify_vault_id_6_step,
|
||||
&ux_approval_starkware_verify_vault_id_7_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
void prepare_register_4();
|
||||
|
||||
void prepare_withdraw_3() {
|
||||
uint8_t address[41];
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination, address, &sha3);
|
||||
strings.common.fullAddress[0] = '0';
|
||||
strings.common.fullAddress[1] = 'x';
|
||||
os_memmove((unsigned char *)strings.common.fullAddress+2, address, 40);
|
||||
strings.common.fullAddress[42] = '\0';
|
||||
}
|
||||
|
||||
void prepare_withdraw_5() {
|
||||
char *ticker = (char*)PIC(chainConfig->coinName);
|
||||
|
||||
if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) {
|
||||
tokenDefinition_t *token = &tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex];
|
||||
ticker = (char*)token->ticker;
|
||||
}
|
||||
strcpy(strings.common.fullAmount, ticker);
|
||||
}
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_approval_starkware_withdraw_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_withdraw_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Withdrawal",
|
||||
.text = " "
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_withdraw_3_step,
|
||||
bnnn_paging,
|
||||
prepare_withdraw_3(),
|
||||
{
|
||||
.title = "Contract Name",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_withdraw_4_step,
|
||||
bnnn_paging,
|
||||
prepare_register_4(),
|
||||
{
|
||||
.title = "To Eth Address",
|
||||
.text = strings.common.fullAddress
|
||||
});
|
||||
|
||||
UX_STEP_NOCB_INIT(
|
||||
ux_approval_starkware_withdraw_5_step,
|
||||
bnnn_paging,
|
||||
prepare_withdraw_5(),
|
||||
{
|
||||
.title = "Token Symbol",
|
||||
.text = strings.common.fullAmount
|
||||
});
|
||||
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_approval_starkware_withdraw_6_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Max Fees",
|
||||
.text = strings.common.maxFee,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_withdraw_7_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_tx_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_approval_starkware_withdraw_8_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_approval_starkware_withdraw_flow [] = {
|
||||
&ux_approval_starkware_withdraw_1_step,
|
||||
&ux_approval_starkware_withdraw_2_step,
|
||||
&ux_approval_starkware_withdraw_3_step,
|
||||
&ux_approval_starkware_withdraw_4_step,
|
||||
&ux_approval_starkware_withdraw_5_step,
|
||||
&ux_approval_starkware_withdraw_6_step,
|
||||
&ux_approval_starkware_withdraw_7_step,
|
||||
&ux_approval_starkware_withdraw_8_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
65
src_features/stark_getPublicKey/cmd_stark_getPublicKey.c
Normal file
65
src_features/stark_getPublicKey/cmd_stark_getPublicKey.c
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "apdu_constants.h"
|
||||
#include "stark_utils.h"
|
||||
#include "feature_stark_getPublicKey.h"
|
||||
#ifdef TARGET_BLUE
|
||||
#include "ui_blue.h"
|
||||
#endif
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ui_flow.h"
|
||||
#endif
|
||||
|
||||
void handleStarkwareGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
UNUSED(dataLength);
|
||||
uint8_t privateKeyData[32];
|
||||
uint32_t bip32Path[MAX_BIP32_PATH];
|
||||
uint32_t i;
|
||||
uint8_t bip32PathLength = *(dataBuffer++);
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
reset_app_context();
|
||||
if ((bip32PathLength < 0x01) ||
|
||||
(bip32PathLength > MAX_BIP32_PATH)) {
|
||||
PRINTF("Invalid path\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if (p2 != 0) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
for (i = 0; i < bip32PathLength; i++) {
|
||||
bip32Path[i] = U4BE(dataBuffer, 0);
|
||||
dataBuffer += 4;
|
||||
}
|
||||
io_seproxyhal_io_heartbeat();
|
||||
starkDerivePrivateKey(bip32Path, bip32PathLength, privateKeyData);
|
||||
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
cx_ecfp_generate_pair(CX_CURVE_Stark256, &tmpCtx.publicKeyContext.publicKey, &privateKey, 1);
|
||||
os_memset(&privateKey, 0, sizeof(privateKey));
|
||||
os_memset(privateKeyData, 0, sizeof(privateKeyData));
|
||||
io_seproxyhal_io_heartbeat();
|
||||
#ifndef NO_CONSENT
|
||||
if (p1 == P1_NON_CONFIRM)
|
||||
#endif // NO_CONSENT
|
||||
{
|
||||
*tx = set_result_get_stark_publicKey();
|
||||
THROW(0x9000);
|
||||
}
|
||||
#ifndef NO_CONSENT
|
||||
else
|
||||
{
|
||||
// prepare for a UI based reply
|
||||
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, tmpCtx.publicKeyContext.publicKey.W + 1);
|
||||
ux_flow_init(0, ux_display_stark_public_flow, NULL);
|
||||
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
}
|
||||
#endif // NO_CONSENT
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
uint32_t set_result_get_stark_publicKey(void);
|
||||
|
||||
15
src_features/stark_getPublicKey/logic_stark_getPublicKey.c
Normal file
15
src_features/stark_getPublicKey/logic_stark_getPublicKey.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "feature_stark_getPublicKey.h"
|
||||
|
||||
uint32_t set_result_get_stark_publicKey() {
|
||||
uint32_t tx = 0;
|
||||
os_memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.publicKey.W, 65);
|
||||
tx += 65;
|
||||
return tx;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
#include "feature_stark_getPublicKey.h"
|
||||
|
||||
unsigned int io_seproxyhal_touch_stark_pubkey_ok(const bagl_element_t *e) {
|
||||
uint32_t tx = set_result_get_stark_publicKey();
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
49
src_features/stark_getPublicKey/ui_flow_stark_getPublicKey.c
Normal file
49
src_features/stark_getPublicKey/ui_flow_stark_getPublicKey.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
unsigned int io_seproxyhal_touch_stark_pubkey_ok(const bagl_element_t *e);
|
||||
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_display_stark_public_flow_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Verify",
|
||||
"Stark key",
|
||||
});
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_display_stark_public_flow_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Stark Key",
|
||||
.text = strings.tmp.tmp,
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_display_stark_public_flow_3_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_stark_pubkey_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Approve",
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_display_stark_public_flow_4_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_address_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_display_stark_public_flow [] = {
|
||||
&ux_display_stark_public_flow_1_step,
|
||||
&ux_display_stark_public_flow_2_step,
|
||||
&ux_display_stark_public_flow_3_step,
|
||||
&ux_display_stark_public_flow_4_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
42
src_features/stark_provideQuantum/cmd_stark_provideQuantum.c
Normal file
42
src_features/stark_provideQuantum/cmd_stark_provideQuantum.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "apdu_constants.h"
|
||||
#ifdef TARGET_BLUE
|
||||
#include "ui_blue.h"
|
||||
#endif
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ui_flow.h"
|
||||
#endif
|
||||
|
||||
void handleStarkwareProvideQuantum(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
size_t i = 0;
|
||||
tokenDefinition_t *currentToken = NULL;
|
||||
if (appState != APP_STATE_IDLE) {
|
||||
reset_app_context();
|
||||
}
|
||||
if (dataLength != 20 + 32) {
|
||||
THROW(0x6700);
|
||||
}
|
||||
if (!allzeroes(dataBuffer, 20)) {
|
||||
for(i=0; i<MAX_TOKEN; i++){
|
||||
currentToken = &tmpCtx.transactionContext.tokens[i];
|
||||
if (tmpCtx.transactionContext.tokenSet[i] && (os_memcmp(currentToken->address, dataBuffer, 20) == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == MAX_TOKEN) {
|
||||
PRINTF("Associated token not found\n");
|
||||
THROW(0x6A80);
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = MAX_TOKEN;
|
||||
}
|
||||
os_memmove(dataContext.tokenContext.quantum, dataBuffer + 20, 32);
|
||||
dataContext.tokenContext.quantumIndex = i;
|
||||
quantumSet = true;
|
||||
THROW(0x9000);
|
||||
}
|
||||
|
||||
#endif
|
||||
140
src_features/stark_sign/cmd_stark_sign.c
Normal file
140
src_features/stark_sign/cmd_stark_sign.c
Normal file
@@ -0,0 +1,140 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "apdu_constants.h"
|
||||
#include "stark_utils.h"
|
||||
#ifdef TARGET_BLUE
|
||||
#include "ui_blue.h"
|
||||
#endif
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ui_flow.h"
|
||||
#endif
|
||||
#include "poorstream.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
#define U8BE(buf, off) (uint64_t)((((uint64_t)U4BE(buf, off)) << 32) | (((uint64_t)U4BE(buf, off + 4)) & 0xFFFFFFFF))
|
||||
#define TMP_OFFSET 140
|
||||
|
||||
void handleStarkwareSignMessage(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
uint8_t privateKeyData[32];
|
||||
uint32_t i;
|
||||
uint8_t bip32PathLength = *(dataBuffer);
|
||||
uint8_t offset = 1;
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
poorstream_t bitstream;
|
||||
bool selfTransfer = false;
|
||||
// Initial checks
|
||||
if (appState != APP_STATE_IDLE) {
|
||||
reset_app_context();
|
||||
}
|
||||
if ((bip32PathLength < 0x01) ||
|
||||
(bip32PathLength > MAX_BIP32_PATH)) {
|
||||
PRINTF("Invalid path\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
switch(p1) {
|
||||
case P1_STARK_ORDER:
|
||||
if (dataLength != (20 + 32 + 20 + 32 + 4 + 4 + 8 + 8 + 4 + 4 + 1 + 4 * bip32PathLength)) {
|
||||
THROW(0x6700);
|
||||
}
|
||||
break;
|
||||
case P1_STARK_TRANSFER:
|
||||
if (dataLength != (20 + 32 + 32 + 4 + 4 + 8 + 4 + 4 + 1 + 4 * bip32PathLength)) {
|
||||
THROW(0x6700);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if (p2 != 0) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
tmpCtx.transactionContext.pathLength = bip32PathLength;
|
||||
for (i = 0; i < bip32PathLength; i++) {
|
||||
tmpCtx.transactionContext.bip32Path[i] = U4BE(dataBuffer, offset);
|
||||
PRINTF("Storing path %d %d\n", i, tmpCtx.transactionContext.bip32Path[i]);
|
||||
offset += 4;
|
||||
}
|
||||
// Discard the path to use part of dataBuffer as a temporary buffer
|
||||
os_memmove(dataBuffer, dataBuffer + offset, dataLength - offset);
|
||||
// Fail immediately if the contract is unknown
|
||||
if (!allzeroes(dataBuffer, 20) && getKnownToken(dataBuffer) == NULL) {
|
||||
PRINTF("stark - cannot process unknown token %.*H", 20, dataBuffer);
|
||||
THROW(0x6A80);
|
||||
}
|
||||
if ((p1 == P1_STARK_ORDER) && (!allzeroes(dataBuffer + 20 + 32, 20) && getKnownToken(dataBuffer + 20 + 32) == NULL)) {
|
||||
PRINTF("stark - cannot process unknown token %.*H", 20, dataBuffer + 20 + 32);
|
||||
THROW(0x6A80);
|
||||
}
|
||||
// Prepare the Stark parameters
|
||||
io_seproxyhal_io_heartbeat();
|
||||
compute_token_id(&sha3, dataBuffer, dataBuffer + 20, dataContext.starkContext.w1);
|
||||
if (p1 == P1_STARK_ORDER) {
|
||||
io_seproxyhal_io_heartbeat();
|
||||
compute_token_id(&sha3, dataBuffer + 20 + 32, dataBuffer + 20 + 32 + 20, dataContext.starkContext.w2);
|
||||
offset = 20 + 32 + 20 + 32;
|
||||
}
|
||||
else {
|
||||
os_memmove(dataContext.starkContext.w2, dataBuffer + 20 + 32, 32);
|
||||
offset = 20 + 32 + 32;
|
||||
}
|
||||
poorstream_init(&bitstream, dataContext.starkContext.w3);
|
||||
poorstream_write_bits(&bitstream, 0, 11); // padding
|
||||
poorstream_write_bits(&bitstream, (p1 == P1_STARK_ORDER ? STARK_ORDER_TYPE : STARK_TRANSFER_TYPE), 4);
|
||||
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset), 31);
|
||||
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset + 4), 31);
|
||||
poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4), 63);
|
||||
if (p1 == P1_STARK_ORDER) {
|
||||
poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4 + 8), 63);
|
||||
offset += 4 + 4 + 8 + 8;
|
||||
}
|
||||
else {
|
||||
poorstream_write_bits(&bitstream, 0, 63);
|
||||
offset += 4 + 4 + 8;
|
||||
}
|
||||
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset), 31);
|
||||
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset + 4), 22);
|
||||
|
||||
PRINTF("stark w1 %.*H\n", 32, dataContext.starkContext.w1);
|
||||
PRINTF("stark w2 %.*H\n", 32, dataContext.starkContext.w2);
|
||||
PRINTF("stark w3 %.*H\n", 32, dataContext.starkContext.w3);
|
||||
// Prepare the UI
|
||||
if (p1 == P1_STARK_ORDER) {
|
||||
io_seproxyhal_io_heartbeat();
|
||||
// amount to sell
|
||||
stark_get_amount_string(dataBuffer, dataBuffer + 20, dataBuffer + 20 + 32 + 20 + 32 + 4 + 4, (char*)(dataBuffer + TMP_OFFSET), strings.common.fullAmount);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
// amount to buy
|
||||
stark_get_amount_string(dataBuffer + 20 + 32, dataBuffer + 20 + 32 + 20, dataBuffer + 20 + 32 + 20 + 32 + 4 + 4 + 8, (char*)(dataBuffer + TMP_OFFSET), strings.common.maxFee);
|
||||
// src vault ID
|
||||
snprintf(strings.common.fullAddress, sizeof(strings.common.fullAddress), "%d", U4BE(dataBuffer, 20 + 32 + 20 + 32));
|
||||
}
|
||||
else {
|
||||
cx_ecfp_public_key_t publicKey;
|
||||
// Check if the transfer is a self transfer
|
||||
io_seproxyhal_io_heartbeat();
|
||||
starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path, bip32PathLength, privateKeyData);
|
||||
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
cx_ecfp_generate_pair(CX_CURVE_Stark256, &publicKey, &privateKey, 1);
|
||||
os_memset(&privateKey, 0, sizeof(privateKey));
|
||||
os_memset(privateKeyData, 0, sizeof(privateKeyData));
|
||||
io_seproxyhal_io_heartbeat();
|
||||
selfTransfer = (os_memcmp(publicKey.W + 1, dataBuffer + 20 + 32, 32) == 0);
|
||||
PRINTF("self transfer %d\n", selfTransfer);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
// amount to transfer
|
||||
stark_get_amount_string(dataBuffer, dataBuffer + 20, dataBuffer + 20 + 32 + 32 + 4 + 4, (char*)(dataBuffer + TMP_OFFSET), tmpContent.tmp);
|
||||
// dest vault ID
|
||||
snprintf(strings.tmp.tmp2, sizeof(strings.tmp.tmp2), "%d", U4BE(dataBuffer, 20 + 32 + 32 + 4));
|
||||
if (!selfTransfer) {
|
||||
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataBuffer + 20 + 32);
|
||||
}
|
||||
}
|
||||
ux_flow_init(0, p1 == P1_STARK_ORDER ? ux_stark_limit_order_flow : selfTransfer ?
|
||||
ux_stark_self_transfer_flow : ux_stark_transfer_flow, NULL);
|
||||
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
}
|
||||
|
||||
#endif
|
||||
28
src_features/stark_sign/ui_common_stark_sign.c
Normal file
28
src_features/stark_sign/ui_common_stark_sign.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "stark_utils.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
unsigned int io_seproxyhal_touch_stark_ok(const bagl_element_t *e) {
|
||||
uint8_t privateKeyData[32];
|
||||
uint8_t signature[72];
|
||||
uint32_t tx = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path, tmpCtx.transactionContext.pathLength, privateKeyData);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
stark_sign(signature, privateKeyData, dataContext.starkContext.w1, dataContext.starkContext.w2, dataContext.starkContext.w3);
|
||||
G_io_apdu_buffer[0] = 0;
|
||||
format_signature_out(signature);
|
||||
tx = 65;
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
#endif
|
||||
165
src_features/stark_sign/ui_flow_stark_sign.c
Normal file
165
src_features/stark_sign/ui_flow_stark_sign.c
Normal file
@@ -0,0 +1,165 @@
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
unsigned int io_seproxyhal_touch_stark_ok(const bagl_element_t *e);
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_limit_order_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_limit_order_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Limit",
|
||||
.text = "Order"
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_limit_order_3_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Trading",
|
||||
.text = "Pair"
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_limit_order_4_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Sell",
|
||||
.text = strings.common.fullAmount
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_limit_order_5_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Buy",
|
||||
.text = strings.common.maxFee
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_limit_order_6_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Token Accont",
|
||||
.text = strings.common.fullAddress
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_stark_limit_order_7_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_stark_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_stark_limit_order_8_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_stark_limit_order_flow [] = {
|
||||
&ux_stark_limit_order_1_step,
|
||||
&ux_stark_limit_order_2_step,
|
||||
&ux_stark_limit_order_3_step,
|
||||
&ux_stark_limit_order_4_step,
|
||||
&ux_stark_limit_order_5_step,
|
||||
&ux_stark_limit_order_6_step,
|
||||
&ux_stark_limit_order_7_step,
|
||||
&ux_stark_limit_order_8_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
UX_FLOW_DEF_NOCB(ux_stark_transfer_1_step,
|
||||
pnn,
|
||||
{
|
||||
&C_icon_eye,
|
||||
"Review",
|
||||
"transaction",
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_transfer_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Transfer",
|
||||
.text = " "
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_self_transfer_2_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Self",
|
||||
.text = "Transfer"
|
||||
});
|
||||
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_transfer_3_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Amount",
|
||||
.text = tmpContent.tmp
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_transfer_4_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Master Account",
|
||||
.text = strings.tmp.tmp
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_NOCB(ux_stark_transfer_5_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Token Accont",
|
||||
.text = strings.tmp.tmp2
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_stark_transfer_6_step,
|
||||
pbb,
|
||||
io_seproxyhal_touch_stark_ok(NULL),
|
||||
{
|
||||
&C_icon_validate_14,
|
||||
"Accept",
|
||||
"and send",
|
||||
});
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_stark_transfer_7_step,
|
||||
pb,
|
||||
io_seproxyhal_touch_tx_cancel(NULL),
|
||||
{
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
|
||||
const ux_flow_step_t * const ux_stark_transfer_flow [] = {
|
||||
&ux_stark_transfer_1_step,
|
||||
&ux_stark_transfer_2_step,
|
||||
&ux_stark_transfer_3_step,
|
||||
&ux_stark_transfer_4_step,
|
||||
&ux_stark_transfer_5_step,
|
||||
&ux_stark_transfer_6_step,
|
||||
&ux_stark_transfer_7_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
const ux_flow_step_t * const ux_stark_self_transfer_flow [] = {
|
||||
&ux_stark_transfer_1_step,
|
||||
&ux_stark_self_transfer_2_step,
|
||||
&ux_stark_transfer_3_step,
|
||||
&ux_stark_transfer_5_step,
|
||||
&ux_stark_transfer_6_step,
|
||||
&ux_stark_transfer_7_step,
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user