@onekeyfe/hd-core 1.1.25-alpha.1 → 1.1.26-alpha.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.
@@ -12,9 +12,22 @@ import type {
12
12
  } from '@onekeyfe/hd-transport';
13
13
  import type { StellarOperation, StellarSignTransactionParams } from '../../types';
14
14
 
15
+ // Firmware accepts up to 1024 bytes per chunk; 1 byte = 2 hex chars
16
+ const SOROBAN_CHUNK_BYTES = 1024;
17
+ const SOROBAN_CHUNK_HEX_CHARS = SOROBAN_CHUNK_BYTES * 2;
18
+
15
19
  export default class StellarSignTransaction extends BaseMethod<HardwareStellarSignTx> {
16
20
  operations: any[] = [];
17
21
 
22
+ private sorobanState?: {
23
+ callArgs: string;
24
+ callArgsSent: number;
25
+ auth: string;
26
+ authSent: number;
27
+ ext: string;
28
+ extSent: number;
29
+ };
30
+
18
31
  parseOperation = (op: StellarOperation) => {
19
32
  switch (op.type) {
20
33
  case 'createAccount':
@@ -144,6 +157,59 @@ export default class StellarSignTransaction extends BaseMethod<HardwareStellarSi
144
157
  source_account: op.source,
145
158
  bump_to: op.bumpTo,
146
159
  };
160
+
161
+ case 'invokeHostFunctionOneKey': {
162
+ const callArgs = op.callArgsXDRHex ?? '';
163
+ const auth = op.sorobanAuthXDRHex ?? '';
164
+
165
+ if (!this.sorobanState) {
166
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'sorobanState not initialized');
167
+ }
168
+ this.sorobanState.callArgs = callArgs;
169
+ this.sorobanState.callArgsSent = Math.min(callArgs.length, SOROBAN_CHUNK_HEX_CHARS);
170
+ this.sorobanState.auth = auth;
171
+ this.sorobanState.authSent = Math.min(auth.length, SOROBAN_CHUNK_HEX_CHARS);
172
+
173
+ return {
174
+ type: 'StellarInvokeHostFunctionOp',
175
+ source_account: op.source,
176
+ contract_address: op.contract,
177
+ function_name: op.functionName,
178
+ call_args_xdr_size: callArgs.length / 2,
179
+ call_args_xdr_initial_chunk: callArgs.slice(0, SOROBAN_CHUNK_HEX_CHARS),
180
+ soroban_auth_xdr_size: auth.length / 2,
181
+ soroban_auth_xdr_initial_chunk: auth.slice(0, SOROBAN_CHUNK_HEX_CHARS),
182
+ };
183
+ }
184
+
185
+ case 'pathPaymentStrictReceive':
186
+ validateParams(op, [{ name: 'sendMax', type: 'bigNumber', required: true }]);
187
+ validateParams(op, [{ name: 'destAmount', type: 'bigNumber', required: true }]);
188
+ return {
189
+ type: 'StellarPathPaymentStrictReceiveOp',
190
+ source_account: op.source,
191
+ send_asset: op.sendAsset,
192
+ send_max: op.sendMax,
193
+ destination_account: op.destination,
194
+ destination_asset: op.destAsset,
195
+ destination_amount: op.destAmount,
196
+ paths: op.path,
197
+ };
198
+
199
+ case 'pathPaymentStrictSend':
200
+ validateParams(op, [{ name: 'sendAmount', type: 'bigNumber', required: true }]);
201
+ validateParams(op, [{ name: 'destMin', type: 'bigNumber', required: true }]);
202
+ return {
203
+ type: 'StellarPathPaymentStrictSendOp',
204
+ source_account: op.source,
205
+ send_asset: op.sendAsset,
206
+ send_amount: op.sendAmount,
207
+ destination_account: op.destination,
208
+ destination_asset: op.destAsset,
209
+ destination_min: op.destMin,
210
+ paths: op.path,
211
+ };
212
+
147
213
  default:
148
214
  return {};
149
215
  }
@@ -171,6 +237,31 @@ export default class StellarSignTransaction extends BaseMethod<HardwareStellarSi
171
237
  // init params
172
238
  const addressN = validatePath(this.payload.path, 3);
173
239
 
