Skip to content

Commit 3bb38cb

Browse files
Feat/ton sign data (#778)
* feat(ton): add tonSignData method for TON Connect v2 signData - New `tonSignData` method dispatching firmware TonSignData/TonSignedData for text/binary/cell payload signing, mirroring the TonSignProof shape. - Re-export TonSignDataType as a runtime value from @onekeyfe/hd-core so consumers can use the enum (previously only re-exported as a type, so `TonSignDataType.TEXT` threw at runtime). - Map firmware Failure_PinMismatch to new HardwareErrorCode.PinMismatch (828); surfaced only in set/change-PIN flows, so not added to the session-release list. - Regenerate hd-transport messages.ts and core messages.json from the updated firmware proto. * refactor(hwk-ledger-adapter): unify UI events and legacy SDK lifecycle App-side now subscribes hardware UI events from a single hw.on(...) bus instead of mixing connector.on('ui-event') with hw.on(UI_REQUEST.X). LedgerAdapter forwards the connector 'ui-event' channel onto its own emitter so the four EConnectorInteraction values (ConfirmOnDevice / ConfirmOpenApp / UnlockDevice / InteractionComplete) reach consumers through the same surface as REQUEST_DEVICE_PERMISSION etc. The dead 'ui-request_confirmation' → REQUEST_BUTTON path and its 'ui-request' listener are removed. Legacy-SDK chains (TRON today, future XRP/ADA/DOT) now go through a single withLegacyChainCall wrapper that owns the full lifecycle: pre-flight ensureAppOpen, ConfirmOnDevice/InteractionComplete pairing, wrong-app retry, and symmetric UI cleanup on failure paths. TRON handlers shrink ~40% and stop reimplementing the open-app boilerplate. AppManager.ensureAppOpen invokes the onConfirmOnDevice callback BEFORE issuing the blocking OpenAppCommand APDU; previously the prompt event fired after the user had already confirmed on-device, so UI consumers showed and immediately closed the "open app" toast. The fallback path also closes any lingering ConfirmOpenApp prompt when ensureAppOpen itself throws (e.g. 0x6807 app-not-installed). mapLedgerError accepts an optional defaultAppName so DMK signer errors (which lack appName) get a chain-bound fallback. LedgerConnectorBase .dispatcher injects this once per call via _ctxForMethod, keeping chain handlers' wrapError calls a single line. Downstream the App layer's ThirdPartyAppNotInstalled toast can interpolate {appName} across all chains, not just TRON. Adds focused debug logs at points where, when bugs occur, no upstream log can localize the failure: AppManager (currentApp / closeApp / openApp statusCode / waitForApp exhausted), legacyChainCall decision points (pre-flight failure / non-wrong-app / wrong-app retry / retry failure / retry success), and BTC wallet template selection. * fix(hwk-ledger-adapter): stop duplicating the same device with mismatched labels Two independent bugs combined to make a single physical Ledger appear as two devices in the discovered list — one labelled with its real name and one labelled "Ledger". 1. LedgerAdapter.searchDevices() accumulated entries instead of replacing them. DMK assigns ephemeral UUIDs as USB device paths (which we use as connectId), so each replug produced a fresh connectId while the prior connectId still sat in the cache pointing at a device DMK no longer recognized. Fix: clear the cache before writing this round's raw result so it always reflects current discovery state. 2. LedgerConnectorBase.connect() emitted 'device-connect' with a hardcoded `name: 'Ledger'` placeholder. The adapter's deviceConnectHandler then wrote that placeholder over the real label that searchDevices() had just stored. Fix: capture the searchDevices() return value at connect entry and emit the real name found by connectId; fall back to 'Ledger' only if the device isn't in this round's discovery. Both fixes are required: clearing the cache without fixing the emit still leaves the active device's label clobbered by the placeholder; fixing the emit without clearing the cache still leaves stale connectId entries from prior plug events. * chore: release 1.1.26-alpha.9 * refactor(hwk-ledger-adapter): replace setDebugEnabled with setLogger sink Hosts now inject a typed logger callback instead of toggling a boolean to switch console output on/off. Makes SDK debug output flow into the host's existing logging pipeline (e.g. defaultLogger.hardware.sdkLog). setLogger((level, ...args) => { ... }) // host-supplied debugLog('[X]', value) // routed through the injected sink Removes setDebugEnabled / isDebugEnabled. SDK no longer holds a console-output flag; not injecting a logger means the SDK is silent. Cross-runtime note: this module's `logger` is a per-process singleton. Hosts that span multiple runtimes (e.g. MV3 extensions where the SW holds the adapter and an offscreen document holds the connector) must call setLogger from each runtime — they don't share state. * refactor(hwk-ledger-adapter): unify SDK events behind onSdkEvent bus Replaces the single-sink setLogger callback with a typed event bus, matching the pattern OneKey's own hd-core uses (addHardwareGlobalEventListener). onSdkEvent((event) => { if (event.type === 'log') /* ... */ }) `SdkEvent` is a discriminated union — currently `{ type: 'log', level, message }`. Future variants (firmware progress, battery state, ...) extend the union and host adapters dispatch via the same subscription. Why this matters for cross-runtime integration: hosts that span SW ↔ offscreen (MV3 extensions) or main ↔ renderer (Electron) wire one IPC channel that forwards the whole `SdkEvent` payload. Adding a new event variant doesn't require a new IPC route, a new subscriber, or a new host-side handler — the dispatch is data-driven on `event.type`. debugLog/debugError now `emitSdkEvent({type: 'log', ...})` internally; hosts that want logs subscribe and route to their logger pipeline. With no subscribers the bus skips stringification, so the SDK has zero overhead when nobody's listening. Removes setLogger / Logger / LogLevel exports. * chore(hwk-ledger-adapter): log DMK signer interactions; trim sdkEventBus comments Adds a single debugLog at each chain's signer.onInteraction site so the raw DMK interaction string (verify-address / sign-transaction / confirm-open-app / interaction-complete / unlock-device / ...) is visible in the host's SDK log scope. Without it, the entire device-side state machine between IO start and IO end is a black box — useful for diagnosing UI-event timing questions like "did verify-address actually fire on the device" or "where did app-switch insert itself". Trims redundant prose from sdkEventBus.ts and debugLog.ts that the file header / function name already conveys. * chore: release 1.1.26-alpha.10 * fix: address PR review feedback - TonSignData: restore getVersionRange(). With strictCheckDeviceSupport=true the core consults this method's version matrix; an empty range causes every device to be classified as unsupported and the TonSignData typedCall is rejected before run() ever fires. Aligned with TonSignMessage's getFixInitStateErrorVersionRange — bump when the firmware ships TonSignData. - LedgerConnectorBase.call: stop logging full call params via JSON.stringify(params). Now that debugLog flows through onSdkEvent into the host's defaultLogger pipeline, sensitive payloads (serializedTx, psbt, rawTxHex, messageHex, typed data) would propagate to telemetry / persistent stores. Replaced with summarizeCallParams() which surfaces only path, length-of-payload, and harmless flags. * revert: roll back PR review fixes per maintainer call - TonSignData: drop strictCheckDeviceSupport (set to false) and remove getVersionRange(). Firmware version that ships TonSignData isn't decided yet; gating now would lock out every connected device. Re-enable both once the touch/classic1s min versions are known. - LedgerConnectorBase.call: restore JSON.stringify(params) in debugLog. Log bus only feeds the host's local defaultLogger pipeline (no third-party telemetry forwarding), so full params are acceptable for now and useful for in-the-wild debugging.
1 parent 7b8e0ff commit 3bb38cb

65 files changed

Lines changed: 1092 additions & 533 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/connect-examples/electron-example/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "hardware-example",
33
"productName": "HardwareExample",
44
"executableName": "onekey-hardware-example",
5-
"version": "1.1.26-alpha.8",
5+
"version": "1.1.26-alpha.11",
66
"author": "OneKey",
77
"description": "End-to-end encrypted workspaces for teams",
88
"main": "dist/index.js",
@@ -22,7 +22,7 @@
2222
"ts:check": "yarn tsc --noEmit"
2323
},
2424
"dependencies": {
25-
"@onekeyfe/hd-transport-electron": "1.1.26-alpha.8",
25+
"@onekeyfe/hd-transport-electron": "1.1.26-alpha.11",
2626
"@stoprocent/noble": "2.3.16",
2727
"debug": "4.3.4",
2828
"electron-is-dev": "^3.0.1",

packages/connect-examples/expo-example/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "expo-example",
3-
"version": "1.1.26-alpha.8",
3+
"version": "1.1.26-alpha.11",
44
"scripts": {
55
"start": "cross-env CONNECT_SRC=https://localhost:8087/ yarn expo start --dev-client",
66
"android": "yarn expo run:android",
@@ -19,10 +19,10 @@
1919
"@noble/ed25519": "^2.1.0",
2020
"@noble/hashes": "^1.3.3",
2121
"@noble/secp256k1": "^1.7.1",
22-
"@onekeyfe/hd-ble-sdk": "1.1.26-alpha.8",
23-
"@onekeyfe/hd-common-connect-sdk": "1.1.26-alpha.8",
24-
"@onekeyfe/hd-core": "1.1.26-alpha.8",
25-
"@onekeyfe/hd-web-sdk": "1.1.26-alpha.8",
22+
"@onekeyfe/hd-ble-sdk": "1.1.26-alpha.11",
23+
"@onekeyfe/hd-common-connect-sdk": "1.1.26-alpha.11",
24+
"@onekeyfe/hd-core": "1.1.26-alpha.11",
25+
"@onekeyfe/hd-web-sdk": "1.1.26-alpha.11",
2626
"@onekeyfe/react-native-ble-utils": "^0.1.3",
2727
"@polkadot/util-crypto": "13.1.1",
2828
"@react-native-async-storage/async-storage": "1.21.0",

packages/connect-examples/expo-example/src/data/ton.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,62 @@ const api: PlaygroundProps[] = [
164164
},
165165
],
166166
},
167+
{
168+
method: 'tonSignData',
169+
description: 'Sign Data (TON Connect signData)',
170+
presupposes: [
171+
{
172+
title: 'Text',
173+
value: {
174+
path: "m/44'/607'/0'",
175+
// TonSignDataType.TEXT = 0
176+
type: 0,
177+
// hex of "Hello OneKey"
178+
payload: '48656c6c6f204f6e654b6579',
179+
appdomain: 'onekey.so',
180+
timestamp: Math.floor(Date.now() / 1000),
181+
fromAddress: 'UQBYkuShkZzRYAWX_HrK3kFpeAixiRKd-K7QBXYxl9OBXM0_',
182+
walletVersion: 3,
183+
isBounceable: false,
184+
isTestnetOnly: false,
185+
},
186+
},
187+
{
188+
title: 'Binary',
189+
value: {
190+
path: "m/44'/607'/0'",
191+
// TonSignDataType.BINARY = 1
192+
type: 1,
193+
// arbitrary binary bytes as hex
194+
payload: '00112233445566778899aabbccddeeff',
195+
appdomain: 'onekey.so',
196+
timestamp: Math.floor(Date.now() / 1000),
197+
fromAddress: 'UQBYkuShkZzRYAWX_HrK3kFpeAixiRKd-K7QBXYxl9OBXM0_',
198+
walletVersion: 3,
199+
isBounceable: false,
200+
isTestnetOnly: false,
201+
},
202+
},
203+
{
204+
title: 'Cell',
205+
value: {
206+
path: "m/44'/607'/0'",
207+
// TonSignDataType.CELL = 2
208+
type: 2,
209+
// BoC hex of the cell payload
210+
payload: 'b5ee9c7241010101000e000018000000004f6e654b65792043656c6c3cc87b8a',
211+
// TL-B schema of the cell payload (required by TON Connect for cell type)
212+
schema: 'text_comment#00000000 text:string = InternalMsgBody;',
213+
appdomain: 'onekey.so',
214+
timestamp: Math.floor(Date.now() / 1000),
215+
fromAddress: 'UQBYkuShkZzRYAWX_HrK3kFpeAixiRKd-K7QBXYxl9OBXM0_',
216+
walletVersion: 3,
217+
isBounceable: false,
218+
isTestnetOnly: false,
219+
},
220+
},
221+
],
222+
},
167223
];
168224

