@onekeyfe/hd-core 1.2.8-alpha.125 → 1.2.8-alpha.127
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/__tests__/allNetworkGetAddress-privacy-networks.test.ts +78 -0
- package/__tests__/logBlockEvent.test.ts +292 -0
- package/__tests__/monero-get-address.test.ts +147 -0
- package/__tests__/monero-key-image-sync.test.ts +272 -0
- package/__tests__/monero-sign-transaction.test.ts +436 -0
- package/__tests__/zcash-protobuf.test.ts +141 -0
- package/__tests__/zcash-sign-pczt.test.ts +446 -0
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/helpers/pathUtils.d.ts +1 -0
- package/dist/api/helpers/pathUtils.d.ts.map +1 -1
- package/dist/api/index.d.ts +6 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/monero/MoneroGetAddress.d.ts +11 -0
- package/dist/api/monero/MoneroGetAddress.d.ts.map +1 -0
- package/dist/api/monero/MoneroGetWatchKey.d.ts +11 -0
- package/dist/api/monero/MoneroGetWatchKey.d.ts.map +1 -0
- package/dist/api/monero/MoneroKeyImageSync.d.ts +20 -0
- package/dist/api/monero/MoneroKeyImageSync.d.ts.map +1 -0
- package/dist/api/monero/MoneroSignTransaction.d.ts +17 -0
- package/dist/api/monero/MoneroSignTransaction.d.ts.map +1 -0
- package/dist/api/monero/helpers.d.ts +5 -0
- package/dist/api/monero/helpers.d.ts.map +1 -0
- package/dist/api/zcash/ZcashGetAddress.d.ts +12 -0
- package/dist/api/zcash/ZcashGetAddress.d.ts.map +1 -0
- package/dist/api/zcash/ZcashSignPczt.d.ts +16 -0
- package/dist/api/zcash/ZcashSignPczt.d.ts.map +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts +10 -0
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +1 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +140 -4
- package/dist/index.js +866 -11
- package/dist/inject.d.ts.map +1 -1
- package/dist/types/api/allNetworkGetAddress.d.ts +5 -1
- package/dist/types/api/allNetworkGetAddress.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +6 -0
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +12 -0
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/moneroGetAddress.d.ts +15 -0
- package/dist/types/api/moneroGetAddress.d.ts.map +1 -0
- package/dist/types/api/moneroGetWatchKey.d.ts +15 -0
- package/dist/types/api/moneroGetWatchKey.d.ts.map +1 -0
- package/dist/types/api/moneroKeyImageSync.d.ts +24 -0
- package/dist/types/api/moneroKeyImageSync.d.ts.map +1 -0
- package/dist/types/api/moneroSignTransaction.d.ts +32 -0
- package/dist/types/api/moneroSignTransaction.d.ts.map +1 -0
- package/dist/types/api/zcashGetAddress.d.ts +22 -0
- package/dist/types/api/zcashGetAddress.d.ts.map +1 -0
- package/dist/types/api/zcashSignPczt.d.ts +9 -0
- package/dist/types/api/zcashSignPczt.d.ts.map +1 -0
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +2 -0
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +38 -1
- package/src/api/helpers/pathUtils.ts +23 -0
- package/src/api/index.ts +7 -0
- package/src/api/monero/MoneroGetAddress.ts +71 -0
- package/src/api/monero/MoneroGetWatchKey.ts +69 -0
- package/src/api/monero/MoneroKeyImageSync.ts +164 -0
- package/src/api/monero/MoneroSignTransaction.ts +319 -0
- package/src/api/monero/helpers.ts +28 -0
- package/src/api/zcash/ZcashGetAddress.ts +119 -0
- package/src/api/zcash/ZcashSignPczt.ts +152 -0
- package/src/core/index.ts +4 -3
- package/src/data/messages/messages-protocol-v2.json +138 -1
- package/src/events/logBlockEvent.ts +55 -3
- package/src/events/ui-request.ts +1 -0
- package/src/inject.ts +13 -0
- package/src/types/api/allNetworkGetAddress.ts +9 -1
- package/src/types/api/export.ts +15 -0
- package/src/types/api/index.ts +20 -0
- package/src/types/api/moneroGetAddress.ts +27 -0
- package/src/types/api/moneroGetWatchKey.ts +28 -0
- package/src/types/api/moneroKeyImageSync.ts +45 -0
- package/src/types/api/moneroSignTransaction.ts +54 -0
- package/src/types/api/zcashGetAddress.ts +35 -0
- package/src/types/api/zcashSignPczt.ts +18 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import MoneroKeyImageSync from '../src/api/monero/MoneroKeyImageSync';
|
|
2
|
+
import { getMoneroVersionRange } from '../src/api/monero/helpers';
|
|
3
|
+
import { toHardened } from '../src/api/helpers/pathUtils';
|
|
4
|
+
|
|
5
|
+
import type { Device } from '../src/device/Device';
|
|
6
|
+
import type { MoneroTransferDetails } from '@onekeyfe/hd-transport';
|
|
7
|
+
|
|
8
|
+
jest.mock('../src/data/config', () => ({
|
|
9
|
+
getSDKVersion: jest.fn(() => '1.0.0'),
|
|
10
|
+
DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const ACCOUNT_0 = [toHardened(44), toHardened(128), toHardened(0)];
|
|
14
|
+
const ENC_KEY = 'ee'.repeat(32);
|
|
15
|
+
const key = (byte: number) => byte.toString(16).padStart(2, '0').repeat(32);
|
|
16
|
+
const indexKey = (index: number) => index.toString(16).padStart(64, '0');
|
|
17
|
+
|
|
18
|
+
// Expected values from an independent Keccak-256 over the firmware layout
|
|
19
|
+
// (apps/monero/xmr/key_image.py compute_hash): out_key || tx_pub_key ||
|
|
20
|
+
// additional_tx_pub_keys || uvarint(internal_output_index); the init hash is
|
|
21
|
+
// keccak over the concatenated per-transfer digests (key_image_sync.py).
|
|
22
|
+
const VECTOR_TRANSFERS = [
|
|
23
|
+
{ outKey: key(1), txPubKey: key(2), internalOutputIndex: 0 },
|
|
24
|
+
{ outKey: key(3), txPubKey: key(4), additionalTxPubKeys: [key(5)], internalOutputIndex: 300 },
|
|
25
|
+
];
|
|
26
|
+
const VECTOR_HASH = '66dfea8ea33dd0b1165d4729e71117f796eb43d58e452e7c3885d9de859d43c3';
|
|
27
|
+
|
|
28
|
+
type StepMessage = { tdis?: MoneroTransferDetails[] };
|
|
29
|
+
|
|
30
|
+
// Fake device: one encrypted key image per transfer, tagged by its out_key.
|
|
31
|
+
const fakeDevice = (type: string, _resType: string, msg?: StepMessage) => {
|
|
32
|
+
switch (type) {
|
|
33
|
+
case 'MoneroKeyImageExportInitRequest':
|
|
34
|
+
return Promise.resolve({ type: 'MoneroKeyImageExportInitAck', message: {} });
|
|
35
|
+
case 'MoneroKeyImageSyncStepRequest':
|
|
36
|
+
return Promise.resolve({
|
|
37
|
+
type: 'MoneroKeyImageSyncStepAck',
|
|
38
|
+
message: {
|
|
39
|
+
kis: (msg?.tdis ?? []).map(td => ({
|
|
40
|
+
iv: td.out_key?.slice(0, 24),
|
|
41
|
+
blob: `b0${td.out_key}`,
|
|
42
|
+
})),
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
case 'MoneroKeyImageSyncFinalRequest':
|
|
46
|
+
return Promise.resolve({ type: 'MoneroKeyImageSyncFinalAck', message: { enc_key: ENC_KEY } });
|
|
47
|
+
default:
|
|
48
|
+
return Promise.reject(new Error(`unexpected ${type}`));
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const createTypedCall = () => jest.fn(fakeDevice);
|
|
53
|
+
|
|
54
|
+
const attachDevice = (method: MoneroKeyImageSync, typedCall: jest.Mock) => {
|
|
55
|
+
const commands = { typedCall };
|
|
56
|
+
method.device = {
|
|
57
|
+
commands,
|
|
58
|
+
getCommands: () => commands,
|
|
59
|
+
toMessageObject: () => ({}),
|
|
60
|
+
} as unknown as Device;
|
|
61
|
+
method.postMessage = jest.fn();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const createMethod = (payload: Record<string, unknown>) =>
|
|
65
|
+
new MoneroKeyImageSync({ id: 1, payload: { method: 'moneroKeyImageSync', ...payload } });
|
|
66
|
+
|
|
67
|
+
const transferAt = (index: number) => ({
|
|
68
|
+
outKey: indexKey(index),
|
|
69
|
+
txPubKey: key(0xaa),
|
|
70
|
+
internalOutputIndex: index,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('MoneroKeyImageSync', () => {
|
|
74
|
+
test('uses the Monero device rules of the other Monero methods', () => {
|
|
75
|
+
const method = createMethod({ path: "m/44'/128'/0'", transfers: [transferAt(0)] });
|
|
76
|
+
method.init();
|
|
77
|
+
|
|
78
|
+
expect(method.getSupportedProtocols()).toEqual(['V1', 'V2']);
|
|
79
|
+
expect(method.strictCheckDeviceSupport).toBe(true);
|
|
80
|
+
expect(method.checkDeviceId).toBe(true);
|
|
81
|
+
expect(method.getVersionRange()).toEqual(getMoneroVersionRange());
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('commits to the transfers with the firmware hash and returns the key images', async () => {
|
|
85
|
+
const method = createMethod({
|
|
86
|
+
path: "m/44'/128'/0'",
|
|
87
|
+
networkType: 2,
|
|
88
|
+
transfers: VECTOR_TRANSFERS,
|
|
89
|
+
});
|
|
90
|
+
method.init();
|
|
91
|
+
const typedCall = createTypedCall();
|
|
92
|
+
attachDevice(method, typedCall);
|
|
93
|
+
|
|
94
|
+
await expect(method.run()).resolves.toEqual({
|
|
95
|
+
encKey: ENC_KEY,
|
|
96
|
+
keyImages: [
|
|
97
|
+
{ iv: key(1).slice(0, 24), blob: `b0${key(1)}` },
|
|
98
|
+
{ iv: key(3).slice(0, 24), blob: `b0${key(3)}` },
|
|
99
|
+
],
|
|
100
|
+
});
|
|
101
|
+
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
102
|
+
'MoneroKeyImageExportInitRequest',
|
|
103
|
+
'MoneroKeyImageSyncStepRequest',
|
|
104
|
+
'MoneroKeyImageSyncFinalRequest',
|
|
105
|
+
]);
|
|
106
|
+
expect(typedCall.mock.calls[0]).toEqual([
|
|
107
|
+
'MoneroKeyImageExportInitRequest',
|
|
108
|
+
'MoneroKeyImageExportInitAck',
|
|
109
|
+
{ num: 2, hash: VECTOR_HASH, address_n: ACCOUNT_0, network_type: 2, subs: [] },
|
|
110
|
+
]);
|
|
111
|
+
expect(typedCall.mock.calls[1][2]).toEqual({
|
|
112
|
+
tdis: [
|
|
113
|
+
{
|
|
114
|
+
out_key: key(1),
|
|
115
|
+
tx_pub_key: key(2),
|
|
116
|
+
additional_tx_pub_keys: [],
|
|
117
|
+
internal_output_index: 0,
|
|
118
|
+
sub_addr_major: 0,
|
|
119
|
+
sub_addr_minor: 0,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
out_key: key(3),
|
|
123
|
+
tx_pub_key: key(4),
|
|
124
|
+
additional_tx_pub_keys: [key(5)],
|
|
125
|
+
internal_output_index: 300,
|
|
126
|
+
sub_addr_major: 0,
|
|
127
|
+
sub_addr_minor: 0,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
|
+
expect(typedCall.mock.calls[2][2]).toEqual({});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('hashes an output index above 2^31 as a full varint', async () => {
|
|
135
|
+
const method = createMethod({
|
|
136
|
+
path: "m/44'/128'/0'",
|
|
137
|
+
transfers: [{ outKey: key(1), txPubKey: key(2), internalOutputIndex: 2 ** 35 + 5 }],
|
|
138
|
+
});
|
|
139
|
+
method.init();
|
|
140
|
+
const typedCall = createTypedCall();
|
|
141
|
+
attachDevice(method, typedCall);
|
|
142
|
+
|
|
143
|
+
await method.run();
|
|
144
|
+
// uvarint(2^35 + 5) = 85 80 80 80 80 01
|
|
145
|
+
expect(typedCall.mock.calls[0][2]).toMatchObject({
|
|
146
|
+
hash: '38d7a92307938e332a62a5c8acb706638dd07a0cbb38c6cbbd8cb90049dd2d5c',
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('normalizes hex keys and keeps the subaddress index', () => {
|
|
151
|
+
const method = createMethod({
|
|
152
|
+
path: [toHardened(44), toHardened(128), toHardened(3)],
|
|
153
|
+
transfers: [
|
|
154
|
+
{
|
|
155
|
+
outKey: `0x${key(0xab).toUpperCase()}`,
|
|
156
|
+
txPubKey: key(0xcd),
|
|
157
|
+
internalOutputIndex: 1,
|
|
158
|
+
subAddrMajor: 2,
|
|
159
|
+
subAddrMinor: 7,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
});
|
|
163
|
+
method.init();
|
|
164
|
+
|
|
165
|
+
expect(method.params.address_n).toEqual([toHardened(44), toHardened(128), toHardened(3)]);
|
|
166
|
+
expect(method.params.network_type).toBe(0);
|
|
167
|
+
expect(method.params.tdis[0]).toMatchObject({
|
|
168
|
+
out_key: key(0xab),
|
|
169
|
+
sub_addr_major: 2,
|
|
170
|
+
sub_addr_minor: 7,
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('sends transfers in steps of 10 and keeps the key images in order', async () => {
|
|
175
|
+
const transfers = Array.from({ length: 23 }, (_, i) => transferAt(i));
|
|
176
|
+
const method = createMethod({ path: "m/44'/128'/0'", transfers });
|
|
177
|
+
method.init();
|
|
178
|
+
const typedCall = createTypedCall();
|
|
179
|
+
attachDevice(method, typedCall);
|
|
180
|
+
|
|
181
|
+
const result = (await method.run()) as { keyImages: { blob: string }[] };
|
|
182
|
+
|
|
183
|
+
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
184
|
+
'MoneroKeyImageExportInitRequest',
|
|
185
|
+
'MoneroKeyImageSyncStepRequest',
|
|
186
|
+
'MoneroKeyImageSyncStepRequest',
|
|
187
|
+
'MoneroKeyImageSyncStepRequest',
|
|
188
|
+
'MoneroKeyImageSyncFinalRequest',
|
|
189
|
+
]);
|
|
190
|
+
expect(typedCall.mock.calls[0][2]).toMatchObject({ num: 23 });
|
|
191
|
+
const steps = typedCall.mock.calls.slice(1, 4).map(call => call[2].tdis);
|
|
192
|
+
expect(steps.map(step => step.length)).toEqual([10, 10, 3]);
|
|
193
|
+
expect(steps.flat().map((td: MoneroTransferDetails) => td.internal_output_index)).toEqual(
|
|
194
|
+
transfers.map(transfer => transfer.internalOutputIndex)
|
|
195
|
+
);
|
|
196
|
+
expect(result.keyImages.map(ki => ki.blob)).toEqual(
|
|
197
|
+
transfers.map(transfer => `b0${transfer.outKey}`)
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const withTransfer = (fields: Record<string, unknown>) => ({
|
|
202
|
+
transfers: [{ ...transferAt(0), ...fields }],
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test.each([
|
|
206
|
+
['missing transfers', {}, /Missing required parameter: transfers/],
|
|
207
|
+
['empty transfers', { transfers: [] }, /"transfers" is empty/],
|
|
208
|
+
['a non-array transfers', { transfers: 'abc' }, /\[transfers\]/],
|
|
209
|
+
['a short outKey', withTransfer({ outKey: key(1).slice(2) }), /\.outKey must be/],
|
|
210
|
+
['a non-hex txPubKey', withTransfer({ txPubKey: 'zz'.repeat(32) }), /\.txPubKey must be/],
|
|
211
|
+
[
|
|
212
|
+
'a short additional key',
|
|
213
|
+
withTransfer({ additionalTxPubKeys: ['00'] }),
|
|
214
|
+
/\.additionalTxPubKeys\[0\] must be/,
|
|
215
|
+
],
|
|
216
|
+
[
|
|
217
|
+
'a non-array additionalTxPubKeys',
|
|
218
|
+
withTransfer({ additionalTxPubKeys: key(5) }),
|
|
219
|
+
/\.additionalTxPubKeys must be an array/,
|
|
220
|
+
],
|
|
221
|
+
[
|
|
222
|
+
'a missing output index',
|
|
223
|
+
{ transfers: [{ outKey: key(1), txPubKey: key(2) }] },
|
|
224
|
+
/\.internalOutputIndex must be/,
|
|
225
|
+
],
|
|
226
|
+
['a negative output index', withTransfer({ internalOutputIndex: -1 }), /internalOutputIndex/],
|
|
227
|
+
[
|
|
228
|
+
'a fractional output index',
|
|
229
|
+
withTransfer({ internalOutputIndex: 1.5 }),
|
|
230
|
+
/internalOutputIndex/,
|
|
231
|
+
],
|
|
232
|
+
[
|
|
233
|
+
'an out of range subaddress',
|
|
234
|
+
withTransfer({ subAddrMajor: 2 ** 32 }),
|
|
235
|
+
/\.subAddrMajor must be/,
|
|
236
|
+
],
|
|
237
|
+
['an unknown network type', { transfers: [transferAt(0)], networkType: 3 }, /network type/],
|
|
238
|
+
[
|
|
239
|
+
'a fractional account',
|
|
240
|
+
{ transfers: [transferAt(0)], path: "m/44'/128'/0.5'" },
|
|
241
|
+
/Not a valid path/,
|
|
242
|
+
],
|
|
243
|
+
])('rejects %s', (_, params, message) => {
|
|
244
|
+
expect(() => createMethod({ path: "m/44'/128'/0'", ...params }).init()).toThrow(message);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test('fails when a step returns fewer key images than transfers', async () => {
|
|
248
|
+
const method = createMethod({ path: "m/44'/128'/0'", transfers: VECTOR_TRANSFERS });
|
|
249
|
+
method.init();
|
|
250
|
+
const typedCall = jest.fn((type: string, resType: string, msg?: StepMessage) =>
|
|
251
|
+
type === 'MoneroKeyImageSyncStepRequest'
|
|
252
|
+
? Promise.resolve({ type: resType, message: { kis: [{ iv: '00', blob: '00' }] } })
|
|
253
|
+
: fakeDevice(type, resType, msg)
|
|
254
|
+
);
|
|
255
|
+
attachDevice(method, typedCall);
|
|
256
|
+
|
|
257
|
+
await expect(method.run()).rejects.toThrow(/Expected array length of 2/);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test('fails when the device omits the encryption key', async () => {
|
|
261
|
+
const method = createMethod({ path: "m/44'/128'/0'", transfers: VECTOR_TRANSFERS });
|
|
262
|
+
method.init();
|
|
263
|
+
const typedCall = jest.fn((type: string, resType: string, msg?: StepMessage) =>
|
|
264
|
+
type === 'MoneroKeyImageSyncFinalRequest'
|
|
265
|
+
? Promise.resolve({ type: resType, message: { enc_key: null } })
|
|
266
|
+
: fakeDevice(type, resType, msg)
|
|
267
|
+
);
|
|
268
|
+
attachDevice(method, typedCall);
|
|
269
|
+
|
|
270
|
+
await expect(method.run()).rejects.toThrow(/encKey/);
|
|
271
|
+
});
|
|
272
|
+
});
|