@alephium/ledger-app 0.2.1 → 0.4.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.
@@ -0,0 +1,383 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const src_1 = __importStar(require("../src"));
30
+ const web3_1 = require("@alephium/web3");
31
+ const web3_test_1 = require("@alephium/web3-test");
32
+ const web3_wallet_1 = require("@alephium/web3-wallet");
33
+ const blakejs_1 = __importDefault(require("blakejs"));
34
+ const utils_1 = require("./utils");
35
+ describe('ledger wallet', () => {
36
+ const nodeProvider = new web3_1.NodeProvider("http://127.0.0.1:22973");
37
+ web3_1.web3.setCurrentNodeProvider(nodeProvider);
38
+ let pathIndex;
39
+ let path;
40
+ beforeEach(() => {
41
+ pathIndex = (0, utils_1.getRandomInt)(0, 1000000);
42
+ path = `m/44'/1234'/0'/0/` + pathIndex;
43
+ });
44
+ async function transferToAddress(address, amount = web3_1.ONE_ALPH * 10n) {
45
+ const balance0 = await getALPHBalance(address);
46
+ const fromAccount = await (0, web3_test_1.getSigner)();
47
+ const transferResult = await (0, web3_test_1.transfer)(fromAccount, address, web3_1.ALPH_TOKEN_ID, amount);
48
+ await (0, web3_1.waitForTxConfirmation)(transferResult.txId, 1, 1000);
49
+ const balance1 = await getALPHBalance(address);
50
+ expect(balance1 - balance0).toEqual(amount);
51
+ }
52
+ async function getALPHBalance(address) {
53
+ const balances = await nodeProvider.addresses.getAddressesAddressBalance(address);
54
+ return BigInt(balances.balance);
55
+ }
56
+ it('should get version', async () => {
57
+ const transport = await (0, utils_1.createTransport)();
58
+ const app = new src_1.default(transport);
59
+ const version = await app.getVersion();
60
+ expect(version).toBe('0.4.0');
61
+ await app.close();
62
+ });
63
+ it('should get public key', async () => {
64
+ const transport = await (0, utils_1.createTransport)();
65
+ const app = new src_1.default(transport);
66
+ const [account, hdIndex] = await app.getAccount(path);
67
+ expect(hdIndex).toBe(pathIndex);
68
+ console.log(account);
69
+ await app.close();
70
+ });
71
+ it('should get public key and confirm address', async () => {
72
+ const transport = await (0, utils_1.createTransport)();
73
+ const app = new src_1.default(transport);
74
+ (0, utils_1.approveAddress)();
75
+ const [account, hdIndex] = await app.getAccount(path, undefined, undefined, true);
76
+ expect(hdIndex).toBe(pathIndex);
77
+ console.log(account);
78
+ await app.close();
79
+ }, 30000);
80
+ it('should get public key for group', async () => {
81
+ const transport = await (0, utils_1.createTransport)();
82
+ const app = new src_1.default(transport);
83
+ for (let group = 0; group < src_1.GROUP_NUM; group++) {
84
+ const [account, hdIndex] = await app.getAccount(path, group);
85
+ expect(hdIndex >= pathIndex).toBe(true);
86
+ expect((0, web3_1.groupOfAddress)(account.address)).toBe(group);
87
+ expect(account.keyType).toBe('default');
88
+ }
89
+ await app.close();
90
+ });
91
+ it('should get public key for group for Schnorr signature', async () => {
92
+ const transport = await (0, utils_1.createTransport)();
93
+ const app = new src_1.default(transport);
94
+ for (let group = 0; group < src_1.GROUP_NUM; group++) {
95
+ await expect(app.getAccount(path, group, 'bip340-schnorr')).rejects.toThrow('BIP340-Schnorr is not supported yet');
96
+ }
97
+ await app.close();
98
+ });
99
+ it('should sign hash', async () => {
100
+ const transport = await (0, utils_1.createTransport)();
101
+ const app = new src_1.default(transport);
102
+ const [account] = await app.getAccount(path);
103
+ console.log(account);
104
+ const hash = Buffer.from(blakejs_1.default.blake2b(Buffer.from([0, 1, 2, 3, 4]), undefined, 32));
105
+ (0, utils_1.approveHash)();
106
+ const signature = await app.signHash(path, hash);
107
+ console.log(signature);
108
+ await app.close();
109
+ expect((0, web3_1.transactionVerifySignature)(hash.toString('hex'), account.publicKey, signature)).toBe(true);
110
+ }, 10000);
111
+ it('shoudl transfer alph to one address', async () => {
112
+ const transport = await (0, utils_1.createTransport)();
113
+ const app = new src_1.default(transport);
114
+ const [testAccount] = await app.getAccount(path);
115
+ await transferToAddress(testAccount.address);
116
+ const buildTxResult = await nodeProvider.transactions.postTransactionsBuild({
117
+ fromPublicKey: testAccount.publicKey,
118
+ destinations: [
119
+ {
120
+ address: '1BmVCLrjttchZMW7i6df7mTdCKzHpy38bgDbVL1GqV6P7',
121
+ attoAlphAmount: (web3_1.ONE_ALPH * 2n).toString(),
122
+ }
123
+ ]
124
+ });
125
+ (0, utils_1.approveTx)([utils_1.OutputType.Base]);
126
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'));
127
+ expect((0, web3_1.transactionVerifySignature)(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true);
128
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
129
+ unsignedTx: buildTxResult.unsignedTx,
130
+ signature: signature
131
+ });
132
+ await (0, web3_1.waitForTxConfirmation)(submitResult.txId, 1, 1000);
133
+ const balance = await getALPHBalance(testAccount.address);
134
+ expect(balance < (web3_1.ONE_ALPH * 8n)).toEqual(true);
135
+ await app.close();
136
+ }, 120000);
137
+ it('should transfer alph to multiple addresses', async () => {
138
+ const transport = await (0, utils_1.createTransport)();
139
+ const app = new src_1.default(transport);
140
+ const [testAccount] = await app.getAccount(path);
141
+ await transferToAddress(testAccount.address);
142
+ const buildTxResult = await nodeProvider.transactions.postTransactionsBuild({
143
+ fromPublicKey: testAccount.publicKey,
144
+ destinations: [
145
+ {
146
+ address: '1BmVCLrjttchZMW7i6df7mTdCKzHpy38bgDbVL1GqV6P7',
147
+ attoAlphAmount: (web3_1.ONE_ALPH * 2n).toString(),
148
+ },
149
+ {
150
+ address: '1F1fu6GjuN9yUVRFVcgQKWwiTg8RMzKFv1BZFDwFcfWJq',
151
+ attoAlphAmount: (web3_1.ONE_ALPH * 3n).toString(),
152
+ },
153
+ ]
154
+ });
155
+ (0, utils_1.approveTx)(Array(2).fill(utils_1.OutputType.Base));
156
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'));
157
+ expect((0, web3_1.transactionVerifySignature)(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true);
158
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
159
+ unsignedTx: buildTxResult.unsignedTx,
160
+ signature: signature
161
+ });
162
+ await (0, web3_1.waitForTxConfirmation)(submitResult.txId, 1, 1000);
163
+ const balance1 = await getALPHBalance(testAccount.address);
164
+ expect(balance1 < (web3_1.ONE_ALPH * 5n)).toEqual(true);
165
+ await app.close();
166
+ }, 120000);
167
+ it('should transfer alph to multisig address', async () => {
168
+ const transport = await (0, utils_1.createTransport)();
169
+ const app = new src_1.default(transport);
170
+ const [testAccount] = await app.getAccount(path);
171
+ await transferToAddress(testAccount.address);
172
+ const multiSigAddress = 'X3KYVteDjsKuUP1F68Nv9iEUecnnkMuwjbC985AnA6MvciDFJ5bAUEso2Sd7sGrwZ5rfNLj7Rp4n9XjcyzDiZsrPxfhNkPYcDm3ce8pQ9QasNFByEufMi3QJ3cS9Vk6cTpqNcq';
173
+ const buildTxResult = await nodeProvider.transactions.postTransactionsBuild({
174
+ fromPublicKey: testAccount.publicKey,
175
+ destinations: [
176
+ {
177
+ address: multiSigAddress,
178
+ attoAlphAmount: (web3_1.ONE_ALPH * 2n).toString(),
179
+ }
180
+ ]
181
+ });
182
+ (0, utils_1.approveTx)([utils_1.OutputType.Multisig]);
183
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'));
184
+ expect((0, web3_1.transactionVerifySignature)(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true);
185
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
186
+ unsignedTx: buildTxResult.unsignedTx,
187
+ signature: signature
188
+ });
189
+ await (0, web3_1.waitForTxConfirmation)(submitResult.txId, 1, 1000);
190
+ const balance1 = await getALPHBalance(testAccount.address);
191
+ expect(balance1 < (web3_1.ONE_ALPH * 8n)).toEqual(true);
192
+ await app.close();
193
+ }, 120000);
194
+ it('should transfer token to multisig address', async () => {
195
+ const transport = await (0, utils_1.createTransport)();
196
+ const app = new src_1.default(transport);
197
+ const [testAccount] = await app.getAccount(path);
198
+ await transferToAddress(testAccount.address);
199
+ const tokenInfo = await (0, web3_test_1.mintToken)(testAccount.address, 2222222222222222222222222n);
200
+ const multiSigAddress = 'X3KYVteDjsKuUP1F68Nv9iEUecnnkMuwjbC985AnA6MvciDFJ5bAUEso2Sd7sGrwZ5rfNLj7Rp4n9XjcyzDiZsrPxfhNkPYcDm3ce8pQ9QasNFByEufMi3QJ3cS9Vk6cTpqNcq';
201
+ const buildTxResult = await nodeProvider.transactions.postTransactionsBuild({
202
+ fromPublicKey: testAccount.publicKey,
203
+ destinations: [
204
+ {
205
+ address: multiSigAddress,
206
+ attoAlphAmount: (web3_1.ONE_ALPH * 5n).toString(),
207
+ tokens: [
208
+ {
209
+ id: tokenInfo.contractId,
210
+ amount: "1111111111111111111111111",
211
+ }
212
+ ]
213
+ }
214
+ ]
215
+ });
216
+ (0, utils_1.approveTx)([utils_1.OutputType.MultisigAndToken, utils_1.OutputType.Multisig]);
217
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'));
218
+ expect((0, web3_1.transactionVerifySignature)(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true);
219
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
220
+ unsignedTx: buildTxResult.unsignedTx,
221
+ signature: signature
222
+ });
223
+ await (0, web3_1.waitForTxConfirmation)(submitResult.txId, 1, 1000);
224
+ const balances = await nodeProvider.addresses.getAddressesAddressBalance(testAccount.address);
225
+ const alphBalance = BigInt(balances.balance);
226
+ expect(alphBalance < (web3_1.ONE_ALPH * 5n)).toEqual(true);
227
+ expect(balances.tokenBalances.length).toEqual(1);
228
+ const token = balances.tokenBalances[0];
229
+ expect(token.id).toEqual(tokenInfo.contractId);
230
+ expect(token.amount).toEqual('1111111111111111111111111');
231
+ await app.close();
232
+ }, 120000);
233
+ it('should transfer from multiple inputs', async () => {
234
+ const transport = await (0, utils_1.createTransport)();
235
+ const app = new src_1.default(transport);
236
+ const [testAccount] = await app.getAccount(path);
237
+ for (let i = 0; i < 20; i += 1) {
238
+ await transferToAddress(testAccount.address, web3_1.ONE_ALPH);
239
+ }
240
+ const buildTxResult = await nodeProvider.transactions.postTransactionsBuild({
241
+ fromPublicKey: testAccount.publicKey,
242
+ destinations: [
243
+ {
244
+ address: '1BmVCLrjttchZMW7i6df7mTdCKzHpy38bgDbVL1GqV6P7',
245
+ attoAlphAmount: (web3_1.ONE_ALPH * 19n).toString(),
246
+ }
247
+ ]
248
+ });
249
+ (0, utils_1.approveTx)([utils_1.OutputType.Base]);
250
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'));
251
+ expect((0, web3_1.transactionVerifySignature)(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true);
252
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
253
+ unsignedTx: buildTxResult.unsignedTx,
254
+ signature: signature
255
+ });
256
+ await (0, web3_1.waitForTxConfirmation)(submitResult.txId, 1, 1000);
257
+ const balance = await getALPHBalance(testAccount.address);
258
+ expect(balance < (web3_1.ONE_ALPH * 1n)).toEqual(true);
259
+ await app.close();
260
+ }, 120000);
261
+ function getAccount(groupIndex) {
262
+ const useDefaultKeyType = Math.random() >= 0.5;
263
+ if (useDefaultKeyType) {
264
+ const account = web3_wallet_1.PrivateKeyWallet.Random(groupIndex);
265
+ return { account, unlockScript: '00' + account.publicKey };
266
+ }
267
+ const account = web3_wallet_1.PrivateKeyWallet.Random(groupIndex, nodeProvider, 'bip340-schnorr');
268
+ const unlockScript = '02' + `0101000000000458144020${account.publicKey}8685` + '00';
269
+ return { account, unlockScript };
270
+ }
271
+ it('should test external inputs', async () => {
272
+ const transport = await (0, utils_1.createTransport)();
273
+ const app = new src_1.default(transport);
274
+ const [testAccount] = await app.getAccount(path);
275
+ const { account: newAccount, unlockScript: unlockScript0 } = getAccount(testAccount.group);
276
+ for (let i = 0; i < 2; i += 1) {
277
+ await transferToAddress(testAccount.address, web3_1.ONE_ALPH);
278
+ await transferToAddress(newAccount.address, web3_1.ONE_ALPH);
279
+ }
280
+ const utxos0 = await nodeProvider.addresses.getAddressesAddressUtxos(newAccount.address);
281
+ expect(utxos0.utxos.length).toEqual(2);
282
+ const utxos1 = await nodeProvider.addresses.getAddressesAddressUtxos(testAccount.address);
283
+ expect(utxos1.utxos.length).toEqual(2);
284
+ const useSameAsPrevious = Math.random() >= 0.5;
285
+ const inputs0 = utxos0.utxos.map((utxo, index) => {
286
+ const unlockScript = index > 0 && useSameAsPrevious ? '03' : unlockScript0;
287
+ return { outputRef: utxo.ref, unlockScript };
288
+ });
289
+ const unlockScript1 = '00' + testAccount.publicKey;
290
+ const inputs1 = utxos1.utxos.map((utxo, index) => {
291
+ const unlockScript = index > 0 && useSameAsPrevious ? '03' : unlockScript1;
292
+ return { outputRef: utxo.ref, unlockScript };
293
+ });
294
+ const unsignedTx = {
295
+ txId: '',
296
+ version: 0,
297
+ networkId: 4,
298
+ gasAmount: 100000,
299
+ gasPrice: (web3_1.ONE_ALPH / 100000n).toString(),
300
+ inputs: inputs0.concat(inputs1),
301
+ fixedOutputs: [{
302
+ hint: 0,
303
+ key: '',
304
+ attoAlphAmount: (web3_1.ONE_ALPH * 3n).toString(),
305
+ address: newAccount.address,
306
+ tokens: [],
307
+ lockTime: 0,
308
+ message: ''
309
+ }]
310
+ };
311
+ const txBytes = web3_1.codec.unsignedTxCodec.encodeApiUnsignedTx(unsignedTx);
312
+ const signResult0 = await newAccount.signUnsignedTx({
313
+ signerAddress: newAccount.address,
314
+ unsignedTx: (0, web3_1.binToHex)(txBytes)
315
+ });
316
+ (0, utils_1.approveTx)([utils_1.OutputType.Base], true);
317
+ const signature1 = await app.signUnsignedTx(path, Buffer.from(txBytes));
318
+ expect((0, web3_1.transactionVerifySignature)(signResult0.txId, testAccount.publicKey, signature1)).toBe(true);
319
+ const submitResult = await nodeProvider.multisig.postMultisigSubmit({
320
+ unsignedTx: (0, web3_1.binToHex)(txBytes),
321
+ signatures: [signResult0.signature, signature1]
322
+ });
323
+ await (0, web3_1.waitForTxConfirmation)(submitResult.txId, 1, 1000);
324
+ const balance = await getALPHBalance(newAccount.address);
325
+ expect(balance).toEqual(web3_1.ONE_ALPH * 3n);
326
+ await app.close();
327
+ }, 120000);
328
+ it('should test self transfer tx', async () => {
329
+ const transport = await (0, utils_1.createTransport)();
330
+ const app = new src_1.default(transport);
331
+ const [testAccount] = await app.getAccount(path);
332
+ await transferToAddress(testAccount.address);
333
+ const buildTxResult = await nodeProvider.transactions.postTransactionsBuild({
334
+ fromPublicKey: testAccount.publicKey,
335
+ destinations: [
336
+ {
337
+ address: testAccount.address,
338
+ attoAlphAmount: (web3_1.ONE_ALPH * 2n).toString(),
339
+ }
340
+ ]
341
+ });
342
+ (0, utils_1.approveTx)([]);
343
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'));
344
+ expect((0, web3_1.transactionVerifySignature)(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true);
345
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
346
+ unsignedTx: buildTxResult.unsignedTx,
347
+ signature: signature
348
+ });
349
+ await (0, web3_1.waitForTxConfirmation)(submitResult.txId, 1, 1000);
350
+ const balance = await getALPHBalance(testAccount.address);
351
+ expect(balance > (web3_1.ONE_ALPH * 9n)).toEqual(true);
352
+ await app.close();
353
+ }, 12000);
354
+ it('should test script execution tx', async () => {
355
+ const transport = await (0, utils_1.createTransport)();
356
+ const app = new src_1.default(transport);
357
+ const [testAccount] = await app.getAccount(path);
358
+ await transferToAddress(testAccount.address);
359
+ const buildTxResult = await nodeProvider.contracts.postContractsUnsignedTxDeployContract({
360
+ fromPublicKey: testAccount.publicKey,
361
+ bytecode: '00010c010000000002d38d0b3636020000'
362
+ });
363
+ setTimeout(() => (0, utils_1.skipBlindSigningWarning)(), 1000);
364
+ await expect(app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))).rejects.toThrow();
365
+ await (0, utils_1.enableBlindSigning)();
366
+ if ((0, utils_1.needToAutoApprove)()) {
367
+ (0, utils_1.staxFlexApproveOnce)().then(() => (0, utils_1.approveTx)([]));
368
+ }
369
+ else {
370
+ // waiting for blind signing setting to be enabled
371
+ await (0, web3_1.sleep)(20000);
372
+ }
373
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'));
374
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
375
+ unsignedTx: buildTxResult.unsignedTx,
376
+ signature: signature
377
+ });
378
+ await (0, web3_1.waitForTxConfirmation)(submitResult.txId, 1, 1000);
379
+ const details = await nodeProvider.transactions.getTransactionsDetailsTxid(submitResult.txId);
380
+ expect(details.scriptExecutionOk).toEqual(true);
381
+ await app.close();
382
+ }, 120000);
383
+ });
@@ -0,0 +1,55 @@
1
+ # Import this mnemonic to have 4'000'000 token allocated for your addresses
2
+ #
3
+ # vault alarm sad mass witness property virus style good flower rice alpha viable evidence run glare pretty scout evil judge enroll refuse another lava
4
+
5
+ alephium.genesis.allocations = [
6
+ {
7
+ address = "1DrDyTr9RpRsQnDnXo2YRiPzPW4ooHX5LLoqXrqfMrpQH",
8
+ amount = 1000000000000000000000000,
9
+ lock-duration = 0 seconds
10
+ },
11
+ {
12
+ address = "14UAjZ3qcmEVKdTo84Kwf4RprTQi86w2TefnnGFjov9xF",
13
+ amount = 1000000000000000000000000,
14
+ lock-duration = 0 seconds
15
+ },
16
+ {
17
+ address = "15jjExDyS8q3Wqk9v29PCQ21jDqubDrD8WQdgn6VW2oi4",
18
+ amount = 1000000000000000000000000,
19
+ lock-duration = 0 seconds
20
+ },
21
+ {
22
+ address = "17cBiTcWhung3WDLuc9ja5Y7BMus5Q7CD9wYBxS1r1P2R",
23
+ amount = 1000000000000000000000000,
24
+ lock-duration = 0 seconds
25
+ }
26
+ ]
27
+ alephium.consensus.num-zeros-at-least-in-hash = 0
28
+ alephium.consensus.mainnet.block-target-time = 10 millis
29
+ alephium.consensus.mainnet.uncle-dependency-gap-time = 0 seconds
30
+ alephium.consensus.rhone.block-target-time = 5 millis
31
+ alephium.consensus.rhone.uncle-dependency-gap-time = 0 seconds
32
+ alephium.network.leman-hard-fork-timestamp = 0
33
+ alephium.network.rhone-hard-fork-timestamp = 0
34
+
35
+ alephium.network.network-id = 4
36
+ alephium.discovery.bootstrap = []
37
+ alephium.wallet.locking-timeout = 99999 minutes
38
+ alephium.mempool.auto-mine-for-dev = true
39
+ alephium.node.event-log.enabled=true
40
+ alephium.node.event-log.index-by-tx-id = true
41
+ alephium.node.event-log.index-by-block-hash = true
42
+
43
+ alephium.network.rest-port = 22973
44
+ alephium.network.ws-port = 21973
45
+ alephium.network.miner-api-port = 20973
46
+ alephium.api.network-interface = "0.0.0.0"
47
+ alephium.api.api-key-enabled = false
48
+
49
+ # arbitrary mining addresses
50
+ alephium.mining.miner-addresses = [
51
+ "1FsroWmeJPBhcPiUr37pWXdojRBe6jdey9uukEXk1TheA",
52
+ "1CQvSXsmM5BMFKguKDPpNUfw1idiut8UifLtT8748JdHc",
53
+ "193maApeJWrz9GFwWCfa982ccLARVE9Y1WgKSJaUs7UAx",
54
+ "16fZKYPCZJv2TP3FArA9FLUQceTS9U8xVnSjxFG9MBKyY"
55
+ ]
@@ -0,0 +1,22 @@
1
+ version: "3.3"
2
+
3
+ services:
4
+ alephium:
5
+ image: alephium/alephium:v3.3.0
6
+ restart: "no"
7
+ ports:
8
+ - 19973:19973/tcp
9
+ - 19973:19973/udp
10
+ - 127.0.0.1:20973:20973
11
+ - 127.0.0.1:21973:21973
12
+ - 127.0.0.1:22973:22973
13
+ security_opt:
14
+ - no-new-privileges:true
15
+ volumes:
16
+ - ./devnet.conf:/alephium-home/.alephium/user.conf
17
+ # - ~/.alephium:/alephium-home/.alephium
18
+ environment:
19
+ ALEPHIUM_FILE_LOG_LEVEL: "DEBUG"
20
+ healthcheck:
21
+ test: ["CMD", "curl", "http://127.0.0.1:22973/infos/self-clique"]
22
+ timeout: 45s
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alephium/ledger-app",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "license": "GPL",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "exports": {
@@ -12,7 +12,8 @@
12
12
  "clean:windows": "node -e \"if (process.platform === 'win32') process.exit(1)\" || , if exist dist rmdir /Q /S dist",
