Skip to content

Commit

Permalink
feat: hardcoded jettons
Browse files Browse the repository at this point in the history
fix: tests
chore: bump version
  • Loading branch information
krigga committed Jul 25, 2024
1 parent e92bd21 commit 5edc4cb
Show file tree
Hide file tree
Showing 442 changed files with 651 additions and 65 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS)

APPNAME = "TON"
APPVERSION_M = 2
APPVERSION_N = 1
APPVERSION_N = 2
APPVERSION_P = 0
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"

Expand Down Expand Up @@ -82,6 +82,10 @@ else
endif
endif

ifneq ($(TARGET_NAME),TARGET_NANOS)
DEFINES += HAVE_HARDCODED_JETTONS
endif

DEBUG = 0
ifneq ($(DEBUG),0)
DEFINES += HAVE_PRINTF
Expand Down
6 changes: 4 additions & 2 deletions doc/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@
Use P2 to control what kind of address to present to user:
* set bit 0x01 to make address testnet only
* set bit 0x02 to use masterchain instead of basechain for the address
* set bit 0x04 to include is_v3r2 flag and subwallet_id

The bip32 path must be at least 3 elements long and must start with the prefix `m/44'/607'/`.

| CLA | INS | P1 | P2 | Lc | CData |
| --- | --- | --- | --- | --- | --- |
| 0xE0 | 0x05 | 0x00 (no display) <br> 0x01 (display) | 0x00-0x03 | 1 + 4n | `len(bip32_path) (1)` \|\|<br> `bip32_path{1} (4)` \|\|<br>`...` \|\|<br>`bip32_path{n} (4)` |
| 0xE0 | 0x05 | 0x00 (no display) <br> 0x01 (display) | 0x00-0x07 | 1 + 4n + (0 or 5) | `len(bip32_path) (1)` \|\|<br> `bip32_path{1} (4)` \|\|<br>`...` \|\|<br>`bip32_path{n} (4)` \|\|<br> (if `P2 & 0x04`) `is_v3r2 (1)` (`0x00` or `0x01`) \|\|<br> (if `P2 & 0x04`) `subwallet_id (4)` |

### Response