240
+ const isSoroban = transaction.operations.some(op => op.type === 'invokeHostFunctionOneKey');
241
+
242
+ if (isSoroban) {
243
+ if (transaction.operations.length !== 1) {
244
+ throw ERRORS.TypedError(
245
+ HardwareErrorCode.CallMethodInvalidParameter,
246
+ 'Soroban transactions must contain exactly one operation'
247
+ );
248
+ }
249
+ if (!transaction.sorobanDataXDR) {
250
+ throw ERRORS.TypedError(
251
+ HardwareErrorCode.CallMethodInvalidParameter,
252
+ 'sorobanDataXDR is required for Soroban transactions'
253
+ );
254
+ }
255
+ this.sorobanState = {
256
+ callArgs: '',
257
+ callArgsSent: 0,
258
+ auth: '',
259
+ authSent: 0,
260
+ ext: transaction.sorobanDataXDR,
261
+ extSent: 0,
262
+ };
263
+ }
264
+
174
265
  this.params = {
175
266
  address_n: addressN,
176
267
  network_passphrase: networkPassphrase,
@@ -181,6 +272,7 @@ export default class StellarSignTransaction extends BaseMethod<HardwareStellarSi
181
272
  memo_type: StellarMemoType.NONE,
182
273
  timebounds_start: transaction.timebounds.minTime,
183
274
  timebounds_end: transaction.timebounds.maxTime,
275
+ ...(this.sorobanState ? { soroban_data_size: this.sorobanState.ext.length / 2 } : {}),
184
276
  };
185
277
 
186
278
  if (transaction.memo) {
@@ -198,23 +290,85 @@ export default class StellarSignTransaction extends BaseMethod<HardwareStellarSi
198
290
  });
199
291
  }
200
292
 
201
- processTxRequest = async (operations: any, index: number): Promise<StellarSignedTx> => {
202
- const isLastOp = index + 1 >= operations.length;
203
- const { type, ...op } = operations[index];
293
+ processTxRequest = async (
294
+ response: { type: string; message: any },
295
+ operations: any[],
296
+ index: number
297
+ ): Promise<StellarSignedTx> => {
298
+ switch (response.type) {
299
+ case 'StellarSignedTx':
300
+ return response.message;
204
301
 
205
- if (isLastOp) {
206
- const response = await this.device.commands.typedCall(type, 'StellarSignedTx', op);
207
- return response.message;
208
- }
302
+ case 'StellarSorobanDataRequest': {
303
+ if (!this.sorobanState) {
304
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'sorobanState not initialized');
305
+ }
209
306
 
210
- await this.device.commands.typedCall(type, 'StellarTxOpRequest', op);
307
+ const reqType = response.message.type as string;
308
+ // data_length 是字节数,转为 hex 字符数
309
+ const hexLen = (response.message.data_length as number) * 2;
310
+ let chunk: string;
311
+
312
+ switch (reqType) {
313
+ // CALL: invoke contract call_args
314
+ case 'CALL': {
315
+ const { callArgs, callArgsSent } = this.sorobanState;
316
+ chunk = callArgs.slice(callArgsSent, callArgsSent + hexLen);
317
+ this.sorobanState.callArgsSent += chunk.length;
318
+ break;
319
+ }
320
+ // AUTH: soroban authorization entries
321
+ case 'AUTH': {
322
+ const { auth, authSent } = this.sorobanState;
323
+ chunk = auth.slice(authSent, authSent + hexLen);
324
+ this.sorobanState.authSent += chunk.length;
325
+ break;
326
+ }
327
+ // EXT: soroban transaction extension data
328
+ case 'EXT': {
329
+ const { ext, extSent } = this.sorobanState;
330
+ chunk = ext.slice(extSent, extSent + hexLen);
331
+ this.sorobanState.extSent += chunk.length;
332
+ break;
333
+ }
334
+ default:
335
+ throw ERRORS.TypedError(
336
+ HardwareErrorCode.RuntimeError,
337
+ `unknown soroban request type: ${reqType}`
338
+ );
339
+ }
340
+
341
+ const sorobanRes = await this.device.commands.typedCall(
342
+ 'StellarSorobanDataAck',
343
+ ['StellarSorobanDataRequest', 'StellarSignedTx'],
344
+ { data_xdr: chunk }
345
+ );
346
+ return this.processTxRequest(sorobanRes, operations, index);
347
+ }
211
348
 
212
- return this.processTxRequest(operations, index + 1);
349
+ case 'StellarTxOpRequest': {
350
+ const { type, ...op } = operations[index];
351
+ const nextRes = await this.device.commands.typedCall(
352
+ type,
353
+ ['StellarTxOpRequest', 'StellarSorobanDataRequest', 'StellarSignedTx'],
354
+ op
355
+ );
356
+ return this.processTxRequest(nextRes, operations, index + 1);
357
+ }
358
+
359
+ default:
360
+ throw ERRORS.TypedError(
361
+ HardwareErrorCode.RuntimeError,
362
+ `unexpected response type: ${response.type}`
363
+ );
364
+ }
213
365
  };
214
366
 
215
367
  async run() {
216
- await this.device.commands.typedCall('StellarSignTx', 'StellarTxOpRequest', { ...this.params });
368
+ const response = await this.device.commands.typedCall('StellarSignTx', 'StellarTxOpRequest', {
369
+ ...this.params,
370
+ });
217
371
 
218
- return this.processTxRequest(this.operations, 0);
372
+ return this.processTxRequest(response, this.operations, 0);
219
373
  }
