@ton-community/ton-ledger 7.4.0-pre.0 → 7.4.0-pre.1

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.
@@ -121,6 +121,21 @@ export type SignDataRequest = {
121
121
  data: Cell;
122
122
  ext?: Cell;
123
123
  };
124
+ export type SignDataNewRequestCommon = {
125
+ domain: string;
126
+ };
127
+ export type SignDataNewRequestPartial = {
128
+ type: 'plaintext';
129
+ text: string;
130
+ } | {
131
+ type: 'binary';
132
+ data: Buffer;
133
+ } | {
134
+ type: 'app-data';
135
+ schemaCrc: number;
136
+ data: Cell;
137
+ };
138
+ export type SignDataNewRequest = SignDataNewRequestCommon & SignDataNewRequestPartial;
124
139
  export declare class TonTransport {
125
140
  #private;
126
141
  readonly transport: Transport;
@@ -168,6 +183,19 @@ export declare class TonTransport {
168
183
  cell: Cell;
169
184
  timestamp: number;
170
185
  }>;
186
+ signDataNew(path: number[], req: SignDataNewRequest, opts?: {
187
+ timestamp?: number;
188
+ testOnly?: boolean;
189
+ chain?: number;
190
+ subwalletId?: number;
191
+ walletVersion?: 'v3r2' | 'v4';
192
+ }): Promise<{
193
+ signature: Buffer;
194
+ address: Address;
195
+ signedData: Buffer | Cell;
196
+ signedDataHash: Buffer;
197
+ timestamp: number;
198
+ }>;
171
199
  signTransaction: (path: number[], transaction: {
172
200
  to: Address;
173
201
  sendMode: SendMode;
@@ -190,4 +218,5 @@ export declare class TonTransport {
190
218
  blindSigningEnabled: boolean;
191
219
  expertMode: boolean;
192
220
  }>;
221
+ launchApp(): Promise<void>;
193
222
  }
@@ -1068,6 +1068,112 @@ class TonTransport {
1068
1068
  timestamp,
1069
1069
  };
1070
1070
  }
1071
+ async signDataNew(path, req, opts) {
1072
+ validatePath(path);
1073
+ const { publicKey, address: addressString } = (await this.getAddress(path, opts));
1074
+ const expectedAddress = core_1.Address.parse(addressString);
1075
+ const { flags, specifiers, chain } = processAddressFlags(opts);
1076
+ let specifiersBuf = Buffer.alloc(0);
1077
+ if (specifiers !== undefined) {
1078
+ specifiersBuf = Buffer.concat([(0, ledgerWriter_1.writeUint8)(specifiers.isV3R2 ? 1 : 0), (0, ledgerWriter_1.writeUint32)(specifiers.subwalletId)]);
1079
+ }
1080
+ const timestamp = opts?.timestamp ?? Math.floor(Date.now() / 1000);
1081
+ const domainBuf = Buffer.from(req.domain, 'ascii');
1082
+ let typeId;
1083
+ let payload;
1084
+ let signedData;
1085
+ switch (req.type) {
1086
+ case 'plaintext': {
1087
+ typeId = 0;
1088
+ payload = Buffer.from(req.text, 'ascii');
1089
+ signedData = Buffer.concat([
1090
+ Buffer.from([0xff, 0xff]),
1091
+ Buffer.from('ton-connect/sign-data/'),
1092
+ (0, ledgerWriter_1.writeInt32BE)(chain),
1093
+ expectedAddress.hash,
1094
+ (0, ledgerWriter_1.writeUint32)(domainBuf.length),
1095
+ domainBuf,
1096
+ (0, ledgerWriter_1.writeUint64)(BigInt(timestamp)),
1097
+ Buffer.from('txt', 'ascii'),
1098
+ (0, ledgerWriter_1.writeUint32)(payload.length),
1099
+ payload,
1100
+ ]);
1101
+ break;
1102
+ }
1103
+ case 'binary': {
1104
+ typeId = 1;
1105
+ payload = req.data;
1106
+ signedData = Buffer.concat([
1107
+ Buffer.from([0xff, 0xff]),
1108
+ Buffer.from('ton-connect/sign-data/'),
1109
+ (0, ledgerWriter_1.writeInt32BE)(chain),
1110
+ expectedAddress.hash,
1111
+ (0, ledgerWriter_1.writeUint32)(domainBuf.length),
1112
+ domainBuf,
1113
+ (0, ledgerWriter_1.writeUint64)(BigInt(timestamp)),
1114
+ Buffer.from('bin', 'ascii'),
1115
+ (0, ledgerWriter_1.writeUint32)(payload.length),
1116
+ payload,
1117
+ ]);
1118
+ break;
1119
+ }
1120
+ case 'app-data': {
1121
+ typeId = 2;
1122
+ payload = Buffer.concat([
1123
+ (0, ledgerWriter_1.writeUint32)(req.schemaCrc),
1124
+ (0, ledgerWriter_1.writeCellRef)(req.data),
1125
+ ]);
1126
+ let inner = (0, core_1.beginCell)();
1127
+ req.domain.split('.').reverse().forEach(p => {
1128
+ inner.storeBuffer(Buffer.from(p, 'ascii'));
1129
+ inner.storeUint(0, 8);
1130
+ });
1131
+ signedData = (0, core_1.beginCell)()
1132
+ .storeUint(0x75569022, 32) // prefix
1133
+ .storeUint(req.schemaCrc, 32) // schema hash
1134
+ .storeUint(timestamp, 64) // timestamp
1135
+ .storeAddress(expectedAddress) // user wallet address
1136
+ .storeRef(inner) // domain
1137
+ .storeRef(req.data) // payload cell
1138
+ .endCell();
1139
+ break;
1140
+ }
1141
+ default: {
1142
+ throw new Error(`Sign data request type '${req.type}' not supported`);
1143
+ }
1144
+ }
1145
+ const pkg = Buffer.concat([
1146
+ (0, ledgerWriter_1.writeUint8)(typeId),
1147
+ (0, ledgerWriter_1.writeUint8)(flags),
1148
+ specifiersBuf,
1149
+ (0, ledgerWriter_1.writeUint8)(domainBuf.length),
1150
+ domainBuf,
1151
+ (0, ledgerWriter_1.writeUint64)(BigInt(timestamp)),
1152
+ payload,
1153
+ ]);
1154
+ await this.#doRequest(INS_SIGN_DATA, 0x01, 0x03, pathElementsToBuffer(path.map((v) => v + 0x80000000)));
1155
+ const pkgCs = chunks(pkg, 255);
1156
+ for (let i = 0; i < pkgCs.length - 1; i++) {
1157
+ await this.#doRequest(INS_SIGN_DATA, 0x01, 0x02, pkgCs[i]);
1158
+ }
1159
+ const res = await this.#doRequest(INS_SIGN_DATA, 0x01, 0x00, pkgCs[pkgCs.length - 1]);
1160
+ let signature = res.subarray(1, 1 + 64);
1161
+ let hash = res.subarray(2 + 64, 2 + 64 + 32);
1162
+ const signedDataHash = signedData instanceof core_1.Cell ? signedData.hash() : (0, crypto_1.sha256_sync)(signedData);
1163
+ if (!hash.equals(signedDataHash)) {
1164
+ throw Error('Hash mismatch. Expected: ' + signedDataHash.toString('hex') + ', got: ' + hash.toString('hex'));
1165
+ }
1166
+ if (!(0, crypto_1.signVerify)(signedDataHash, signature, publicKey)) {
1167
+ throw Error('Received signature is invalid');
1168
+ }
1169
+ return {
1170
+ signature,
1171
+ address: expectedAddress,
1172
+ signedData,
1173
+ signedDataHash,
1174
+ timestamp,
1175
+ };
1176
+ }
1071
1177
  signTransaction = async (path, transaction) => {
1072
1178
  // Check path
1073
1179
  validatePath(path);
@@ -1250,6 +1356,9 @@ class TonTransport {
1250
1356
  expertMode: (loaded[0] & 0x02) > 0,
1251
1357
  };
1252
1358
  }
1359
+ async launchApp() {
1360
+ await this.#doRequest(0xd8, 0x00, 0x00, Buffer.from('TON', 'ascii'));
1361
+ }
1253
1362
  #doRequest = async (ins, p1, p2, data) => {
1254
1363
  return this.#lock.inLock(async () => {
1255
1364
  let r = await this.transport.send(LEDGER_CLA, ins, p1, p2, data);
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  import { Address, Cell } from '@ton/core';
4
+ export declare function writeInt32BE(value: number): Buffer;
4
5
  export declare function writeUint32(value: number): Buffer;
5
6
  export declare function writeUint16(value: number): Buffer;
6
7
  export declare function writeUint48(value: number): Buffer;
@@ -1,7 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.writeCellInline = exports.writeCellRef = exports.writeAddress = exports.writeUint8 = exports.writeVarUInt = exports.writeUint64 = exports.writeUint48 = exports.writeUint16 = exports.writeUint32 = void 0;
3
+ exports.writeCellInline = exports.writeCellRef = exports.writeAddress = exports.writeUint8 = exports.writeVarUInt = exports.writeUint64 = exports.writeUint48 = exports.writeUint16 = exports.writeUint32 = exports.writeInt32BE = void 0;
4
4
  const core_1 = require("@ton/core");
5
+ function writeInt32BE(value) {
6
+ let b = Buffer.alloc(4);
7
+ b.writeInt32BE(value, 0);
8
+ return b;
9
+ }
10
+ exports.writeInt32BE = writeInt32BE;
5
11
  function writeUint32(value) {
6
12
  let b = Buffer.alloc(4);
7
13
  b.writeUint32BE(value, 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ton-community/ton-ledger",
3
- "version": "7.4.0-pre.0",
3
+ "version": "7.4.0-pre.1",
4
4
  "repository": "https://github.com/ton-community/ton-ledger-ts",
5
5
  "author": "Steve Korshakov <steve@korshakov.com>",
6
6
  "license": "MIT",