13
13
  "lint": "eslint . --ext ts",
14
14
  "lint:fix": "eslint . --fix --ext ts",
15
- "test": "jest -i --config ./jest-config.json",
15
+ "speculos-test": "BACKEND=speculos jest -i --config ./jest-config.json",
16
+ "device-test": "BACKEND=device jest -i --config ./jest-config.json",
16
17
  "pub": "npm run build && npm publish --access public"
17
18
  },
18
19
  "prettier": {
@@ -25,19 +26,18 @@
25
26
  "trailingComma": "none"
26
27
  },
27
28
  "dependencies": {
28
- "@alephium/cli": "^0.14.0",
29
- "@alephium/web3": "^0.14.0",
30
- "@alephium/web3-test": "^0.14.0",
31
- "@alephium/web3-wallet": "^0.14.0",
32
- "@ledgerhq/hw-transport": "6.27.10"
29
+ "@alephium/web3": "^1.2.0",
30
+ "@ledgerhq/hw-transport": "6.31.0"
33
31
  },
34
32
  "devDependencies": {
35
- "@ledgerhq/hw-transport-node-hid": "^6.27.9",
36
- "@ledgerhq/hw-transport-node-speculos": "^6.27.9",
37
- "@ledgerhq/logs": "^6.10.1",
33
+ "@alephium/web3-test": "^1.2.0",
34
+ "@alephium/web3-wallet": "^1.2.0",
35
+ "@alephium/cli": "^1.2.0",
36
+ "@ledgerhq/hw-transport-node-hid": "6.29.1",
37
+ "@ledgerhq/hw-transport-node-speculos": "6.29.0",
38
38
  "@types/elliptic": "^6.4.13",
39
39
  "@types/jest": "^27.5.1",
40
- "@types/node": "^16.7.8",
40
+ "@types/node": "^20.8.10",
41
41
  "@typescript-eslint/eslint-plugin": "^4.30.0",
42
42
  "@typescript-eslint/parser": "^4.30.0",
43
43
  "eslint": "^7.32.0",
package/src/index.ts CHANGED
@@ -9,7 +9,8 @@ export const CLA = 0x80
9
9
  export enum INS {
10
10
  GET_VERSION = 0x00,
11
11
  GET_PUBLIC_KEY = 0x01,
12
- SIGN_HASH = 0x02
12
+ SIGN_HASH = 0x02,
13
+ SIGN_TX = 0x03
13
14
  }
14
15
 
15
16
  export const GROUP_NUM = 4
@@ -32,8 +33,7 @@ export default class AlephiumApp {
32
33
  return `${response[0]}.${response[1]}.${response[2]}`
33
34
  }
34
35
 
35
- // TODO: make address display optional
36
- async getAccount(startPath: string, targetGroup?: number, keyType?: KeyType): Promise<readonly [Account, number]> {
36
+ async getAccount(startPath: string, targetGroup?: number, keyType?: KeyType, display = false): Promise<readonly [Account, number]> {
37
37
  if ((targetGroup ?? 0) >= GROUP_NUM) {
38
38
  throw Error(`Invalid targetGroup: ${targetGroup}`)
39
39
  }
@@ -44,7 +44,8 @@ export default class AlephiumApp {
44
44
 
45
45
  const p1 = targetGroup === undefined ? 0x00 : GROUP_NUM
46
46
  const p2 = targetGroup === undefined ? 0x00 : targetGroup
47
- const response = await this.transport.send(CLA, INS.GET_PUBLIC_KEY, p1, p2, serde.serializePath(startPath))
47
+ const payload = Buffer.concat([serde.serializePath(startPath), Buffer.from([display ? 1 : 0])]);
48
+ const response = await this.transport.send(CLA, INS.GET_PUBLIC_KEY, p1, p2, payload)
48
49
  const publicKey = ec.keyFromPublic(response.slice(0, 65)).getPublic(true, 'hex')
49
50
  const address = addressFromPublicKey(publicKey)
50
51
  const group = groupOfAddress(address)
@@ -63,12 +64,40 @@ export default class AlephiumApp {
63
64
  const response = await this.transport.send(CLA, INS.SIGN_HASH, 0x00, 0x00, data, [StatusCodes.OK])
64
65
  console.log(`response ${response.length} - ${response.toString('hex')}`)
65
66
 
66
- // Decode signature: https://bitcoin.stackexchange.com/a/12556
67
- const rLen = response.slice(3, 4)[0]
68
- const r = response.slice(4, 4 + rLen)
69
- const sLen = response.slice(5 + rLen, 6 + rLen)[0]
70
- const s = response.slice(6 + rLen, 6 + rLen + sLen)
71
- console.log(`${rLen} - ${r.toString('hex')}\n${sLen} - ${s.toString('hex')}`)
72
- return encodeHexSignature(r.toString('hex'), s.toString('hex'))
67
+ return decodeSignature(response)
73
68
  }
69
+
70
+ async signUnsignedTx(path: string, unsignedTx: Buffer): Promise<string> {
71
+ console.log(`unsigned tx size: ${unsignedTx.length}`)
72
+ const encodedPath = serde.serializePath(path)
73
+ const firstFrameTxLength = 256 - 25;
74
+ const txData = unsignedTx.slice(0, unsignedTx.length > firstFrameTxLength ? firstFrameTxLength : unsignedTx.length)
75
+ const data = Buffer.concat([encodedPath, txData])
76
+ let response = await this.transport.send(CLA, INS.SIGN_TX, 0x00, 0x00, data, [StatusCodes.OK])
77
+ if (unsignedTx.length <= firstFrameTxLength) {
78
+ return decodeSignature(response)
79
+ }
80
+
81
+ const frameLength = 256 - 5
82
+ let fromIndex = firstFrameTxLength
83
+ while (fromIndex < unsignedTx.length) {
84
+ const remain = unsignedTx.length - fromIndex
85
+ const toIndex = remain > frameLength ? (fromIndex + frameLength) : unsignedTx.length
86
+ const data = unsignedTx.slice(fromIndex, toIndex)
87
+ response = await this.transport.send(CLA, INS.SIGN_TX, 0x01, 0x00, data, [StatusCodes.OK])
88
+ fromIndex = toIndex
89
+ }
90
+
91
+ return decodeSignature(response)
92
+ }
93
+ }
94
+
95
+ function decodeSignature(response: Buffer): string {
96
+ // Decode signature: https://bitcoin.stackexchange.com/a/12556
97
+ const rLen = response.slice(3, 4)[0]
98
+ const r = response.slice(4, 4 + rLen)
99
+ const sLen = response.slice(5 + rLen, 6 + rLen)[0]
100
+ const s = response.slice(6 + rLen, 6 + rLen + sLen)
101
+ console.log(`${rLen} - ${r.toString('hex')}\n${sLen} - ${s.toString('hex')}`)
102
+ return encodeHexSignature(r.toString('hex'), s.toString('hex'))
74
103
  }