220
374
  }
@@ -10274,6 +10274,13 @@
10274
10274
  "rule": "required",
10275
10275
  "type": "uint32",
10276
10276
  "id": 14
10277
+ },
10278
+ "soroban_data_size": {
10279
+ "type": "uint32",
10280
+ "id": 60,
10281
+ "options": {
10282
+ "default": 0
10283
+ }
10277
10284
  }
10278
10285
  },
10279
10286
  "nested": {
@@ -10666,6 +10673,76 @@
10666
10673
  }
10667
10674
  }
10668
10675
  },
10676
+ "StellarInvokeHostFunctionOp": {
10677
+ "fields": {
10678
+ "source_account": {
10679
+ "type": "string",
10680
+ "id": 1
10681
+ },
10682
+ "contract_address": {
10683
+ "rule": "required",
10684
+ "type": "string",
10685
+ "id": 2
10686
+ },
10687
+ "function_name": {
10688
+ "rule": "required",
10689
+ "type": "string",
10690
+ "id": 3
10691
+ },
10692
+ "call_args_xdr_size": {
10693
+ "rule": "required",
10694
+ "type": "uint32",
10695
+ "id": 4
10696
+ },
10697
+ "call_args_xdr_initial_chunk": {
10698
+ "rule": "required",
10699
+ "type": "bytes",
10700
+ "id": 5
10701
+ },
10702
+ "soroban_auth_xdr_size": {
10703
+ "rule": "required",
10704
+ "type": "uint32",
10705
+ "id": 6
10706
+ },
10707
+ "soroban_auth_xdr_initial_chunk": {
10708
+ "rule": "required",
10709
+ "type": "bytes",
10710
+ "id": 7
10711
+ }
10712
+ }
10713
+ },
10714
+ "StellarSorobanDataRequest": {
10715
+ "fields": {
10716
+ "type": {
10717
+ "rule": "required",
10718
+ "type": "StellarRequestType",
10719
+ "id": 1
10720
+ },
10721
+ "data_length": {
10722
+ "rule": "required",
10723
+ "type": "uint32",
10724
+ "id": 2
10725
+ }
10726
+ },
10727
+ "nested": {
10728
+ "StellarRequestType": {
10729
+ "values": {
10730
+ "CALL": 0,
10731
+ "AUTH": 1,
10732
+ "EXT": 2
10733
+ }
10734
+ }
10735
+ }
10736
+ },
10737
+ "StellarSorobanDataAck": {
10738
+ "fields": {
10739
+ "data_xdr": {
10740
+ "rule": "required",
10741
+ "type": "bytes",
10742
+ "id": 1
10743
+ }
10744
+ }
10745
+ },
10669
10746
  "StellarSignedTx": {
10670
10747
  "fields": {
10671
10748
  "public_key": {
@@ -12201,6 +12278,9 @@
12201
12278
  "MessageType_StellarManageBuyOfferOp": 222,
12202
12279
  "MessageType_StellarPathPaymentStrictSendOp": 223,
12203
12280
  "MessageType_StellarSignedTx": 230,
12281
+ "MessageType_StellarInvokeHostFunctionOp": 260,
12282
+ "MessageType_StellarSorobanDataRequest": 261,
12283
+ "MessageType_StellarSorobanDataAck": 262,
12204
12284
  "MessageType_CardanoGetPublicKey": 305,
12205
12285
  "MessageType_CardanoPublicKey": 306,
12206
12286
  "MessageType_CardanoGetAddress": 307,
@@ -14,6 +14,7 @@ const Log = getLogger(LoggerNames.Transport);
14
14
  const BleLogger = getLogger(LoggerNames.HdBleTransport);
15
15
  const HttpLogger = getLogger(LoggerNames.HdTransportHttp);
16
16
  const LowLevelLogger = getLogger(LoggerNames.HdTransportLowLevel);
17
+ const NodeUsbLogger = getLogger(LoggerNames.HdTransportNodeUsb);
17
18
  const WebBleLogger = getLogger(LoggerNames.HdWebBleTransport);
18
19
  const WebUsbLogger = getLogger(LoggerNames.HdTransportWebUsb);
19
20
 
@@ -53,11 +54,14 @@ export default class TransportManager {
53
54
  } else {
54
55
  Log.debug('React Native Do Not Initializing transports');
55
56
  }
57
+ } else if (env === 'node-usb') {
58
+ // NodeUsbTransport handles USB I/O directly — no plugin needed
59
+ await this.transport.init(NodeUsbLogger, DevicePool.emitter);
56
60
  } else if (env === 'lowlevel') {
57
61
  if (!this.plugin) {
58
62
  throw ERRORS.TypedError(
59
63
  HardwareErrorCode.TransportNotConfigured,
60
- 'Lowlevel transport mast have plugin'
64
+ 'Lowlevel transport must have plugin'
61
65
  );
62
66
  }
63
67
  await this.transport.init(LowLevelLogger, DevicePool.emitter, this.plugin);
@@ -839,6 +839,7 @@ export class Device extends EventEmitter {
839
839
  skipPassphraseCheck?: boolean
840
840
  ) {
841
841
  if (!this.features) return false;
842
+
842
843
  const { passphraseState: newPassphraseState, unlockedAttachPin } =
843
844
  await getPassphraseStateWithRefreshDeviceInfo(this, {
844
845
  expectPassphraseState: passphraseState,
@@ -110,6 +110,37 @@ type StellarInflationOperation = {
110
110
  source?: string;
111
111
  };
112
112
 
113
+ export type StellarPathPaymentStrictReceiveOperation = {
114
+ type: 'pathPaymentStrictReceive';
115
+ source?: string;
116
+ sendAsset: StellarAsset;
117
+ sendMax: string;
118
+ destination: string;
119
+ destAsset: StellarAsset;
120
+ destAmount: string;
121
+ path?: StellarAsset[];
122
+ };
123
+
124
+ export type StellarPathPaymentStrictSendOperation = {
125
+ type: 'pathPaymentStrictSend';
126
+ source?: string;
127
+ sendAsset: StellarAsset;
128
+ sendAmount: string;
129
+ destination: string;
130
+ destAsset: StellarAsset;
131
+ destMin: string;
132
+ path?: StellarAsset[];
133
+ };
134
+
135
+ export type StellarInvokeHostFunctionOperation = {
136
+ type: 'invokeHostFunctionOneKey';
137
+ source?: string;
138
+ contract: string;
139
+ functionName: string;
140
+ callArgsXDRHex: string;
141
+ sorobanAuthXDRHex: string;
142
+ };
143
+
113
144
  export type StellarOperation =
114
145
  | StellarCreateAccountOperation
115
146
  | StellarPaymentOperation
@@ -122,7 +153,10 @@ export type StellarOperation =
122
153
  | StellarAccountMergeOperation
123
154
  | StellarInflationOperation
124
155
  | StellarManageDataOperation
125
- | StellarBumpSequenceOperation;
156
+ | StellarBumpSequenceOperation
157
+ | StellarPathPaymentStrictReceiveOperation
158
+ | StellarPathPaymentStrictSendOperation
159
+ | StellarInvokeHostFunctionOperation;
126
160
 
127
161
  export type StellarTransaction = {
128
162
  source: string;
@@ -139,6 +173,7 @@ export type StellarTransaction = {
139
173
  hash?: string | Buffer;
140
174
  };
141
175
  operations: StellarOperation[];
176
+ sorobanDataXDR?: string;
142
177
  };
143
178
 
144
179
  export type StellarSignTransactionParams = {
@@ -11,7 +11,8 @@ export type transportEnv =
11
11
  | 'desktop-webusb'
12
12
  | 'desktop-web-ble'
13
13
  | 'emulator'
14
- | 'lowlevel';
14
+ | 'lowlevel'
15
+ | 'node-usb';
15
16
  export type ConnectSettings = {
16
17
  connectSrc?: string;
17
18
  debug?: boolean;
@@ -160,6 +160,7 @@ export enum LoggerNames {
160
160
  HdBleTransport = '@onekey/hd-ble-transport',
161
161
  HdWebBleTransport = '@onekey/hd-web-ble-transport',
162
162
  HdTransportWebUsb = '@onekey/hd-transport-webusb',
163
+ HdTransportNodeUsb = '@onekey/hd-transport-node-usb',
163
164
  Connect = '@onekey/connect',
164
165
  Iframe = 'IFrame',
165
166
  SendMessage = '[SendMessage]',
@@ -180,6 +181,7 @@ export const LoggerMap = {
180
181
  [LoggerNames.HdWebBleTransport]: initLog(LoggerNames.HdWebBleTransport),
181
182
  [LoggerNames.HdTransportLowLevel]: initLog(LoggerNames.HdTransportLowLevel),
182
183
  [LoggerNames.HdTransportWebUsb]: initLog(LoggerNames.HdTransportWebUsb),
184
+ [LoggerNames.HdTransportNodeUsb]: initLog(LoggerNames.HdTransportNodeUsb),
183
185
  [LoggerNames.Connect]: initLog(LoggerNames.Connect),
184
186
  [LoggerNames.Iframe]: initLog(LoggerNames.Iframe),
185
187
  [LoggerNames.SendMessage]: initLog(LoggerNames.SendMessage),