169225
export default api;

packages/connect-examples/expo-playground/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "onekey-hardware-playground",
3-
"version": "1.1.26-alpha.8",
3+
"version": "1.1.26-alpha.11",
44
"private": true,
55
"sideEffects": [
66
"app/utils/shim.js",
@@ -17,9 +17,9 @@
1717
},
1818
"dependencies": {
1919
"@noble/hashes": "^1.8.0",
20-
"@onekeyfe/hd-common-connect-sdk": "1.1.26-alpha.8",
21-
"@onekeyfe/hd-core": "1.1.26-alpha.8",
22-
"@onekeyfe/hd-shared": "1.1.26-alpha.8",
20+
"@onekeyfe/hd-common-connect-sdk": "1.1.26-alpha.11",
21+
"@onekeyfe/hd-core": "1.1.26-alpha.11",
22+
"@onekeyfe/hd-shared": "1.1.26-alpha.11",
2323
"@radix-ui/react-checkbox": "^1.3.2",
2424
"@radix-ui/react-dialog": "^1.1.14",
2525
"@radix-ui/react-dropdown-menu": "^2.1.15",

packages/core/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@onekeyfe/hd-core",
3-
"version": "1.1.26-alpha.8",
3+
"version": "1.1.26-alpha.11",
44
"description": "Core processes and APIs for communicating with OneKey hardware devices.",
55
"author": "OneKey",
66
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
@@ -25,8 +25,8 @@
2525
"url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
2626
},
2727
"dependencies": {
28-
"@onekeyfe/hd-shared": "1.1.26-alpha.8",
29-
"@onekeyfe/hd-transport": "1.1.26-alpha.8",
28+
"@onekeyfe/hd-shared": "1.1.26-alpha.11",
29+
"@onekeyfe/hd-transport": "1.1.26-alpha.11",
3030
"axios": "1.15.2",
3131
"bignumber.js": "^9.0.2",
3232
"bytebuffer": "^5.0.1",

packages/core/src/api/alephium/AlephiumSignTransaction.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import {
2-
type AlephiumSignedTx,
3-
type AlephiumSignTx as HardwareAlephiumSignTx,
4-
TypedCall,
5-
} from '@onekeyfe/hd-transport';
61
import { bytesToHex } from '@noble/hashes/utils';
72
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
83

94
import { UI_REQUEST } from '../../constants/ui-request';
105
import { validatePath } from '../helpers/pathUtils';
116
import { BaseMethod } from '../BaseMethod';
127
import { validateParams } from '../helpers/paramsValidator';
8+
9+
import type {
10+
AlephiumSignedTx,
11+
AlephiumSignTx as HardwareAlephiumSignTx,
12+
TypedCall,
13+
} from '@onekeyfe/hd-transport';
1314
import type { AlephiumSignTransactionParams } from '../../types';
1415
import type { TypedResponseMessage } from '../../device/DeviceCommands';
1516

packages/core/src/api/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ export { default as dnxSignTransaction } from './dynex/DnxSignTransaction';
143143
export { default as tonGetAddress } from './ton/TonGetAddress';
144144
export { default as tonSignMessage } from './ton/TonSignMessage';
145145
export { default as tonSignProof } from './ton/TonSignProof';
146+
export { default as tonSignData } from './ton/TonSignData';
146147

147148
export { default as scdoGetAddress } from './scdo/ScdoGetAddress';
148149
export { default as scdoSignTransaction } from './scdo/ScdoSignTransaction';
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { UI_REQUEST } from '../../constants/ui-request';
2+
import { validatePath } from '../helpers/pathUtils';
3+
import { BaseMethod } from '../BaseMethod';
4+
import { validateParams } from '../helpers/paramsValidator';
5+
import { formatAnyHex } from '../helpers/hexUtils';
6+
7+
import type { TonSignData as HardwareTonSignData } from '@onekeyfe/hd-transport';
8+
import type { TonSignDataParams } from '../../types/api/tonSignData';
9+
10+
export default class TonSignData extends BaseMethod<HardwareTonSignData> {
11+
init() {
12+
// Keep strict-check off until the firmware release that ships TonSignData
13+
// is decided — we don't yet know the min versions for touch/classic1s.
14+
// Flip back to true and add getVersionRange() once those numbers land.
15+
this.strictCheckDeviceSupport = false;
16+
this.checkDeviceId = true;
17+
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
18+
19+
validateParams(this.payload, [
20+
{ name: 'path', required: true },
21+
{ name: 'type', type: 'number', required: true },
22+
{ name: 'payload', type: 'hexString', required: true },
23+
{ name: 'schema', type: 'string' },
24+
{ name: 'appdomain', type: 'string', required: true },
25+
{ name: 'timestamp', required: true },
26+
{ name: 'fromAddress', type: 'string' },
27+
{ name: 'walletVersion' },
28+
{ name: 'walletId', type: 'number' },
29+
{ name: 'workchain' },
30+
{ name: 'isBounceable', type: 'boolean' },
31+
{ name: 'isTestnetOnly', type: 'boolean' },
32+
]);
33+
34+
const { path } = this.payload as TonSignDataParams;
35+
const addressN = validatePath(path, 3);
36+
37+
this.params = {
38+
address_n: addressN,
39+
type: this.payload.type,
40+
payload: formatAnyHex(this.payload.payload),
41+
schema: this.payload.schema,
42+
appdomain: this.payload.appdomain,
43+
timestamp: this.payload.timestamp,
44+
from_address: this.payload.fromAddress,
45+
wallet_version: this.payload.walletVersion,
46+
wallet_id: this.payload.walletId,
47+
workchain: this.payload.workchain,
48+
is_bounceable: this.payload.isBounceable,
49+
is_testnet_only: this.payload.isTestnetOnly,
50+
};
51+
}
52+
53+
async run() {
54+
const res = await this.device.commands.typedCall('TonSignData', 'TonSignedData', {
55+
...this.params,
56+
});
57+
58+
return Promise.resolve(res.message);
59+
}
60+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export { safeThrowError } from './errors';
2-
export { Messages as PROTO } from '@onekeyfe/hd-transport';
2+
export { Messages as PROTO, TonSignDataType } from '@onekeyfe/hd-transport';

packages/core/src/data/messages/messages.json

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11569,6 +11569,102 @@
1156911569
}
1157011570
}
1157111571
},
11572+
"TonSignData": {
11573+
"fields": {
11574+
"address_n": {
11575+
"rule": "repeated",
11576+
"type": "uint32",
11577+
"id": 1,
11578+
"options": {
11579+
"packed": false
11580+
}
11581+
},
11582+
"type": {
11583+
"rule": "required",
11584+
"type": "TonSignDataType",
11585+
"id": 2
11586+
},
11587+
"payload": {
11588+
"rule": "required",
11589+
"type": "bytes",
11590+
"id": 3
11591+
},
11592+
"schema": {
11593+
"type": "string",
11594+
"id": 4
11595+
},
11596+
"appdomain": {
11597+
"rule": "required",
11598+
"type": "string",
11599+
"id": 5
11600+
},
11601+
"timestamp": {
11602+
"rule": "required",
11603+
"type": "uint64",
11604+
"id": 6
11605+
},
11606+
"from_address": {
11607+
"type": "string",
11608+
"id": 7
11609+
},
11610+
"wallet_version": {
11611+
"type": "TonWalletVersion",
11612+
"id": 8,
11613+
"options": {
11614+
"default": "V4R2"
11615+
}
11616+
},
11617+
"wallet_id": {
11618+
"type": "uint32",
11619+
"id": 9,
11620+
"options": {
11621+
"default": 698983191
11622+
}
11623+
},
11624+
"workchain": {
11625+
"type": "TonWorkChain",
11626+
"id": 10,
11627+
"options": {
11628+
"default": "BASECHAIN"
11629+
}
11630+
},
11631+
"is_bounceable": {
11632+
"type": "bool",
11633+
"id": 11,
11634+
"options": {
11635+
"default": false
11636+
}
11637+
},
11638+
"is_testnet_only": {
11639+
"type": "bool",
11640+
"id": 12,
11641+
"options": {
11642+
"default": false
11643+
}
11644+
}
11645+
},
11646+
"nested": {
11647+
"TonSignDataType": {
11648+
"values": {
11649+
"TEXT": 0,
11650+
"BINARY": 1,
11651+
"CELL": 2
11652+
}
11653+
}
11654+
}
11655+
},
11656+
"TonSignedData": {
11657+
"fields": {
11658+
"signature": {
11659+
"type": "bytes",
11660+
"id": 1
11661+
},
11662+
"digest": {
11663+
"type": "bytes",
11664+
"id": 2
11665+
}
11666+
}
11667+
},
1157211668
"TronGetAddress": {
1157311669
"fields": {
1157411670
"address_n": {
@@ -12501,6 +12597,8 @@
1250112597
"MessageType_TonSignProof": 11905,
1250212598
"MessageType_TonSignedProof": 11906,
1250312599
"MessageType_TonTxAck": 11907,
12600+
"MessageType_TonSignData": 11908,
12601+
"MessageType_TonSignedData": 11909,
1250412602
"MessageType_ScdoGetAddress": 12001,
1250512603
"MessageType_ScdoAddress": 12002,
1250612604
"MessageType_ScdoSignTx": 12003,

0 commit comments

Comments
 (0)