Skip to content

Commit

Permalink
Merge pull request #8 from ton-blockchain/develop
Browse files Browse the repository at this point in the history
Version 2.1.0
  • Loading branch information
fbeutin-ledger authored May 29, 2024
2 parents 0808a63 + 5ca0490 commit e92bd21
Show file tree
Hide file tree
Showing 738 changed files with 1,782 additions and 60 deletions.
2 changes: 1 addition & 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 = 0
APPVERSION_N = 1
APPVERSION_P = 0
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"

Expand Down
22 changes: 22 additions & 0 deletions doc/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
| `SIGN_TX` | 0x06 | Sign transaction given BIP32 path and raw transaction |
| `GET_ADDRESS_PROOF` | 0x08 | Sign an address proof in TON Connect 2 compliant format given BIP32 path and proof parameters |
| `SIGN_DATA` | 0x09 | Sign custom data in TON Connect 2 compliant format |
| `GET_APP_SETTINGS` | 0x0A | Get app settings |

## GET_VERSION

Expand Down Expand Up @@ -129,6 +130,26 @@ Then an arbitrary number of chunks with serialized custom data (see [CUSTOM_DATA
| --- | --- | --- |
| 98 | 0x9000 | `len(signature) (1)` \|\| <br> `signature (64)` \|\| <br> `len(hash) (1)` \|\| <br> `hash (32)` \|\||

## GET_APP_SETTINGS

### Command

| CLA | INS | P1 | P2 | Lc | CData |
| --- | --- | --- | --- | --- | --- |
| 0xE0 | 0x0A | 0x00 | 0x00 | 0x00 | - |

### Response

True/false settings are sent as bitfields, currently all settings fit in one byte, future versions may add additional flags to that byte or add new bytes.

In the current version, `flags` has:
- bit `0x01` set if blind signing is enabled
- bit `0x02` set if expert mode is enabled

| Response length (bytes) | SW | RData |
| --- | --- | --- |
| 1 | 0x9000 | `flags (1)` |

## Status Words

| SW | SW name | Description |
Expand All @@ -149,4 +170,5 @@ Then an arbitrary number of chunks with serialized custom data (see [CUSTOM_DATA
| 0xB008 | `SW_SIGNATURE_FAIL` | Signature of raw transaction failed |
| 0xB00B | `SW_REQUEST_TOO_LONG` | The request is too long |
| 0xB0BD | `SW_BAD_BIP32_PATH` | The bip32 derivation path is invalid |
| 0xBD00 | `SW_BLIND_SIGNING_DISABLED` | A blind transaction was requested, but blind signing is disabled |
| 0x9000 | `OK` | Success |
2 changes: 1 addition & 1 deletion doc/CUSTOM_DATA.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ text#_ {n:#} data:(SnakeData ~n) = Text;
Ledger request format:
| Value | Length or type | Description |
| --- | --- | --- |
| `message` | 0-250 | ASCII-only message |
| `message` | 0-120 | ASCII-only message |

## App data (0x54b58535)

Expand Down
195 changes: 195 additions & 0 deletions doc/MESSAGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ This list contains a number of messages that ledger could assemble and display c
| --- | --- | --- |
| 0x00 | Message with comment | Typical transaction with a comment |
| 0x01 | Jetton transfer | [TEP-74 transfer message](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md#1-transfer) |
| 0x02 | NFT transfer | [TEP-62 transfer message](https://github.com/ton-blockchain/TEPs/blob/master/text/0062-nft-standard.md#1-transfer) |
| 0x03 | Jetton burn | [TEP-74 burn message](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md#2-burn) |
| 0x04 | Add whitelist | [Vesting add whitelist message](https://github.com/ton-blockchain/vesting-contract?tab=readme-ov-file#whitelist) |
| 0x05 | Single Nominator withdraw | [Single nominator withdraw message](https://github.com/orbs-network/single-nominator/tree/main?tab=readme-ov-file#1-withdraw) |
| 0x06 | Single Nominator change validator address | [Single nominator change validator message](https://github.com/orbs-network/single-nominator/tree/main?tab=readme-ov-file#2-change-validator) |
| 0x07 | Tonstakers deposit | [Tonstakers deposit message](https://github.com/ton-blockchain/liquid-staking-contract/blob/be2ee6d1e746bd2bb0f13f7b21537fb30ef0bc3b/contracts/interaction.tlb#L52) |
| 0x08 | Jetton DAO vote for proposal | [Jetton DAO vote for proposal message](https://github.com/EmelyanenkoK/jetton_dao/blob/02fed5d124effd57ea50be77044b209ad800a621/contracts/voting.tlb#L61) |
| 0x09 | Change DNS record | [Change DNS record message](https://github.com/ton-blockchain/dns-contract/blob/d08131031fb659d2826cccc417ddd9b98476f814/func/nft-item.fc#L204) |
| 0x0A | Token bridge pay for swap | [Token bridge pay for swap message](https://github.com/ton-blockchain/token-bridge-func/blob/3346a901e3e8e1a1e020fac564c845db3220c238/src/func/jetton-bridge/op-codes.fc#L20) |

# 0x00: Message with comment

Expand Down Expand Up @@ -46,3 +55,189 @@ transfer#0f8a7ea5 query_id:uint64 amount:(VarUInteger 16) destination:MsgAddress
| `forward_amount` | `varuint` | Amount of TON to forward to the receiver |
| `has_forward_payload` | 1 | Whether `forward_payload` is present |
| `forward_payload` | 0 or `cell_ref` | `forward_payload` for the message |

# 0x02: NFT transfer

### TL-B
```
transfer#5fcc3d14 query_id:uint64 new_owner:MsgAddress response_destination:MsgAddress custom_payload:(Maybe ^Cell) forward_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell) = InternalMsgBody;
```

### 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` |
| `new_owner` | `address` | Whom to transfer jettons to |
| `response_destination` | `address` | Whom to transfer the excess of TON to |
| `has_custom_payload` | 1 | Whether `custom_payload` is present |
| `custom_payload` | 0 or `cell_ref` | `custom_payload` for the message |
| `forward_amount` | `varuint` | Amount of TON to forward to the receiver |
| `has_forward_payload` | 1 | Whether `forward_payload` is present |
| `forward_payload` | 0 or `cell_ref` | `forward_payload` for the message |

# 0x03: Jetton burn

### TL-B
```
burn#595f07bc query_id:uint64 amount:(VarUInteger 16)
response_destination:MsgAddress custom_payload:(Maybe ^Cell)
= InternalMsgBody;
```

### 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` |
| `amount` | `varuint` | Jetton amount |
| `response_destination` | `address` | Whom to transfer the excess of TON to |
| `custom_payload_type` | 1 | 0 - none, 1 - `cell_ref`, 2 - `cell_inline` |
| `custom_payload` | 0 or `cell_ref` or `cell_inline` | `custom_payload` for the message |

# 0x04: Add whitelist

### TL-B
```
add_whitelist#7258a69b query_id:uint64 address:MsgAddress = InternalMsgBody;
```

### 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` |
| `address` | `address` | Whom to add to the whitelist |

# 0x05: Single Nominator withdraw

### TL-B
```
withdraw#1000 query_id:uint64 amount:Coins = InternalMsgBody;
```

### 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` |
| `amount` | `varuint` | Amount to withdraw |

# 0x06: Single Nominator change validator address

### TL-B
```
change_validator_adddress#1001 query_id:uint64 new_validator_address:MsgAddress = InternalMsgBody;
```

### 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` |
| `address` | `address` | New validator address |

# 0x07: Tonstakers deposit

### TL-B
```
deposit#47d54391 query_id:uint64 app_id:uint64 = InternalMsgBody;
```
or
```
deposit#47d54391 query_id:uint64 = InternalMsgBody;
```

### 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` |
| `has_app_id` | 1 | Whether `app_id` is present |
| `app_id` | 0 or 8 | `app_id` for the message, will not be stored if `!has_app_id` |

# 0x08: Jetton DAO vote for proposal

### TL-B
```
vote#69fb306c query_id:uint64 voting_address:MsgAddressInt expiration_date:uint48 vote:Bool need_confirmation:Bool = InternalMsgBody;
```

### 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` |
| `voting_address` | `address` | Voting address |
| `expiration_date` | 6 | Expiration timestamp |
| `vote` | 1 | Vote flag |
| `need_confirmation` | 1 | Need confirmation flag |

# 0x09: Change DNS record

### TL-B
```
change_dns_record#4eb1f0f9 query_id:uint64 key:uint256 = InternalMsgBody;
```
or
```
change_dns_record#4eb1f0f9 query_id:uint64 key:uint256 value:^Cell = InternalMsgBody;
```

### 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` |
| `has_value` | 1 | Whether to set the value. If 0, the record will be deleted |
| `record_type` | 1 | Record type (see below for available types) |
| `record_data` | ? | Continued record data, depends on record type (see below for types) |

### Record types

#### 0x00: Wallet

`key` is `sha256("wallet")` (will be set by the device automatically).
`record_data` layout (if `has_value`):
| Value | Length or type | Description |
| --- | --- | --- |
| `address` | `address` | Wallet address |
| `has_capabilities` | 1 | Whether capabilities should be stored |
| `is_wallet` | 0 or 1 | Whether to store the `is_wallet` capability. Only present if `has_capabilities` |

If `!has_value`, then `record_data` is empty (0 bytes long)

##### TL-B
```
cap_is_wallet#2177 = SmcCapability;
cap_list_nil$0 = SmcCapList;
cap_list_next$1 head:SmcCapability tail:SmcCapList = SmcCapList;
dns_smc_address#9fd3 smc_addr:MsgAddressInt flags:(## 8) { flags <= 1 }
cap_list:flags . 0?SmcCapList = DNSRecord;
```

#### 0x01: Unknown

Used for unknown keys. Key will be converted to base64 and displayed, value cell's hash will be converted to base64 and displayed. The key will not be hashed again.

`record_data` layout:
| Value | Length or type | Description |
| --- | --- | --- |
| `key` | 32 | Record key |
| `value` | 0 or `cell_ref` | Value cell. Only present if `has_value` |

# 0x0A: Token bridge pay for swap

### TL-B
```
pay_swap#8 query_id:uint64 swap_id:uint256 = InternalMsgBody;
```

### 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` |
| `swap_id` | 32 | The swap ID |
12 changes: 9 additions & 3 deletions doc/TRANSACTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ Address is serialized by appending a single byte of chain - 0x00 or 0xff and the

## Cells

`Cell` is a fundamental data type used in TON, and everything is stored using it. A Cell can store up to 1023 bits, and up to 4 references to other cells (which themselves can store 4 more references each and so on). When hashing a Cell for signing, in order to reference another cell, only two of its properties need to be known - its depth and its hash. We define a format to serialize cell references in requests: 2 bytes for the max depth, and 32 bytes for the hash, 34 in total. We shall name this format `cell_ref`.
`Cell` is a fundamental data type used in TON, and everything is stored using it. A Cell can store up to 1023 bits, and up to 4 references to other cells (which themselves can store 4 more references each and so on).

When hashing a Cell for signing, in order to reference another cell, only two of its properties need to be known - its depth and its hash. We define a format to serialize cell references in requests: 2 bytes for the max depth, and 32 bytes for the hash, 34 in total. We shall name this format `cell_ref`.

We shall also have another format for cells - 1 byte for length in bytes (n) and this many bytes as its contents, so n+1 bytes total. Such format may be used to display the stored data in hex, which is useful in a few situations. The cell will be hashed on the device. A non-integer amount of bytes cannot be stored that way. This type shall be named `cell_inline`. Cells of this type will be displayed as their data in hex. Currently, `cell_inline` has a limitation of max 32 bytes as data.

## Transaction request structure

| Field | Size (bytes) or type | Description |
| --- | :---: | --- |
| `tag` | 1 | 0x00. Reserved for future. |
| `tag` | 1 | 0x00 for app versions <2.1.0, 0x00 or 0x01 for app versions >=2.1.0. Higher values enable more features |
| `subwallet_id` | 0 or 4 | Subwallet id. Only present when `tag == 0x01` |
| `include_wallet_op` | 0 or 1 | Whether to include the 8-bit wallet op (0x01 to include, 0x00 to not include). Only present when `tag == 0x01` |
| `seqno` | 4 | A sequence number used to prevent message replay |
| `timeout` | 4 | Message timeout |
| `value` | `varuint` | The amount in nanotons to send to the destination address encoded as described above |
Expand All @@ -46,7 +52,7 @@ Note that `payload` may be passed without `hints`, but `hints` cannot be passed
| `has_payload` | `has_hints` | Transaction type |
| --- | --- | --- |
| &cross; | &cross; | A simple transfer without any payload |
| &check; | &cross; | An invalid request, an error will be thrown |
| &check; | &cross; | Blind transaction signing, Ledger will display a warning and the payload hash but none of the message fields other than recipient and amount of TON transferred |
| &check; | &check; | A transaction of some known types, see [MESSAGES.md](./MESSAGES.md) to learn about known types. Ledger will display all important fields |
| &cross; | &check; | An invalid request, an error will be thrown |

Expand Down
9 changes: 8 additions & 1 deletion ledger_app.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
[app]
build_directory = "./"
sdk = "C"
devices = ["nanos", "nanox", "nanos+"]
devices = ["nanos", "nanox", "nanos+", "stax"]

[use_cases]
debug = "DEBUG=1"

[tests]
unit_directory = "./unit-tests/"
pytest_directory = "./tests/"
7 changes: 7 additions & 0 deletions src/apdu/dispatcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "../handler/get_public_key.h"
#include "../handler/sign_tx.h"
#include "../handler/sign_data.h"
#include "../handler/get_app_settings.h"

int apdu_dispatcher(const command_t *cmd) {
if (cmd->cla != CLA) {
Expand Down Expand Up @@ -132,6 +133,12 @@ int apdu_dispatcher(const command_t *cmd) {
buf.offset = 0;

return handler_sign_data(&buf, (bool) (cmd->p2 & P2_FIRST), (bool) (cmd->p2 & P2_MORE));
case GET_APP_SETTINGS:
if (cmd->p1 != P1_NONE || cmd->p2 != P2_NONE) {
return io_send_sw(SW_WRONG_P1P2);
}

return handler_get_app_settings();
default:
return io_send_sw(SW_INS_NOT_SUPPORTED);
}
Expand Down
2 changes: 1 addition & 1 deletion src/common/bits.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void BitString_storeCoinsBuf(BitString_t* self, uint8_t* v, uint8_t len) {
BitString_storeBuffer(self, v, len);
}

void BitString_storeBuffer(BitString_t* self, uint8_t* v, uint8_t length) {
void BitString_storeBuffer(BitString_t* self, const uint8_t* v, uint8_t length) {
for (int i = 0; i < length; i++) {
BitString_storeUint(self, v[i], 8);
}
Expand Down
2 changes: 1 addition & 1 deletion src/common/bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ void BitString_storeBit(BitString_t* self, int8_t v);
void BitString_storeUint(BitString_t* self, uint64_t v, uint8_t bits);
void BitString_storeCoins(BitString_t* self, uint64_t v);
void BitString_storeCoinsBuf(BitString_t* self, uint8_t* v, uint8_t len);
void BitString_storeBuffer(BitString_t* self, uint8_t* v, uint8_t length);
void BitString_storeBuffer(BitString_t* self, const uint8_t* v, uint8_t length);
void BitString_storeAddress(BitString_t* self, uint8_t chain, uint8_t* hash);
void BitString_storeAddressNull(BitString_t* self);
void BitString_finalize(BitString_t* self);
15 changes: 15 additions & 0 deletions src/common/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,21 @@ bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness)
return true;
}

bool buffer_read_u48(buffer_t *buffer, uint64_t *value, endianness_t endianness) {
if (!buffer_can_read(buffer, 6)) {
*value = 0;

return false;
}

*value = ((endianness == BE) ? read_u48_be(buffer->ptr, buffer->offset)
: read_u48_le(buffer->ptr, buffer->offset));

buffer_seek_cur(buffer, 6);

return true;
}

bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, size_t out_len) {
if (!bip32_path_read(buffer->ptr + buffer->offset, buffer_remaining(buffer), out, out_len)) {
return false;
Expand Down
15 changes: 15 additions & 0 deletions src/common/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,21 @@ bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness)
*/
bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness);

/**
* Read 6 bytes from buffer into uint64_t.
*
* @param[in,out] buffer
* Pointer to input buffer struct.
* @param[out] value
* Pointer to 64-bit unsigned integer read from buffer.
* @param[in] endianness
* Either BE (Big Endian) or LE (Little Endian).
*
* @return true if success, false otherwise.
*
*/
bool buffer_read_u48(buffer_t *buffer, uint64_t *value, endianness_t endianness);

/**
* Read 8 bytes from buffer into uint64_t.
*
Expand Down
Loading

0 comments on commit e92bd21

Please sign in to comment.