Files
app-ethereum/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c
apaillier-ledger fcc3dd6d31 Add support for ERC-721 and ERC-1155 (v3) (#218)
* First draft for erc721 token allowance

* Split ui and provide parameters into their own files

* Print txtype when not supported

* fix compilation for erc721

* Use pluginType

* Add debug statement in compound plugin

* add debug error msg in plugin error

* Add parameter parsing for all methods

* Remove debug logs

* Add SET_APPROVAL_FOR_ALL; Add correct parsing method on contract init

* Add dst_size parameter to copy functions

* Add query contract id code

* format

* Add UIs

* update ethapp.asc

* Change setExternalPlugin to setPlugin; Add support for ERC721

* clang-format

* Fix typo Unconsistent -> Inconsistent

* Add support for 721; use extraInfo

* Add extraInfo to ethpluginQueryConractUI

* Rename extraInfo to item

* Add txFromEtherscan to tests

* Add nft key and temp padding

* Remove comments around HAVE_BYPASS_SIGNATURES

* Rename TESTING_KEY to NFT_TESTING_KEY

* Add comments regarding value of queryContractUI->item

* Fix comment regarding method selector

* Rename provideToken to provideInfo; Update plugin doc

* fix caps of eth_plugin_prepare_provide_info

* fix caps of handle_provide_info

* Use verificationFn insead of hardcoded cx_ecdsa_verify

* Add comments about nftInfo_t and tokenDefinition_t

* Add erc721 test

* Remove comment from plugin interface version

* Fix network_ticker duplicate

* Add setPlugin and provideNFTInfo to doc.asc

* Add back setExternalPlugin; implement new setPlugin

* Update plugin sdk

* Call setPlugin instead of setExternalPlugin

* setPlugin work without checking sig

* Remove printf of displayed fees

* Add working 721 test

* Finalize ERC721 and add simple test

* Display NFT address on set approval and operator

* Support set approval for all for erc721

* Finish UI for set approval for all erc721

* Move copy_parameter and copy_address to eth_plugin_internal; Add tests for erc721

* update plugin sdk

* Add erc1155 plugin and 1155 tests placeholder

* Add restriction for AWS key and setPlugin

* Add NOT_OLD_INTERNAL variant; Add erc_1155_plugin_call

* Fixed compilation warnings (function pointer casting)

Co-authored-by: pscott <scott.piriou@ledger.fr>
2021-11-22 14:39:36 +01:00

212 lines
7.0 KiB
C

#include "shared_context.h"
#include "apdu_constants.h"
#include "ui_flow.h"
#include "tokens.h"
#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[INT256_LENGTH];
cx_sha256_t sha256;
cx_ecfp_public_key_t tokenKey;
cx_sha256_init(&sha256);
tmpCtx.transactionContext.currentItemIndex =
(tmpCtx.transactionContext.currentItemIndex + 1) % MAX_ITEMS;
tokenDefinition_t *token =
&tmpCtx.transactionContext.tokens[tmpCtx.transactionContext.currentItemIndex];
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);
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);
memmove(token->contractName,
workBuffer + offset,
MIN(contractNameLength, sizeof(token->contractName) - 1));
token->contractName[MIN(contractNameLength, sizeof(token->contractName) - 1)] = '\0';
offset += contractNameLength;
dataLength -= contractNameLength;
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,
LEDGER_SIGNATURE_PUBLIC_KEY,
sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
&tokenKey);
if (!cx_ecdsa_verify(&tokenKey,
CX_LAST,
CX_SHA256,
hash,
32,
workBuffer + offset,
dataLength)) {
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid token signature\n");
THROW(0x6A80);
#endif
}
tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentItemIndex] = 1;
THROW(0x9000);
}
#else
void handleProvideErc20TokenInformation(uint8_t p1,
uint8_t p2,
uint8_t *workBuffer,
uint16_t dataLength,
unsigned int *flags,
__attribute__((unused)) unsigned int *tx) {
UNUSED(p1);
UNUSED(p2);
UNUSED(flags);
uint32_t offset = 0;
uint8_t tickerLength;
uint32_t chainId;
uint8_t hash[INT256_LENGTH];
cx_ecfp_public_key_t tokenKey;
tmpCtx.transactionContext.currentItemIndex =
(tmpCtx.transactionContext.currentItemIndex + 1) % MAX_ITEMS;
tokenDefinition_t *token =
&tmpCtx.transactionContext.extraInfo[tmpCtx.transactionContext.currentItemIndex].token;
PRINTF("Provisioning currentItemIndex %d\n", tmpCtx.transactionContext.currentItemIndex);
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);
memmove(token->ticker, workBuffer + offset, tickerLength);
token->ticker[tickerLength] = ' ';
token->ticker[tickerLength + 1] = '\0';
offset += tickerLength;
dataLength -= tickerLength;
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 != ETHEREUM_MAINNET_CHAINID) && (chainConfig->chainId != chainId)) {
PRINTF("ChainId token mismatch: %d vs %d\n", chainConfig->chainId, chainId);
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 (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,
LEDGER_SIGNATURE_PUBLIC_KEY,
sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
&tokenKey);
if (!cx_ecdsa_verify(&tokenKey,
CX_LAST,
CX_SHA256,
hash,
32,
workBuffer + offset,
dataLength)) {
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid token signature\n");
THROW(0x6A80);
#endif
}
}
#else
cx_ecfp_init_public_key(CX_CURVE_256K1,
LEDGER_SIGNATURE_PUBLIC_KEY,
sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
&tokenKey);
if (!cx_ecdsa_verify(&tokenKey,
CX_LAST,
CX_SHA256,
hash,
32,
workBuffer + offset,
dataLength)) {
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid token signature\n");
THROW(0x6A80);
#endif
}
#endif
tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentItemIndex] = 1;
THROW(0x9000);
}
#endif