Expand Down Expand Up @@ -89,6 +90,7 @@ Then an arbitrary number of chunks with transaction data (see [TRANSACTION.md](.
Use P2 to control what kind of address to present to user:
* set bit 0x01 to make address testnet only
* set bit 0x02 to use masterchain instead of basechain for the address
* set bit 0x04 to include is_v3r2 flag and subwallet_id

The bip32 path must be at least 3 elements long and must start with the prefix `m/44'/607'/`.

Expand All @@ -98,7 +100,7 @@ Proofs are generated according to this [spec](https://github.com/ton-blockchain/

| CLA | INS | P1 | P2 | Lc | CData |
| --- | --- | --- | --- | --- | --- |
| 0xE0 | 0x08 | 0x01 | 0x00-0x03 | 1 + 4n + 1 + d + 8 + p | `len(bip32_path) (1)` \|\|<br> `bip32_path{1} (4)` \|\|<br>`...` \|\|<br>`bip32_path{n} (4)` \|\|<br> `len(app_domain) == d (1)` \|\|<br> `app_domain (d)` \|\|<br> `timestamp (8)` \|\|<br> `payload (p)` |
| 0xE0 | 0x08 | 0x01 | 0x00-0x03 | 1 + 4n + 1 + d + 8 + p | `len(bip32_path) (1)` \|\|<br> `bip32_path{1} (4)` \|\|<br>`...` \|\|<br>`bip32_path{n} (4)` \|\|<br> (if `P2 & 0x04`) `is_v3r2 (1)` (`0x00` or `0x01`) \|\|<br> (if `P2 & 0x04`) `subwallet_id (4)` \|\|<br> `len(app_domain) == d (1)` \|\|<br> `app_domain (d)` \|\|<br> `timestamp (8)` \|\|<br> `payload (p)` |

### Response

Expand Down
6 changes: 4 additions & 2 deletions doc/MESSAGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ transfer#0f8a7ea5 query_id:uint64 amount:(VarUInteger 16) destination:MsgAddress
### Hints
| Value | Length or type | Description |
| --- | --- | --- |
| `has_query_id` | 1 | Whether `query_id` is present |
| `query_id` | 0 or 8 | `query_id` for the message, 0 will be used if `!has_query_id` |
| `flags` | 1 | Bit +1 - whether `query_id` is present, bit +2 - whether this is a known jetton (bit +2 is not available on nano S) |
| `query_id` | 0 or 8 | `query_id` for the message, 0 will be used if not present. Present only when `flags & 1` |
| `jetton_id` | 0 or 2 | ID of the known jetton. Present only when `flags & 2` |
| `owner_workchain` | 0 or 1 | Workchain of owner. Present only when `flags & 2` |
| `amount` | `varuint` | Jetton amount |
| `destination` | `address` | Whom to transfer jettons to |
| `response_destination` | `address` | Whom to transfer the excess of TON to |
Expand Down
58 changes: 43 additions & 15 deletions src/address.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,45 +77,71 @@ const uint8_t root_header[] = {
0xd5,
0xc0};

const uint8_t v3r2_root_header[] = { 0x2, 0x1, 0x34, 0x0, 0x0, 0x0, 0x0, 0x84, 0xda, 0xfa, 0x44, 0x9f, 0x98, 0xa6, 0x98, 0x77, 0x89, 0xba, 0x23, 0x23, 0x58, 0x7, 0x2b, 0xc0, 0xf7, 0x6d, 0xc4, 0x52, 0x40, 0x2, 0xa5, 0xd0, 0x91, 0x8b, 0x9a, 0x75, 0xd2, 0xd5, 0x99 };

const uint8_t data_header[] = {
0x00,
0x51, // Cell header
0x00,
0x00,
0x00,
0x00, // Seqno
0x29,
0xa9,
0xa3,
0x17, // Wallet ID
};

const uint8_t v3r2_data_header[] = {
0x00,
0x50, // Cell header
0x00,
0x00,
0x00,
0x00, // Seqno
};

const uint8_t data_tail[] = {
0x40 // zero bit + padding
};

bool pubkey_to_hash(const uint8_t public_key[static PUBKEY_LEN], uint8_t *out, size_t out_len) {
bool pubkey_to_hash(const uint8_t public_key[static PUBKEY_LEN], const uint32_t subwallet_id, const bool is_v3r2, uint8_t *out, size_t out_len) {
if (out_len != HASH_LEN) {
return false;
}

uint8_t inner[HASH_LEN] = {0};
cx_sha256_t state;

uint8_t subwallet_buf[4];
subwallet_buf[0] = (subwallet_id >> 24) & 0xff;
subwallet_buf[1] = (subwallet_id >> 16) & 0xff;
subwallet_buf[2] = (subwallet_id >> 8) & 0xff;
subwallet_buf[3] = subwallet_id & 0xff;

// Hash init data cell bits
SAFE(cx_sha256_init_no_throw(&state));
SAFE(cx_hash_no_throw((cx_hash_t *) &state, 0, data_header, sizeof(data_header), NULL, 0));
SAFE(cx_hash_no_throw((cx_hash_t *) &state, 0, public_key, PUBKEY_LEN, NULL, 0));
SAFE(cx_hash_no_throw((cx_hash_t *) &state,
CX_LAST,
data_tail,
sizeof(data_tail),
inner,
sizeof(inner)));
if (is_v3r2) {
SAFE(cx_hash_no_throw((cx_hash_t *) &state, 0, v3r2_data_header, sizeof(v3r2_data_header), NULL, 0));
} else {
SAFE(cx_hash_no_throw((cx_hash_t *) &state, 0, data_header, sizeof(data_header), NULL, 0));
}
SAFE(cx_hash_no_throw((cx_hash_t *) &state, 0, subwallet_buf, sizeof(subwallet_buf), NULL, 0));
if (is_v3r2) {
SAFE(cx_hash_no_throw((cx_hash_t *) &state, CX_LAST, public_key, PUBKEY_LEN, inner, sizeof(inner)));
} else {
SAFE(cx_hash_no_throw((cx_hash_t *) &state, 0, public_key, PUBKEY_LEN, NULL, 0));
SAFE(cx_hash_no_throw((cx_hash_t *) &state,
CX_LAST,
data_tail,
sizeof(data_tail),
inner,
sizeof(inner)));
}

// Hash root
SAFE(cx_sha256_init_no_throw(&state));
SAFE(cx_hash_no_throw((cx_hash_t *) &state, 0, root_header, sizeof(root_header), NULL, 0));
if (is_v3r2) {
SAFE(cx_hash_no_throw((cx_hash_t *) &state, 0, v3r2_root_header, sizeof(v3r2_root_header), NULL, 0));
} else {
SAFE(cx_hash_no_throw((cx_hash_t *) &state, 0, root_header, sizeof(root_header), NULL, 0));
}
SAFE(cx_hash_no_throw((cx_hash_t *) &state, CX_LAST, inner, sizeof(inner), out, out_len));

return true;
Expand All @@ -125,6 +151,8 @@ bool address_from_pubkey(const uint8_t public_key[static PUBKEY_LEN],
const uint8_t chain,
const bool bounceable,
const bool testOnly,
const uint32_t subwallet_id,
const bool is_v3r2,
uint8_t *out,
size_t out_len) {
if (out_len < ADDRESS_LEN) {
Expand All @@ -133,7 +161,7 @@ bool address_from_pubkey(const uint8_t public_key[static PUBKEY_LEN],

uint8_t hash[HASH_LEN] = {0};

if (!pubkey_to_hash(public_key, hash, sizeof(hash))) {
if (!pubkey_to_hash(public_key, subwallet_id, is_v3r2, hash, sizeof(hash))) {
return false;
}

Expand Down
12 changes: 11 additions & 1 deletion src/address.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
* @param[in] public_key
* Pointer to byte buffer with public key.
* The public key is represented as 32 bytes.
* @param[in] subwallet_id
* Subwallet ID to be used when deriving wallet hash.
* @param[in] is_v3r2
* Whether to use wallet version V3R2 or V4.
* @param[out] out
* Pointer to output byte buffer for address.
* @param[in] out_len
Expand All @@ -20,7 +24,7 @@
* @return true if success, false otherwise.
*
*/
bool pubkey_to_hash(const uint8_t public_key[static PUBKEY_LEN], uint8_t *out, size_t out_len);
bool pubkey_to_hash(const uint8_t public_key[static PUBKEY_LEN], const uint32_t subwallet_id, const bool is_v3r2, uint8_t *out, size_t out_len);

/**
* Convert public key to address. Uses Wallet V4 contract.
Expand All @@ -34,6 +38,10 @@ bool pubkey_to_hash(const uint8_t public_key[static PUBKEY_LEN], uint8_t *out, s
* Address have to have bounceable flag set
* @param[in] testOnly
* Address have to have testnet flag set
* @param[in] subwallet_id
* Subwallet ID to be used when deriving wallet address.
* @param[in] is_v3r2
* Whether to use wallet version V3R2 or V4.
* @param[out] out
* Pointer to output byte buffer for address.
* @param[in] out_len
Expand All @@ -46,5 +54,7 @@ bool address_from_pubkey(const uint8_t public_key[static PUBKEY_LEN],
const uint8_t chain,
const bool bounceable,
const bool testOnly,
const uint32_t subwallet_id,
const bool is_v3r2,
uint8_t *out,
size_t out_len);
7 changes: 6 additions & 1 deletion src/apdu/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@
*/
#define P2_ADDR_FLAG_MASTERCHAIN 0x02

/**
* P2 bit indicating that wallet specifiers (subwallet_id and version) are present.
*/
#define P2_ADDR_FLAG_WALLET_SPECIFIERS 0x04

/**
* P2 containing all address display bits.
*/
#define P2_ADDR_FLAGS_MAX (P2_ADDR_FLAG_TESTNET | P2_ADDR_FLAG_MASTERCHAIN)
#define P2_ADDR_FLAGS_MAX (P2_ADDR_FLAG_TESTNET | P2_ADDR_FLAG_MASTERCHAIN | P2_ADDR_FLAG_WALLET_SPECIFIERS)
11 changes: 11 additions & 0 deletions src/handler/get_public_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "../common/bip32_check.h"
#include "../ui/display.h"
#include "../helper/send_response.h"
#include "../apdu/params.h"

int handler_get_public_key(uint8_t flags, buffer_t *cdata, bool display) {
explicit_bzero(&G_context, sizeof(G_context));
Expand All @@ -53,6 +54,16 @@ int handler_get_public_key(uint8_t flags, buffer_t *cdata, bool display) {
return io_send_sw(SW_BAD_STATE);
}

if (flags & P2_ADDR_FLAG_WALLET_SPECIFIERS) {
if (!buffer_read_bool(cdata, &G_context.pk_info.is_v3r2) ||
!buffer_read_u32(cdata, &G_context.pk_info.subwallet_id, BE)) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}
} else {
G_context.pk_info.subwallet_id = 698983191;
G_context.pk_info.is_v3r2 = false;
}

if (display) {
return ui_display_address(flags);
}
Expand Down
12 changes: 12 additions & 0 deletions src/proof/proof_deserialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,19 @@ bool deserialize_proof(buffer_t *cdata, uint8_t flags) {
return false;
}

if (flags & P2_ADDR_FLAG_WALLET_SPECIFIERS) {
if (!buffer_read_bool(cdata, &G_context.proof_info.is_v3r2) ||
!buffer_read_u32(cdata, &G_context.proof_info.subwallet_id, BE)) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}
} else {
G_context.proof_info.subwallet_id = 698983191;
G_context.proof_info.is_v3r2 = false;
}

if (!pubkey_to_hash(G_context.proof_info.raw_public_key,
G_context.proof_info.subwallet_id,
G_context.proof_info.is_v3r2,
G_context.proof_info.address_hash,
sizeof(G_context.proof_info.address_hash))) {
io_send_sw(SW_DISPLAY_ADDRESS_FAIL);
Expand Down
Loading

0 comments on commit 5edc4cb

Please sign in to comment.