@ton-community/ton-ledger 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +148 -0
- package/dist/TonTransport.d.ts +74 -0
- package/dist/TonTransport.js +408 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/utils/getInit.d.ts +6 -0
- package/dist/utils/getInit.js +15 -0
- package/dist/utils/ledgerWriter.d.ts +9 -0
- package/dist/utils/ledgerWriter.js +45 -0
- package/dist/utils/ledgerWriter.spec.d.ts +1 -0
- package/dist/utils/ledgerWriter.spec.js +41 -0
- package/package.json +51 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
All notable changes to this project will be documented in this file.
|
|
3
|
+
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [4.0.0] - 2023-06-09
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Added payload types for NFT and Jetton transfers
|
|
12
|
+
- Added TON Connect 2.0 address proof request
|
|
13
|
+
|
|
14
|
+
### Removed
|
|
15
|
+
|
|
16
|
+
- Removed old payload types except for comment and unsafe
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
- Changed APDU format to be the same as the latest embedded app version (breaking change)
|
|
22
|
+
|
|
23
|
+
## [3.0.0] - 2023-01-08
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- Migration to `ton-core`
|
|
28
|
+
|
|
29
|
+
## [2.3.2]
|
|
30
|
+
|
|
31
|
+
- Update documentation
|
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# TON Ledger Library
|
|
2
|
+
|
|
3
|
+
This library allows you to connect to a ledger device and with with TON from browser (only Chrome), NodeJS and React Native.
|
|
4
|
+
|
|
5
|
+
## How to install
|
|
6
|
+
|
|
7
|
+
To add library to your project execute:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
yarn add ton-ledger
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Connecting to a Device
|
|
14
|
+
|
|
15
|
+
First you need to select transport library for you environment.
|
|
16
|
+
|
|
17
|
+
Browser:
|
|
18
|
+
* [@ledgerhq/hw-transport-webhid](https://www.npmjs.com/package/@ledgerhq/hw-transport-webhid)
|
|
19
|
+
* [@ledgerhq/hw-transport-webusb](https://www.npmjs.com/package/@ledgerhq/hw-transport-webusb)
|
|
20
|
+
|
|
21
|
+
Node:
|
|
22
|
+
* [@ledgerhq/hw-transport-node-ble](https://www.npmjs.com/package/@ledgerhq/hw-transport-node-ble)
|
|
23
|
+
* [@ledgerhq/hw-transport-node-hid](https://www.npmjs.com/package/@ledgerhq/hw-transport-node-hid)
|
|
24
|
+
* [@ledgerhq/hw-transport-node-hid-noevents](https://www.npmjs.com/package/@ledgerhq/hw-transport-node-hid-noevents)
|
|
25
|
+
* [@ledgerhq/hw-transport-node-hid-singleton](https://www.npmjs.com/package/@ledgerhq/hw-transport-node-hid-singleton)
|
|
26
|
+
|
|
27
|
+
React Native:
|
|
28
|
+
* [@ledgerhq/hw-transport-web-ble](https://www.npmjs.com/package/@ledgerhq/hw-transport-web-ble)
|
|
29
|
+
|
|
30
|
+
After connecting to a device create a TonTransport instance:
|
|
31
|
+
```typescript
|
|
32
|
+
import { TonTransport } from 'ton-ledger';
|
|
33
|
+
let transport = new TonTransport(device);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Deriviation Path
|
|
37
|
+
|
|
38
|
+
For hardware wallets you need to specify deriviation path of your account for TON it is specified as:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
function pathForAccount(testnet: boolean, workchain: number, account: number) {
|
|
42
|
+
let network = testnet ? 1 : 0;
|
|
43
|
+
let chain = workchain === -1 ? 255 : 0;
|
|
44
|
+
return [44, 607, network, chain, account, 0]; // Last zero is reserved for alternative wallet contracts
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
You can specify any path that starts with `[44, 607]`, but it could be incompatible with other apps.
|
|
49
|
+
|
|
50
|
+
## Get an Address and Public Key
|
|
51
|
+
|
|
52
|
+
To get an address without confimration on device you can perform next things:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
let testnet = true;
|
|
56
|
+
let workchain = 0;
|
|
57
|
+
let accountIndex = 0;
|
|
58
|
+
let bounceable = false;
|
|
59
|
+
let path = pathForAccount(testnet, workchain, accountIndex);
|
|
60
|
+
let response = await transport.getAddress(path, { chain, bounceable, testOnly: testnet });
|
|
61
|
+
let publiKey: Buffer = response.publicKey;
|
|
62
|
+
let address: string = response.address;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Validate Address
|
|
66
|
+
|
|
67
|
+
The same as getting address, but returns address and key only when user confirms that address on the screen is correct. This method usually used after the non-confirming one and displaying address in dApp ad then requesting address validation.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
let testnet = true;
|
|
71
|
+
let workchain = 0;
|
|
72
|
+
let accountIndex = 0;
|
|
73
|
+
let bounceable = false;
|
|
74
|
+
let path = pathForAccount(testnet, workchain, accountIndex);
|
|
75
|
+
let response = await transport.validateAddress(path, { chain, bounceable, testOnly: testnet });
|
|
76
|
+
let publiKey: Buffer = response.publicKey;
|
|
77
|
+
let address: string = response.address;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Sign simple transaction
|
|
81
|
+
|
|
82
|
+
Ledger Nanoapp works with Wallet v4 for now, we recommend you to continue to use it:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { WalletV4Contract, WalletV4Source } from 'ton';
|
|
86
|
+
import { TonPayloadFormat } from 'ton-ledger';
|
|
87
|
+
import { TonClient, Address, SendMode, toNano } from 'ton-core';
|
|
88
|
+
|
|
89
|
+
let client = new TonClient({ endpoint: 'https://toncenter.com/api/v2/jsonRPC' });
|
|
90
|
+
let source = WalletV4Source.create({ workchain: 0, publicKey: deviceAddress.publicKey });
|
|
91
|
+
let contract = new WalletV4Contract(address, source);
|
|
92
|
+
let seqno = await contract.getSeqNo();
|
|
93
|
+
|
|
94
|
+
// Parameters
|
|
95
|
+
let path: number[]; // Account path from above
|
|
96
|
+
let to: Address = Address.parse('...'); // Destination
|
|
97
|
+
let amount: bigint = toNano('100'); // Send 100 TON
|
|
98
|
+
let sendMode = SendMode.IGNORE_ERRORS | SendMode.PAY_GAS_SEPARATLY;
|
|
99
|
+
let timeout = Math.floor((Date.now() / 1000) + 60);
|
|
100
|
+
let bounce = false;
|
|
101
|
+
let payload: TonPayloadFormat | null = null; // See below
|
|
102
|
+
|
|
103
|
+
// Signing on device
|
|
104
|
+
let signed = await transport.signTransaction(path, {
|
|
105
|
+
to,
|
|
106
|
+
sendMode,
|
|
107
|
+
amount,
|
|
108
|
+
seqno,
|
|
109
|
+
timeout: Math.floor((Date.now() / 1000) + 60),
|
|
110
|
+
bounce,
|
|
111
|
+
payload: payload ? payload : undefined
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Send transaction to the network
|
|
115
|
+
await c.sendExternalMessage(contract, signed);
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Payload formats
|
|
120
|
+
|
|
121
|
+
Usually you want to perform transactions with some payload. Ledger's NanoApp currently supports 2 stable commands, all other are outdated or unstable:
|
|
122
|
+
|
|
123
|
+
### Transaction with a comment
|
|
124
|
+
Comments are limited to ASCII-only symbols and 127 letters. Anything above would be automatically downgraded to Blind Signing Mode that you want to avoid at all cost.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
let payload: TonPayloadFormat = {
|
|
128
|
+
type: 'comment',
|
|
129
|
+
text: 'Deposit'
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Unsafe with custom payload
|
|
134
|
+
|
|
135
|
+
This payload allows you to send arbitrary message, this is considered as Blind Signing Mode and only hash of your transaction would be shown to a user.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
let cell: Cell = ...
|
|
139
|
+
let message = new CellMessage(cell);
|
|
140
|
+
let payload: TonPayloadFormat = {
|
|
141
|
+
type: 'unsafe',
|
|
142
|
+
message
|
|
143
|
+
};
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
# License
|
|
147
|
+
|
|
148
|
+
MIT
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
3
|
+
import { Address, Cell, SendMode, StateInit } from "ton-core";
|
|
4
|
+
export type TonPayloadFormat = {
|
|
5
|
+
type: 'unsafe';
|
|
6
|
+
message: Cell;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'comment';
|
|
9
|
+
text: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'jetton-transfer';
|
|
12
|
+
queryId: bigint | null;
|
|
13
|
+
amount: bigint;
|
|
14
|
+
decimals: number;
|
|
15
|
+
ticker: string;
|
|
16
|
+
destination: Address;
|
|
17
|
+
responseDestination: Address;
|
|
18
|
+
customPayload: Cell | null;
|
|
19
|
+
forwardAmount: bigint;
|
|
20
|
+
forwardPayload: Cell | null;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'nft-transfer';
|
|
23
|
+
queryId: bigint | null;
|
|
24
|
+
newOwner: Address;
|
|
25
|
+
responseDestination: Address;
|
|
26
|
+
customPayload: Cell | null;
|
|
27
|
+
forwardAmount: bigint;
|
|
28
|
+
forwardPayload: Cell | null;
|
|
29
|
+
};
|
|
30
|
+
export declare class TonTransport {
|
|
31
|
+
#private;
|
|
32
|
+
readonly transport: Transport;
|
|
33
|
+
constructor(transport: Transport);
|
|
34
|
+
isAppOpen(): Promise<boolean>;
|
|
35
|
+
getVersion(): Promise<string>;
|
|
36
|
+
getAddress(path: number[], opts?: {
|
|
37
|
+
testOnly?: boolean;
|
|
38
|
+
bounceable?: boolean;
|
|
39
|
+
chain?: number;
|
|
40
|
+
}): Promise<{
|
|
41
|
+
address: string;
|
|
42
|
+
publicKey: Buffer;
|
|
43
|
+
}>;
|
|
44
|
+
validateAddress(path: number[], opts?: {
|
|
45
|
+
testOnly?: boolean;
|
|
46
|
+
bounceable?: boolean;
|
|
47
|
+
chain?: number;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
address: string;
|
|
50
|
+
publicKey: Buffer;
|
|
51
|
+
}>;
|
|
52
|
+
getAddressProof(path: number[], params: {
|
|
53
|
+
domain: string;
|
|
54
|
+
timestamp: number;
|
|
55
|
+
payload: Buffer;
|
|
56
|
+
}, opts?: {
|
|
57
|
+
testOnly?: boolean;
|
|
58
|
+
bounceable?: boolean;
|
|
59
|
+
chain?: number;
|
|
60
|
+
}): Promise<{
|
|
61
|
+
signature: Buffer;
|
|
62
|
+
hash: Buffer;
|
|
63
|
+
}>;
|
|
64
|
+
signTransaction: (path: number[], transaction: {
|
|
65
|
+
to: Address;
|
|
66
|
+
sendMode: SendMode;
|
|
67
|
+
seqno: number;
|
|
68
|
+
timeout: number;
|
|
69
|
+
bounce: boolean;
|
|
70
|
+
amount: bigint;
|
|
71
|
+
stateInit?: StateInit;
|
|
72
|
+
payload?: TonPayloadFormat;
|
|
73
|
+
}) => Promise<Cell>;
|
|
74
|
+
}
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TonTransport = void 0;
|
|
4
|
+
const ton_core_1 = require("ton-core");
|
|
5
|
+
const ton_crypto_1 = require("ton-crypto");
|
|
6
|
+
const teslabot_1 = require("teslabot");
|
|
7
|
+
const ledgerWriter_1 = require("./utils/ledgerWriter");
|
|
8
|
+
const getInit_1 = require("./utils/getInit");
|
|
9
|
+
const LEDGER_SYSTEM = 0xB0;
|
|
10
|
+
const LEDGER_CLA = 0xe0;
|
|
11
|
+
const INS_VERSION = 0x03;
|
|
12
|
+
const INS_ADDRESS = 0x05;
|
|
13
|
+
const INS_PROOF = 0x08;
|
|
14
|
+
function chunks(buf, n) {
|
|
15
|
+
const nc = Math.ceil(buf.length / n);
|
|
16
|
+
const cs = [];
|
|
17
|
+
for (let i = 0; i < nc; i++) {
|
|
18
|
+
cs.push(buf.subarray(i * n, (i + 1) * n));
|
|
19
|
+
}
|
|
20
|
+
return cs;
|
|
21
|
+
}
|
|
22
|
+
class TonTransport {
|
|
23
|
+
transport;
|
|
24
|
+
#lock = new teslabot_1.AsyncLock();
|
|
25
|
+
constructor(transport) {
|
|
26
|
+
this.transport = transport;
|
|
27
|
+
}
|
|
28
|
+
//
|
|
29
|
+
// Apps
|
|
30
|
+
//
|
|
31
|
+
async #getCurrentApp() {
|
|
32
|
+
return this.#lock.inLock(async () => {
|
|
33
|
+
let r = await this.transport.send(LEDGER_SYSTEM, 0x01, 0x00, 0x00, undefined, [0x9000]);
|
|
34
|
+
let data = r.slice(0, r.length - 2);
|
|
35
|
+
if (data[0] !== 0x01) {
|
|
36
|
+
throw Error('Invalid response');
|
|
37
|
+
}
|
|
38
|
+
let nameLength = data[1];
|
|
39
|
+
let name = data.slice(2, 2 + nameLength).toString();
|
|
40
|
+
let versionLength = data[2 + nameLength];
|
|
41
|
+
let version = data.slice(3 + nameLength, 3 + nameLength + versionLength).toString();
|
|
42
|
+
return { name, version };
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async isAppOpen() {
|
|
46
|
+
return (await this.#getCurrentApp()).name === 'TON';
|
|
47
|
+
}
|
|
48
|
+
async getVersion() {
|
|
49
|
+
let loaded = await this.#doRequest(INS_VERSION, 0x00, 0x00, Buffer.alloc(0));
|
|
50
|
+
const [major, minor, patch] = loaded;
|
|
51
|
+
return `${major}.${minor}.${patch}`;
|
|
52
|
+
}
|
|
53
|
+
//
|
|
54
|
+
// Operations
|
|
55
|
+
//
|
|
56
|
+
async getAddress(path, opts) {
|
|
57
|
+
// Check path
|
|
58
|
+
validatePath(path);
|
|
59
|
+
// Resolve flags
|
|
60
|
+
let bounceable = true;
|
|
61
|
+
let chain = 0;
|
|
62
|
+
let test = false;
|
|
63
|
+
let flags = 0x00;
|
|
64
|
+
if (opts && opts.bounceable !== undefined && !opts.bounceable) {
|
|
65
|
+
flags |= 0x01;
|
|
66
|
+
bounceable = false;
|
|
67
|
+
}
|
|
68
|
+
if (opts && opts.testOnly) {
|
|
69
|
+
flags |= 0x02;
|
|
70
|
+
test = true;
|
|
71
|
+
}
|
|
72
|
+
if (opts && opts.chain !== undefined) {
|
|
73
|
+
if (opts.chain !== 0 && opts.chain !== -1) {
|
|
74
|
+
throw Error('Invalid chain');
|
|
75
|
+
}
|
|
76
|
+
chain = opts.chain;
|
|
77
|
+
if (opts.chain === -1) {
|
|
78
|
+
flags |= 0x04;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Get public key
|
|
82
|
+
let response = await this.#doRequest(INS_ADDRESS, 0x00, 0x00, pathElementsToBuffer(path.map((v) => v + 0x80000000)));
|
|
83
|
+
if (response.length !== 32) {
|
|
84
|
+
throw Error('Invalid response');
|
|
85
|
+
}
|
|
86
|
+
// Contract
|
|
87
|
+
const contract = (0, getInit_1.getInit)(chain, response);
|
|
88
|
+
const address = (0, ton_core_1.contractAddress)(chain, contract);
|
|
89
|
+
return { address: address.toString({ bounceable: bounceable, testOnly: test }), publicKey: response };
|
|
90
|
+
}
|
|
91
|
+
async validateAddress(path, opts) {
|
|
92
|
+
// Check path
|
|
93
|
+
validatePath(path);
|
|
94
|
+
// Resolve flags
|
|
95
|
+
let bounceable = true;
|
|
96
|
+
let chain = 0;
|
|
97
|
+
let test = false;
|
|
98
|
+
let flags = 0x00;
|
|
99
|
+
if (opts && opts.bounceable !== undefined && !opts.bounceable) {
|
|
100
|
+
flags |= 0x01;
|
|
101
|
+
bounceable = false;
|
|
102
|
+
}
|
|
103
|
+
if (opts && opts.testOnly) {
|
|
104
|
+
flags |= 0x02;
|
|
105
|
+
test = true;
|
|
106
|
+
}
|
|
107
|
+
if (opts && opts.chain !== undefined) {
|
|
108
|
+
if (opts.chain !== 0 && opts.chain !== -1) {
|
|
109
|
+
throw Error('Invalid chain');
|
|
110
|
+
}
|
|
111
|
+
chain = opts.chain;
|
|
112
|
+
if (opts.chain === -1) {
|
|
113
|
+
flags |= 0x04;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Get public key
|
|
117
|
+
let response = await this.#doRequest(INS_ADDRESS, 0x01, flags, pathElementsToBuffer(path.map((v) => v + 0x80000000)));
|
|
118
|
+
if (response.length !== 32) {
|
|
119
|
+
throw Error('Invalid response');
|
|
120
|
+
}
|
|
121
|
+
// Contract
|
|
122
|
+
const contract = (0, getInit_1.getInit)(chain, response);
|
|
123
|
+
const address = (0, ton_core_1.contractAddress)(chain, contract);
|
|
124
|
+
return { address: address.toString({ bounceable: bounceable, testOnly: test }), publicKey: response };
|
|
125
|
+
}
|
|
126
|
+
async getAddressProof(path, params, opts) {
|
|
127
|
+
// Check path
|
|
128
|
+
validatePath(path);
|
|
129
|
+
let publicKey = (await this.getAddress(path)).publicKey;
|
|
130
|
+
// Resolve flags
|
|
131
|
+
let bounceable = true;
|
|
132
|
+
let chain = 0;
|
|
133
|
+
let test = false;
|
|
134
|
+
let flags = 0x00;
|
|
135
|
+
if (opts && opts.bounceable !== undefined && !opts.bounceable) {
|
|
136
|
+
flags |= 0x01;
|
|
137
|
+
bounceable = false;
|
|
138
|
+
}
|
|
139
|
+
if (opts && opts.testOnly) {
|
|
140
|
+
flags |= 0x02;
|
|
141
|
+
test = true;
|
|
142
|
+
}
|
|
143
|
+
if (opts && opts.chain !== undefined) {
|
|
144
|
+
if (opts.chain !== 0 && opts.chain !== -1) {
|
|
145
|
+
throw Error('Invalid chain');
|
|
146
|
+
}
|
|
147
|
+
chain = opts.chain;
|
|
148
|
+
if (opts.chain === -1) {
|
|
149
|
+
flags |= 0x04;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const domainBuf = Buffer.from(params.domain, 'utf-8');
|
|
153
|
+
const reqBuf = Buffer.concat([
|
|
154
|
+
pathElementsToBuffer(path.map((v) => v + 0x80000000)),
|
|
155
|
+
(0, ledgerWriter_1.writeUint8)(domainBuf.length),
|
|
156
|
+
domainBuf,
|
|
157
|
+
(0, ledgerWriter_1.writeUint64)(BigInt(params.timestamp)),
|
|
158
|
+
params.payload,
|
|
159
|
+
]);
|
|
160
|
+
// Get public key
|
|
161
|
+
let res = await this.#doRequest(INS_PROOF, 0x01, flags, reqBuf);
|
|
162
|
+
let signature = res.slice(1, 1 + 64);
|
|
163
|
+
let hash = res.slice(2 + 64, 2 + 64 + 32);
|
|
164
|
+
if (!(0, ton_crypto_1.signVerify)(hash, signature, publicKey)) {
|
|
165
|
+
throw Error('Received signature is invalid');
|
|
166
|
+
}
|
|
167
|
+
return { signature, hash };
|
|
168
|
+
}
|
|
169
|
+
signTransaction = async (path, transaction) => {
|
|
170
|
+
// Check path
|
|
171
|
+
validatePath(path);
|
|
172
|
+
//
|
|
173
|
+
// Fetch key
|
|
174
|
+
//
|
|
175
|
+
let publicKey = (await this.getAddress(path)).publicKey;
|
|
176
|
+
//
|
|
177
|
+
// Create package
|
|
178
|
+
//
|
|
179
|
+
let pkg = Buffer.concat([
|
|
180
|
+
(0, ledgerWriter_1.writeUint8)(0),
|
|
181
|
+
(0, ledgerWriter_1.writeUint32)(transaction.seqno),
|
|
182
|
+
(0, ledgerWriter_1.writeUint32)(transaction.timeout),
|
|
183
|
+
(0, ledgerWriter_1.writeVarUInt)(transaction.amount),
|
|
184
|
+
(0, ledgerWriter_1.writeAddress)(transaction.to),
|
|
185
|
+
(0, ledgerWriter_1.writeUint8)(transaction.bounce ? 1 : 0),
|
|
186
|
+
(0, ledgerWriter_1.writeUint8)(transaction.sendMode),
|
|
187
|
+
]);
|
|
188
|
+
//
|
|
189
|
+
// State init
|
|
190
|
+
//
|
|
191
|
+
let stateInit = null;
|
|
192
|
+
if (transaction.stateInit) {
|
|
193
|
+
stateInit = (0, ton_core_1.beginCell)()
|
|
194
|
+
.store((0, ton_core_1.storeStateInit)(transaction.stateInit))
|
|
195
|
+
.endCell();
|
|
196
|
+
pkg = Buffer.concat([
|
|
197
|
+
pkg,
|
|
198
|
+
(0, ledgerWriter_1.writeUint8)(1),
|
|
199
|
+
(0, ledgerWriter_1.writeUint16)(stateInit.depth()),
|
|
200
|
+
stateInit.hash()
|
|
201
|
+
]);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
pkg = Buffer.concat([
|
|
205
|
+
pkg,
|
|
206
|
+
(0, ledgerWriter_1.writeUint8)(0)
|
|
207
|
+
]);
|
|
208
|
+
}
|
|
209
|
+
//
|
|
210
|
+
// Payload
|
|
211
|
+
//
|
|
212
|
+
let payload = null;
|
|
213
|
+
let hints = Buffer.concat([(0, ledgerWriter_1.writeUint8)(0)]);
|
|
214
|
+
if (transaction.payload) {
|
|
215
|
+
if (transaction.payload.type === 'comment') {
|
|
216
|
+
hints = Buffer.concat([
|
|
217
|
+
(0, ledgerWriter_1.writeUint8)(1),
|
|
218
|
+
(0, ledgerWriter_1.writeUint32)(0x00),
|
|
219
|
+
(0, ledgerWriter_1.writeUint16)(Buffer.from(transaction.payload.text).length),
|
|
220
|
+
Buffer.from(transaction.payload.text)
|
|
221
|
+
]);
|
|
222
|
+
payload = (0, ton_core_1.beginCell)()
|
|
223
|
+
.storeUint(0, 32)
|
|
224
|
+
.storeBuffer(Buffer.from(transaction.payload.text))
|
|
225
|
+
.endCell();
|
|
226
|
+
}
|
|
227
|
+
else if (transaction.payload.type === 'unsafe') {
|
|
228
|
+
payload = transaction.payload.message;
|
|
229
|
+
}
|
|
230
|
+
else if (transaction.payload.type === 'jetton-transfer' || transaction.payload.type === 'nft-transfer') {
|
|
231
|
+
hints = Buffer.concat([
|
|
232
|
+
(0, ledgerWriter_1.writeUint8)(1),
|
|
233
|
+
(0, ledgerWriter_1.writeUint32)(transaction.payload.type === 'jetton-transfer' ? 0x01 : 0x02)
|
|
234
|
+
]);
|
|
235
|
+
let b = (0, ton_core_1.beginCell)()
|
|
236
|
+
.storeUint(transaction.payload.type === 'jetton-transfer' ? 0x0f8a7ea5 : 0x5fcc3d14, 32);
|
|
237
|
+
let d = Buffer.alloc(0);
|
|
238
|
+
if (transaction.payload.queryId !== null) {
|
|
239
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeUint8)(1), (0, ledgerWriter_1.writeUint64)(transaction.payload.queryId)]);
|
|
240
|
+
b = b.storeUint(transaction.payload.queryId, 64);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeUint8)(0)]);
|
|
244
|
+
b = b.storeUint(0, 64);
|
|
245
|
+
}
|
|
246
|
+
if (transaction.payload.type === 'jetton-transfer') {
|
|
247
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeVarUInt)(transaction.payload.amount)]);
|
|
248
|
+
b = b.storeCoins(transaction.payload.amount);
|
|
249
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeUint8)(transaction.payload.decimals), (0, ledgerWriter_1.writeUint8)(transaction.payload.ticker.length), Buffer.from(transaction.payload.ticker, 'ascii')]);
|
|
250
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeAddress)(transaction.payload.destination)]);
|
|
251
|
+
b = b.storeAddress(transaction.payload.destination);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeAddress)(transaction.payload.newOwner)]);
|
|
255
|
+
b = b.storeAddress(transaction.payload.newOwner);
|
|
256
|
+
}
|
|
257
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeAddress)(transaction.payload.responseDestination)]);
|
|
258
|
+
b = b.storeAddress(transaction.payload.responseDestination);
|
|
259
|
+
if (transaction.payload.customPayload !== null) {
|
|
260
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeUint8)(1), (0, ledgerWriter_1.writeCellRef)(transaction.payload.customPayload)]);
|
|
261
|
+
b = b.storeMaybeRef(transaction.payload.customPayload);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeUint8)(0)]);
|
|
265
|
+
b = b.storeMaybeRef(transaction.payload.customPayload);
|
|
266
|
+
}
|
|
267
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeVarUInt)(transaction.payload.forwardAmount)]);
|
|
268
|
+
b = b.storeCoins(transaction.payload.forwardAmount);
|
|
269
|
+
if (transaction.payload.forwardPayload !== null) {
|
|
270
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeUint8)(1), (0, ledgerWriter_1.writeCellRef)(transaction.payload.forwardPayload)]);
|
|
271
|
+
b = b.storeMaybeRef(transaction.payload.forwardPayload);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
d = Buffer.concat([d, (0, ledgerWriter_1.writeUint8)(0)]);
|
|
275
|
+
b = b.storeMaybeRef(transaction.payload.forwardPayload);
|
|
276
|
+
}
|
|
277
|
+
payload = b.endCell();
|
|
278
|
+
hints = Buffer.concat([
|
|
279
|
+
hints,
|
|
280
|
+
(0, ledgerWriter_1.writeUint16)(d.length),
|
|
281
|
+
d
|
|
282
|
+
]);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
//
|
|
286
|
+
// Serialize payload
|
|
287
|
+
//
|
|
288
|
+
if (payload) {
|
|
289
|
+
pkg = Buffer.concat([
|
|
290
|
+
pkg,
|
|
291
|
+
(0, ledgerWriter_1.writeUint8)(1),
|
|
292
|
+
(0, ledgerWriter_1.writeUint16)(payload.depth()),
|
|
293
|
+
payload.hash(),
|
|
294
|
+
hints
|
|
295
|
+
]);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
pkg = Buffer.concat([
|
|
299
|
+
pkg,
|
|
300
|
+
(0, ledgerWriter_1.writeUint8)(0),
|
|
301
|
+
(0, ledgerWriter_1.writeUint8)(0)
|
|
302
|
+
]);
|
|
303
|
+
}
|
|
304
|
+
//
|
|
305
|
+
// Send package
|
|
306
|
+
//
|
|
307
|
+
await this.#doRequest(0x06, 0x00, 0x03, pathElementsToBuffer(path.map((v) => v + 0x80000000)));
|
|
308
|
+
const pkgCs = chunks(pkg, 255);
|
|
309
|
+
for (let i = 0; i < pkgCs.length - 1; i++) {
|
|
310
|
+
await this.#doRequest(0x06, 0x00, 0x02, pkgCs[i]);
|
|
311
|
+
}
|
|
312
|
+
let res = await this.#doRequest(0x06, 0x00, 0x00, pkgCs[pkgCs.length - 1]);
|
|
313
|
+
//
|
|
314
|
+
// Parse response
|
|
315
|
+
//
|
|
316
|
+
let orderBuilder = (0, ton_core_1.beginCell)()
|
|
317
|
+
.storeBit(0)
|
|
318
|
+
.storeBit(true)
|
|
319
|
+
.storeBit(transaction.bounce)
|
|
320
|
+
.storeBit(false)
|
|
321
|
+
.storeAddress(null)
|
|
322
|
+
.storeAddress(transaction.to)
|
|
323
|
+
.storeCoins(transaction.amount)
|
|
324
|
+
.storeBit(false)
|
|
325
|
+
.storeCoins(0)
|
|
326
|
+
.storeCoins(0)
|
|
327
|
+
.storeUint(0, 64)
|
|
328
|
+
.storeUint(0, 32);
|
|
329
|
+
// State Init
|
|
330
|
+
if (stateInit) {
|
|
331
|
+
orderBuilder = orderBuilder
|
|
332
|
+
.storeBit(true)
|
|
333
|
+
.storeBit(true) // Always in reference
|
|
334
|
+
.storeRef(stateInit);
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
orderBuilder = orderBuilder
|
|
338
|
+
.storeBit(false);
|
|
339
|
+
}
|
|
340
|
+
// Payload
|
|
341
|
+
if (payload) {
|
|
342
|
+
orderBuilder = orderBuilder
|
|
343
|
+
.storeBit(true) // Always in reference
|
|
344
|
+
.storeRef(payload);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
orderBuilder = orderBuilder
|
|
348
|
+
.storeBit(false);
|
|
349
|
+
}
|
|
350
|
+
// Transfer message
|
|
351
|
+
let transfer = (0, ton_core_1.beginCell)()
|
|
352
|
+
.storeUint(698983191, 32)
|
|
353
|
+
.storeUint(transaction.timeout, 32)
|
|
354
|
+
.storeUint(transaction.seqno, 32)
|
|
355
|
+
.storeUint(0, 8)
|
|
356
|
+
.storeUint(transaction.sendMode, 8)
|
|
357
|
+
.storeRef(orderBuilder.endCell())
|
|
358
|
+
.endCell();
|
|
359
|
+
// Parse result
|
|
360
|
+
let signature = res.slice(1, 1 + 64);
|
|
361
|
+
let hash = res.slice(2 + 64, 2 + 64 + 32);
|
|
362
|
+
if (!hash.equals(transfer.hash())) {
|
|
363
|
+
throw Error('Hash mismatch. Expected: ' + transfer.hash().toString('hex') + ', got: ' + hash.toString('hex'));
|
|
364
|
+
}
|
|
365
|
+
if (!(0, ton_crypto_1.signVerify)(hash, signature, publicKey)) {
|
|
366
|
+
throw Error('Received signature is invalid');
|
|
367
|
+
}
|
|
368
|
+
// Build a message
|
|
369
|
+
return (0, ton_core_1.beginCell)()
|
|
370
|
+
.storeBuffer(signature)
|
|
371
|
+
.storeSlice(transfer.beginParse())
|
|
372
|
+
.endCell();
|
|
373
|
+
};
|
|
374
|
+
#doRequest = async (ins, p1, p2, data) => {
|
|
375
|
+
return this.#lock.inLock(async () => {
|
|
376
|
+
let r = await this.transport.send(LEDGER_CLA, ins, p1, p2, data);
|
|
377
|
+
return r.slice(0, r.length - 2);
|
|
378
|
+
});
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
exports.TonTransport = TonTransport;
|
|
382
|
+
//
|
|
383
|
+
// Utils
|
|
384
|
+
//
|
|
385
|
+
function validatePath(path) {
|
|
386
|
+
if (path.length < 6) {
|
|
387
|
+
throw Error('Path is too short');
|
|
388
|
+
}
|
|
389
|
+
if (path[0] !== 44) {
|
|
390
|
+
throw Error('First element of a path must be 44');
|
|
391
|
+
}
|
|
392
|
+
if (path[1] !== 607) {
|
|
393
|
+
throw Error('Second element of a path must be 607');
|
|
394
|
+
}
|
|
395
|
+
for (let p of path) {
|
|
396
|
+
if (p >= 0x80000000) {
|
|
397
|
+
throw Error('All path elements must be under 0x80000000');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function pathElementsToBuffer(paths) {
|
|
402
|
+
const buffer = Buffer.alloc(1 + paths.length * 4);
|
|
403
|
+
buffer[0] = paths.length;
|
|
404
|
+
paths.forEach((element, index) => {
|
|
405
|
+
buffer.writeUInt32BE(element, 1 + 4 * index);
|
|
406
|
+
});
|
|
407
|
+
return buffer;
|
|
408
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TonPayloadFormat, TonTransport } from './TonTransport';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TonTransport = void 0;
|
|
4
|
+
var TonTransport_1 = require("./TonTransport");
|
|
5
|
+
Object.defineProperty(exports, "TonTransport", { enumerable: true, get: function () { return TonTransport_1.TonTransport; } });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getInit = void 0;
|
|
4
|
+
const ton_core_1 = require("ton-core");
|
|
5
|
+
function getInit(workchain, publicKey) {
|
|
6
|
+
let code = ton_core_1.Cell.fromBoc(Buffer.from('te6ccgECFAEAAtQAART/APSkE/S88sgLAQIBIAIDAgFIBAUE+PKDCNcYINMf0x/THwL4I7vyZO1E0NMf0x/T//QE0VFDuvKhUVG68qIF+QFUEGT5EPKj+AAkpMjLH1JAyx9SMMv/UhD0AMntVPgPAdMHIcAAn2xRkyDXSpbTB9QC+wDoMOAhwAHjACHAAuMAAcADkTDjDQOkyMsfEssfy/8QERITAubQAdDTAyFxsJJfBOAi10nBIJJfBOAC0x8hghBwbHVnvSKCEGRzdHK9sJJfBeAD+kAwIPpEAcjKB8v/ydDtRNCBAUDXIfQEMFyBAQj0Cm+hMbOSXwfgBdM/yCWCEHBsdWe6kjgw4w0DghBkc3RyupJfBuMNBgcCASAICQB4AfoA9AQw+CdvIjBQCqEhvvLgUIIQcGx1Z4MesXCAGFAEywUmzxZY+gIZ9ADLaRfLH1Jgyz8gyYBA+wAGAIpQBIEBCPRZMO1E0IEBQNcgyAHPFvQAye1UAXKwjiOCEGRzdHKDHrFwgBhQBcsFUAPPFiP6AhPLassfyz/JgED7AJJfA+ICASAKCwBZvSQrb2omhAgKBrkPoCGEcNQICEekk30pkQzmkD6f+YN4EoAbeBAUiYcVnzGEAgFYDA0AEbjJftRNDXCx+AA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYAIBIA4PABmtznaiaEAga5Drhf/AABmvHfaiaEAQa5DrhY/AAG7SB/oA1NQi+QAFyMoHFcv/ydB3dIAYyMsFywIizxZQBfoCFMtrEszMyXP7AMhAFIEBCPRR8qcCAHCBAQjXGPoA0z/IVCBHgQEI9FHyp4IQbm90ZXB0gBjIywXLAlAGzxZQBPoCFMtqEssfyz/Jc/sAAgBsgQEI1xj6ANM/MFIkgQEI9Fnyp4IQZHN0cnB0gBjIywXLAlAFzxZQA/oCE8tqyx8Syz/Jc/sAAAr0AMntVA==', 'base64'))[0];
|
|
7
|
+
let data = (0, ton_core_1.beginCell)()
|
|
8
|
+
.storeUint(0, 32) // Seqno
|
|
9
|
+
.storeUint(698983191 + workchain, 32)
|
|
10
|
+
.storeBuffer(publicKey)
|
|
11
|
+
.storeBit(0) // Empty plugins dict
|
|
12
|
+
.endCell();
|
|
13
|
+
return { code, data };
|
|
14
|
+
}
|
|
15
|
+
exports.getInit = getInit;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Address, Cell } from 'ton-core';
|
|
3
|
+
export declare function writeUint32(value: number): Buffer;
|
|
4
|
+
export declare function writeUint16(value: number): Buffer;
|
|
5
|
+
export declare function writeUint64(value: bigint): Buffer;
|
|
6
|
+
export declare function writeVarUInt(value: bigint): Buffer;
|
|
7
|
+
export declare function writeUint8(value: number): Buffer;
|
|
8
|
+
export declare function writeAddress(address: Address): Buffer;
|
|
9
|
+
export declare function writeCellRef(ref: Cell): Buffer;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeCellRef = exports.writeAddress = exports.writeUint8 = exports.writeVarUInt = exports.writeUint64 = exports.writeUint16 = exports.writeUint32 = void 0;
|
|
4
|
+
const ton_core_1 = require("ton-core");
|
|
5
|
+
function writeUint32(value) {
|
|
6
|
+
let b = Buffer.alloc(4);
|
|
7
|
+
b.writeUint32BE(value, 0);
|
|
8
|
+
return b;
|
|
9
|
+
}
|
|
10
|
+
exports.writeUint32 = writeUint32;
|
|
11
|
+
function writeUint16(value) {
|
|
12
|
+
let b = Buffer.alloc(2);
|
|
13
|
+
b.writeUint16BE(value, 0);
|
|
14
|
+
return b;
|
|
15
|
+
}
|
|
16
|
+
exports.writeUint16 = writeUint16;
|
|
17
|
+
function writeUint64(value) {
|
|
18
|
+
return (0, ton_core_1.beginCell)().storeUint(value, 64).endCell().beginParse().loadBuffer(8);
|
|
19
|
+
}
|
|
20
|
+
exports.writeUint64 = writeUint64;
|
|
21
|
+
function writeVarUInt(value) {
|
|
22
|
+
const sizeBytes = Math.ceil((value.toString(2).length) / 8);
|
|
23
|
+
return (0, ton_core_1.beginCell)().storeUint(sizeBytes, 8).storeUint(value, sizeBytes * 8).endCell().beginParse().loadBuffer(1 + sizeBytes);
|
|
24
|
+
}
|
|
25
|
+
exports.writeVarUInt = writeVarUInt;
|
|
26
|
+
function writeUint8(value) {
|
|
27
|
+
let b = Buffer.alloc(1);
|
|
28
|
+
b[0] = value;
|
|
29
|
+
return b;
|
|
30
|
+
}
|
|
31
|
+
exports.writeUint8 = writeUint8;
|
|
32
|
+
function writeAddress(address) {
|
|
33
|
+
return Buffer.concat([
|
|
34
|
+
writeUint8(address.workChain === -1 ? 0xff : address.workChain),
|
|
35
|
+
address.hash
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
exports.writeAddress = writeAddress;
|
|
39
|
+
function writeCellRef(ref) {
|
|
40
|
+
return Buffer.concat([
|
|
41
|
+
writeUint16(ref.depth()),
|
|
42
|
+
ref.hash()
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
exports.writeCellRef = writeCellRef;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ton_core_1 = require("ton-core");
|
|
4
|
+
const ledgerWriter_1 = require("./ledgerWriter");
|
|
5
|
+
describe('ledgerWriter', () => {
|
|
6
|
+
it('should write ints', () => {
|
|
7
|
+
expect((0, ledgerWriter_1.writeUint8)(0).toString('hex')).toMatchSnapshot();
|
|
8
|
+
expect((0, ledgerWriter_1.writeUint8)(10).toString('hex')).toMatchSnapshot();
|
|
9
|
+
expect((0, ledgerWriter_1.writeUint8)(255).toString('hex')).toMatchSnapshot();
|
|
10
|
+
expect((0, ledgerWriter_1.writeUint16)(0).toString('hex')).toMatchSnapshot();
|
|
11
|
+
expect((0, ledgerWriter_1.writeUint16)(255).toString('hex')).toMatchSnapshot();
|
|
12
|
+
expect((0, ledgerWriter_1.writeUint16)(12312).toString('hex')).toMatchSnapshot();
|
|
13
|
+
expect((0, ledgerWriter_1.writeUint16)(65535).toString('hex')).toMatchSnapshot();
|
|
14
|
+
expect((0, ledgerWriter_1.writeUint32)(0).toString('hex')).toMatchSnapshot();
|
|
15
|
+
expect((0, ledgerWriter_1.writeUint32)(255).toString('hex')).toMatchSnapshot();
|
|
16
|
+
expect((0, ledgerWriter_1.writeUint32)(12312).toString('hex')).toMatchSnapshot();
|
|
17
|
+
expect((0, ledgerWriter_1.writeUint32)(65535).toString('hex')).toMatchSnapshot();
|
|
18
|
+
expect((0, ledgerWriter_1.writeUint32)(123123123).toString('hex')).toMatchSnapshot();
|
|
19
|
+
expect((0, ledgerWriter_1.writeUint32)(4294967295).toString('hex')).toMatchSnapshot();
|
|
20
|
+
expect((0, ledgerWriter_1.writeUint64)(0n).toString('hex')).toMatchSnapshot();
|
|
21
|
+
expect((0, ledgerWriter_1.writeUint64)(255n).toString('hex')).toMatchSnapshot();
|
|
22
|
+
expect((0, ledgerWriter_1.writeUint64)(12312n).toString('hex')).toMatchSnapshot();
|
|
23
|
+
expect((0, ledgerWriter_1.writeUint64)(65535n).toString('hex')).toMatchSnapshot();
|
|
24
|
+
expect((0, ledgerWriter_1.writeUint64)(123123123n).toString('hex')).toMatchSnapshot();
|
|
25
|
+
expect((0, ledgerWriter_1.writeUint64)(4294967295n).toString('hex')).toMatchSnapshot();
|
|
26
|
+
expect((0, ledgerWriter_1.writeUint64)(12312312312312n).toString('hex')).toMatchSnapshot();
|
|
27
|
+
expect((0, ledgerWriter_1.writeUint64)(18446744073709551615n).toString('hex')).toMatchSnapshot();
|
|
28
|
+
});
|
|
29
|
+
it('should write addresses', () => {
|
|
30
|
+
expect((0, ledgerWriter_1.writeAddress)(new ton_core_1.Address(0, Buffer.alloc(32))).toString('hex')).toMatchSnapshot();
|
|
31
|
+
expect((0, ledgerWriter_1.writeAddress)(new ton_core_1.Address(-1, Buffer.alloc(32))).toString('hex')).toMatchSnapshot();
|
|
32
|
+
expect((0, ledgerWriter_1.writeAddress)(ton_core_1.Address.parse('EQBNVUFfKt2QgqKL5vZvnyP50wmniCFP2ASOKAE-g2noRDlR')).toString('hex')).toMatchSnapshot();
|
|
33
|
+
expect((0, ledgerWriter_1.writeAddress)(ton_core_1.Address.parse('Ef87m7_QrVM4uXAPCDM4DuF9Rj5Rwa5nHubwiQG96JmyAjQY')).toString('hex')).toMatchSnapshot();
|
|
34
|
+
});
|
|
35
|
+
it('should write cell refs', () => {
|
|
36
|
+
expect((0, ledgerWriter_1.writeCellRef)((0, ton_core_1.beginCell)().endCell()).toString('hex')).toMatchSnapshot();
|
|
37
|
+
expect((0, ledgerWriter_1.writeCellRef)((0, ton_core_1.beginCell)().storeUint(0, 32).endCell()).toString('hex')).toMatchSnapshot();
|
|
38
|
+
expect((0, ledgerWriter_1.writeCellRef)((0, ton_core_1.beginCell)().storeUint(0, 32).storeRef((0, ton_core_1.beginCell)().endCell()).endCell()).toString('hex')).toMatchSnapshot();
|
|
39
|
+
expect((0, ledgerWriter_1.writeCellRef)((0, ton_core_1.beginCell)().storeUint(0, 32).storeRef((0, ton_core_1.beginCell)().storeRef((0, ton_core_1.beginCell)().endCell()).endCell()).endCell()).toString('hex')).toMatchSnapshot();
|
|
40
|
+
});
|
|
41
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ton-community/ton-ledger",
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"repository": "https://github.com/ton-community/ton-ledger-ts",
|
|
5
|
+
"author": "Steve Korshakov <steve@korshakov.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "rm -fr dist && tsc --declaration",
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"release": "yarn test && yarn build && yarn release-it --npm.yarn1",
|
|
15
|
+
"dev": "ts-node ./test/index.ts"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"ton-core": ">=0.49.1"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@release-it/keep-a-changelog": "^3.1.0",
|
|
22
|
+
"@ledgerhq/hw-transport-node-hid": "^6.27.15",
|
|
23
|
+
"@types/jest": "^29.5.2",
|
|
24
|
+
"@types/node": "^20.2.5",
|
|
25
|
+
"jest": "^29.5.0",
|
|
26
|
+
"release-it": "^15.11.0",
|
|
27
|
+
"ton-core": "^0.49.1",
|
|
28
|
+
"ts-jest": "^29.1.0",
|
|
29
|
+
"ts-node": "^10.9.1",
|
|
30
|
+
"typescript": "^4.9.5"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@ledgerhq/hw-transport": "^6.28.4",
|
|
34
|
+
"teslabot": "^1.5.0",
|
|
35
|
+
"ton-crypto": "^3.2.0"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public",
|
|
39
|
+
"registry": "https://registry.npmjs.org/"
|
|
40
|
+
},
|
|
41
|
+
"release-it": {
|
|
42
|
+
"github": {
|
|
43
|
+
"release": true
|
|
44
|
+
},
|
|
45
|
+
"plugins": {
|
|
46
|
+
"@release-it/keep-a-changelog": {
|
|
47
|
+
"filename": "CHANGELOG.md"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|