@alephium/ledger-app 0.6.0 → 0.6.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.
- package/dist/test/merkle.test.js +6 -0
- package/dist/test/utils.d.ts +6 -7
- package/dist/test/utils.js +64 -52
- package/dist/test/wallet.test.js +8 -8
- package/docker/docker-compose.yaml +1 -1
- package/package.json +2 -2
- package/test/merkle.test.ts +7 -1
- package/test/utils.ts +60 -47
- package/test/wallet.test.ts +8 -8
package/dist/test/merkle.test.js
CHANGED
|
@@ -3,7 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const merkle_1 = require("../src/merkle");
|
|
4
4
|
const serde_1 = require("../src/serde");
|
|
5
5
|
const blakejs_1 = require("blakejs");
|
|
6
|
+
const web3_1 = require("@alephium/web3");
|
|
6
7
|
describe('Merkle', () => {
|
|
8
|
+
it('should generate the correct proofs', () => {
|
|
9
|
+
const { proofs, root } = (0, merkle_1.generateProofs)();
|
|
10
|
+
expect(JSON.stringify(proofs)).toBe(JSON.stringify(merkle_1.tokenMerkleProofs));
|
|
11
|
+
expect(root).toBe((0, web3_1.binToHex)(merkle_1.tokenMerkleRoot));
|
|
12
|
+
});
|
|
7
13
|
it('should verify proofs', () => {
|
|
8
14
|
for (const token of merkle_1.merkleTokens) {
|
|
9
15
|
const proof = merkle_1.tokenMerkleProofs[token.tokenId];
|
package/dist/test/utils.d.ts
CHANGED
|
@@ -2,18 +2,17 @@ import Transport from '@ledgerhq/hw-transport';
|
|
|
2
2
|
export declare enum OutputType {
|
|
3
3
|
Base = 0,
|
|
4
4
|
Multisig = 1,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
BaseAndToken = 5,
|
|
9
|
-
MultisigAndToken = 6
|
|
5
|
+
Token = 2,
|
|
6
|
+
BaseAndToken = 3,
|
|
7
|
+
MultisigAndToken = 4
|
|
10
8
|
}
|
|
11
9
|
export declare function staxFlexApproveOnce(): Promise<void>;
|
|
12
10
|
export declare function approveTx(outputs: OutputType[], hasExternalInputs?: boolean): Promise<void>;
|
|
13
11
|
export declare function approveHash(): Promise<void>;
|
|
14
12
|
export declare function approveAddress(): Promise<void>;
|
|
15
|
-
export declare function
|
|
16
|
-
export declare function skipBlindSigningWarning(): void
|
|
13
|
+
export declare function isStaxOrFlex(): boolean;
|
|
14
|
+
export declare function skipBlindSigningWarning(): Promise<void>;
|
|
15
|
+
export declare function staxFlexAcceptRisk(): Promise<void>;
|
|
17
16
|
export declare function enableBlindSigning(): Promise<void>;
|
|
18
17
|
export declare function getRandomInt(min: number, max: number): number;
|
|
19
18
|
export declare function needToAutoApprove(): boolean;
|
package/dist/test/utils.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.createTransport = exports.needToAutoApprove = exports.getRandomInt = exports.enableBlindSigning = exports.skipBlindSigningWarning = exports.
|
|
6
|
+
exports.createTransport = exports.needToAutoApprove = exports.getRandomInt = exports.enableBlindSigning = exports.staxFlexAcceptRisk = exports.skipBlindSigningWarning = exports.isStaxOrFlex = exports.approveAddress = exports.approveHash = exports.approveTx = exports.staxFlexApproveOnce = exports.OutputType = void 0;
|
|
7
7
|
const hw_transport_node_speculos_1 = __importDefault(require("@ledgerhq/hw-transport-node-speculos"));
|
|
8
8
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
9
9
|
const web3_1 = require("@alephium/web3");
|
|
@@ -23,27 +23,16 @@ async function clickAndApprove(times) {
|
|
|
23
23
|
}
|
|
24
24
|
function getModel() {
|
|
25
25
|
const model = process.env.MODEL;
|
|
26
|
-
return model ? model : '
|
|
26
|
+
return model ? model : 'nanosp';
|
|
27
27
|
}
|
|
28
28
|
var OutputType;
|
|
29
29
|
(function (OutputType) {
|
|
30
30
|
OutputType[OutputType["Base"] = 0] = "Base";
|
|
31
31
|
OutputType[OutputType["Multisig"] = 1] = "Multisig";
|
|
32
|
-
OutputType[OutputType["
|
|
33
|
-
OutputType[OutputType["
|
|
34
|
-
OutputType[OutputType["
|
|
35
|
-
OutputType[OutputType["BaseAndToken"] = 5] = "BaseAndToken";
|
|
36
|
-
OutputType[OutputType["MultisigAndToken"] = 6] = "MultisigAndToken";
|
|
32
|
+
OutputType[OutputType["Token"] = 2] = "Token";
|
|
33
|
+
OutputType[OutputType["BaseAndToken"] = 3] = "BaseAndToken";
|
|
34
|
+
OutputType[OutputType["MultisigAndToken"] = 4] = "MultisigAndToken";
|
|
37
35
|
})(OutputType = exports.OutputType || (exports.OutputType = {}));
|
|
38
|
-
const NanosClickTable = new Map([
|
|
39
|
-
[OutputType.Base, 5],
|
|
40
|
-
[OutputType.Multisig, 10],
|
|
41
|
-
[OutputType.Nanos10, 10],
|
|
42
|
-
[OutputType.Nanos11, 11],
|
|
43
|
-
[OutputType.Token, 11],
|
|
44
|
-
[OutputType.BaseAndToken, 12],
|
|
45
|
-
[OutputType.MultisigAndToken, 16],
|
|
46
|
-
]);
|
|
47
36
|
const NanospClickTable = new Map([
|
|
48
37
|
[OutputType.Base, 3],
|
|
49
38
|
[OutputType.Multisig, 5],
|
|
@@ -52,20 +41,26 @@ const NanospClickTable = new Map([
|
|
|
52
41
|
[OutputType.MultisigAndToken, 8],
|
|
53
42
|
]);
|
|
54
43
|
const StaxClickTable = new Map([
|
|
55
|
-
[OutputType.Base,
|
|
56
|
-
[OutputType.Multisig,
|
|
57
|
-
[OutputType.Token,
|
|
58
|
-
[OutputType.BaseAndToken,
|
|
59
|
-
[OutputType.MultisigAndToken,
|
|
44
|
+
[OutputType.Base, 1],
|
|
45
|
+
[OutputType.Multisig, 2],
|
|
46
|
+
[OutputType.Token, 2],
|
|
47
|
+
[OutputType.BaseAndToken, 2],
|
|
48
|
+
[OutputType.MultisigAndToken, 2],
|
|
49
|
+
]);
|
|
50
|
+
const FlexClickTable = new Map([
|
|
51
|
+
[OutputType.Base, 1],
|
|
52
|
+
[OutputType.Multisig, 2],
|
|
53
|
+
[OutputType.Token, 2],
|
|
54
|
+
[OutputType.BaseAndToken, 2],
|
|
55
|
+
[OutputType.MultisigAndToken, 3],
|
|
60
56
|
]);
|
|
61
57
|
function getOutputClickSize(outputType) {
|
|
62
58
|
const model = getModel();
|
|
63
59
|
switch (model) {
|
|
64
|
-
case 'nanos': return NanosClickTable.get(outputType);
|
|
65
60
|
case 'nanosp':
|
|
66
61
|
case 'nanox': return NanospClickTable.get(outputType);
|
|
67
|
-
case 'stax':
|
|
68
|
-
case 'flex': return
|
|
62
|
+
case 'stax': return StaxClickTable.get(outputType);
|
|
63
|
+
case 'flex': return FlexClickTable.get(outputType);
|
|
69
64
|
default: throw new Error(`Unknown model ${model}`);
|
|
70
65
|
}
|
|
71
66
|
}
|
|
@@ -84,11 +79,15 @@ const STAX_APPROVE_POSITION = { x: 200, y: 515 };
|
|
|
84
79
|
const STAX_REJECT_POSITION = { x: 36, y: 606 };
|
|
85
80
|
const STAX_SETTINGS_POSITION = { x: 342, y: 55 };
|
|
86
81
|
const STAX_BLIND_SETTING_POSITION = { x: 342, y: 90 };
|
|
82
|
+
const STAX_GO_TO_SETTINGS = { x: 36, y: 606 };
|
|
83
|
+
const STAX_ACCEPT_RISK_POSITION = { x: 36, y: 606 };
|
|
87
84
|
const FLEX_CONTINUE_POSITION = { x: 430, y: 550 };
|
|
88
85
|
const FLEX_APPROVE_POSITION = { x: 240, y: 435 };
|
|
89
86
|
const FLEX_REJECT_POSITION = { x: 55, y: 530 };
|
|
90
87
|
const FLEX_SETTINGS_POSITION = { x: 405, y: 75 };
|
|
91
88
|
const FLEX_BLIND_SETTING_POSITION = { x: 405, y: 96 };
|
|
89
|
+
const FLEX_GO_TO_SETTINGS = { x: 55, y: 530 };
|
|
90
|
+
const FLEX_ACCEPT_RISK_POSITION = { x: 55, y: 530 };
|
|
92
91
|
async function touchPosition(pos) {
|
|
93
92
|
await (0, web3_1.sleep)(1000);
|
|
94
93
|
return (0, node_fetch_1.default)(`http://localhost:25000/finger`, {
|
|
@@ -96,14 +95,23 @@ async function touchPosition(pos) {
|
|
|
96
95
|
body: JSON.stringify({ action: 'press-and-release', x: pos.x, y: pos.y })
|
|
97
96
|
});
|
|
98
97
|
}
|
|
99
|
-
async function
|
|
98
|
+
async function longPress(pos) {
|
|
99
|
+
await (0, web3_1.sleep)(1000);
|
|
100
|
+
return (0, node_fetch_1.default)(`http://localhost:25000/finger`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
body: JSON.stringify({ action: 'press-and-release', x: pos.x, y: pos.y, delay: 3 })
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async function _touch(times, approve = false) {
|
|
100
106
|
const model = getModel();
|
|
101
107
|
const continuePos = model === 'stax' ? STAX_CONTINUE_POSITION : FLEX_CONTINUE_POSITION;
|
|
102
108
|
for (let i = 0; i < times; i += 1) {
|
|
103
109
|
await touchPosition(continuePos);
|
|
104
110
|
}
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
if (approve) {
|
|
112
|
+
const approvePos = model === 'stax' ? STAX_APPROVE_POSITION : FLEX_APPROVE_POSITION;
|
|
113
|
+
await longPress(approvePos);
|
|
114
|
+
}
|
|
107
115
|
}
|
|
108
116
|
async function staxFlexApproveOnce() {
|
|
109
117
|
if (getModel() === 'stax') {
|
|
@@ -115,14 +123,16 @@ async function staxFlexApproveOnce() {
|
|
|
115
123
|
}
|
|
116
124
|
exports.staxFlexApproveOnce = staxFlexApproveOnce;
|
|
117
125
|
async function touch(outputs, hasExternalInputs) {
|
|
118
|
-
await (0, web3_1.sleep)(
|
|
126
|
+
await (0, web3_1.sleep)(3000);
|
|
119
127
|
if (hasExternalInputs) {
|
|
120
128
|
await staxFlexApproveOnce();
|
|
121
129
|
}
|
|
130
|
+
_touch(1); // the first review page
|
|
131
|
+
await (0, web3_1.sleep)(1000);
|
|
122
132
|
for (let index = 0; index < outputs.length; index += 1) {
|
|
123
133
|
await _touch(getOutputClickSize(outputs[index]));
|
|
124
134
|
}
|
|
125
|
-
await _touch(
|
|
135
|
+
await _touch(1, true); // fees
|
|
126
136
|
}
|
|
127
137
|
async function approveTx(outputs, hasExternalInputs = false) {
|
|
128
138
|
if (!needToAutoApprove())
|
|
@@ -131,7 +141,7 @@ async function approveTx(outputs, hasExternalInputs = false) {
|
|
|
131
141
|
const isSelfTransfer = outputs.length === 0 && !hasExternalInputs;
|
|
132
142
|
if (isSelfTransfer) {
|
|
133
143
|
if (isStaxOrFlex()) {
|
|
134
|
-
await _touch(2);
|
|
144
|
+
await _touch(2, true);
|
|
135
145
|
}
|
|
136
146
|
else {
|
|
137
147
|
await clickAndApprove(2);
|
|
@@ -150,49 +160,51 @@ async function approveHash() {
|
|
|
150
160
|
if (!needToAutoApprove())
|
|
151
161
|
return;
|
|
152
162
|
if (isStaxOrFlex()) {
|
|
153
|
-
return await _touch(
|
|
154
|
-
}
|
|
155
|
-
if (getModel() === 'nanos') {
|
|
156
|
-
await clickAndApprove(5);
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
await clickAndApprove(3);
|
|
163
|
+
return await _touch(2, true);
|
|
160
164
|
}
|
|
165
|
+
await clickAndApprove(3);
|
|
161
166
|
}
|
|
162
167
|
exports.approveHash = approveHash;
|
|
163
168
|
async function approveAddress() {
|
|
164
169
|
if (!needToAutoApprove())
|
|
165
170
|
return;
|
|
166
171
|
if (isStaxOrFlex()) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
await clickAndApprove(4);
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
await clickAndApprove(2);
|
|
172
|
+
await _touch(1);
|
|
173
|
+
await staxFlexApproveOnce();
|
|
174
|
+
return;
|
|
174
175
|
}
|
|
176
|
+
await clickAndApprove(2);
|
|
175
177
|
}
|
|
176
178
|
exports.approveAddress = approveAddress;
|
|
177
179
|
function isStaxOrFlex() {
|
|
178
180
|
return !getModel().startsWith('nano');
|
|
179
181
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
exports.isNanos = isNanos;
|
|
184
|
-
function skipBlindSigningWarning() {
|
|
182
|
+
exports.isStaxOrFlex = isStaxOrFlex;
|
|
183
|
+
async function skipBlindSigningWarning() {
|
|
185
184
|
if (!needToAutoApprove())
|
|
186
185
|
return;
|
|
187
186
|
if (isStaxOrFlex()) {
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
await (0, web3_1.sleep)(3000);
|
|
188
|
+
const goToSettings = getModel() === 'stax' ? STAX_GO_TO_SETTINGS : FLEX_GO_TO_SETTINGS;
|
|
189
|
+
await touchPosition(goToSettings);
|
|
190
190
|
}
|
|
191
191
|
else {
|
|
192
|
-
clickAndApprove(3);
|
|
192
|
+
await clickAndApprove(3);
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
exports.skipBlindSigningWarning = skipBlindSigningWarning;
|
|
196
|
+
async function staxFlexAcceptRisk() {
|
|
197
|
+
if (!needToAutoApprove())
|
|
198
|
+
return;
|
|
199
|
+
await (0, web3_1.sleep)(3000);
|
|
200
|
+
if (getModel() === 'stax') {
|
|
201
|
+
await touchPosition(STAX_ACCEPT_RISK_POSITION);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
await touchPosition(FLEX_ACCEPT_RISK_POSITION);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
exports.staxFlexAcceptRisk = staxFlexAcceptRisk;
|
|
196
208
|
async function enableBlindSigning() {
|
|
197
209
|
if (!needToAutoApprove())
|
|
198
210
|
return;
|
package/dist/test/wallet.test.js
CHANGED
|
@@ -36,7 +36,7 @@ describe('ledger wallet', () => {
|
|
|
36
36
|
const transport = await (0, utils_1.createTransport)();
|
|
37
37
|
const app = new ledger_app_1.AlephiumApp(transport);
|
|
38
38
|
const version = await app.getVersion();
|
|
39
|
-
expect(version).toBe('0.4.
|
|
39
|
+
expect(version).toBe('0.4.2');
|
|
40
40
|
await app.close();
|
|
41
41
|
});
|
|
42
42
|
it('should get public key', async () => {
|
|
@@ -269,12 +269,7 @@ describe('ledger wallet', () => {
|
|
|
269
269
|
fixedOutputs: outputs
|
|
270
270
|
};
|
|
271
271
|
const encodedUnsignedTx = web3_1.codec.unsignedTxCodec.encodeApiUnsignedTx(unsignedTx);
|
|
272
|
-
|
|
273
|
-
(0, utils_1.approveTx)([utils_1.OutputType.Nanos11, utils_1.OutputType.Nanos10, utils_1.OutputType.Nanos10, utils_1.OutputType.Nanos10, utils_1.OutputType.Nanos11]);
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
(0, utils_1.approveTx)(Array(5).fill(utils_1.OutputType.BaseAndToken));
|
|
277
|
-
}
|
|
272
|
+
(0, utils_1.approveTx)(Array(5).fill(utils_1.OutputType.BaseAndToken));
|
|
278
273
|
const signature = await app.signUnsignedTx(path, Buffer.from(encodedUnsignedTx));
|
|
279
274
|
const txId = blakejs_1.default.blake2b(encodedUnsignedTx, undefined, 32);
|
|
280
275
|
expect((0, web3_1.transactionVerifySignature)((0, web3_1.binToHex)(txId), testAccount.publicKey, signature)).toBe(true);
|
|
@@ -479,7 +474,12 @@ describe('ledger wallet', () => {
|
|
|
479
474
|
await expect(app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))).rejects.toThrow();
|
|
480
475
|
await (0, utils_1.enableBlindSigning)();
|
|
481
476
|
if ((0, utils_1.needToAutoApprove)()) {
|
|
482
|
-
|
|
477
|
+
if ((0, utils_1.isStaxOrFlex)()) {
|
|
478
|
+
(0, utils_1.staxFlexAcceptRisk)().then(() => (0, utils_1.approveTx)([]));
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
(0, utils_1.approveTx)([]);
|
|
482
|
+
}
|
|
483
483
|
}
|
|
484
484
|
else {
|
|
485
485
|
// waiting for blind signing setting to be enabled
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alephium/ledger-app",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"license": "GPL",
|
|
5
5
|
"types": "dist/src/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@alephium/web3": "^1.5.0",
|
|
31
|
-
"@ledgerhq/hw-transport": "6.31.
|
|
31
|
+
"@ledgerhq/hw-transport": "^6.31.4",
|
|
32
32
|
"blakejs": "^1.2.1"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
package/test/merkle.test.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import { hashPair, merkleTokens, tokenMerkleProofs, tokenMerkleRoot } from '../src/merkle'
|
|
1
|
+
import { generateProofs, hashPair, merkleTokens, tokenMerkleProofs, tokenMerkleRoot } from '../src/merkle'
|
|
2
2
|
import { serializeSingleTokenMetadata } from '../src/serde'
|
|
3
3
|
import { blake2b } from 'blakejs'
|
|
4
4
|
import { binToHex } from '@alephium/web3'
|
|
5
5
|
|
|
6
6
|
describe('Merkle', () => {
|
|
7
|
+
it('should generate the correct proofs', () => {
|
|
8
|
+
const { proofs, root } = generateProofs()
|
|
9
|
+
expect(JSON.stringify(proofs)).toBe(JSON.stringify(tokenMerkleProofs))
|
|
10
|
+
expect(root).toBe(binToHex(tokenMerkleRoot))
|
|
11
|
+
})
|
|
12
|
+
|
|
7
13
|
it('should verify proofs', () => {
|
|
8
14
|
for (const token of merkleTokens) {
|
|
9
15
|
const proof = tokenMerkleProofs[token.tokenId]
|
package/test/utils.ts
CHANGED
|
@@ -21,29 +21,17 @@ async function clickAndApprove(times: number) {
|
|
|
21
21
|
|
|
22
22
|
function getModel(): string {
|
|
23
23
|
const model = process.env.MODEL
|
|
24
|
-
return model ? model as string : '
|
|
24
|
+
return model ? model as string : 'nanosp'
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export enum OutputType {
|
|
28
28
|
Base,
|
|
29
29
|
Multisig,
|
|
30
|
-
Nanos10,
|
|
31
|
-
Nanos11,
|
|
32
30
|
Token,
|
|
33
31
|
BaseAndToken,
|
|
34
32
|
MultisigAndToken
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
const NanosClickTable = new Map([
|
|
38
|
-
[OutputType.Base, 5],
|
|
39
|
-
[OutputType.Multisig, 10],
|
|
40
|
-
[OutputType.Nanos10, 10],
|
|
41
|
-
[OutputType.Nanos11, 11],
|
|
42
|
-
[OutputType.Token, 11],
|
|
43
|
-
[OutputType.BaseAndToken, 12],
|
|
44
|
-
[OutputType.MultisigAndToken, 16],
|
|
45
|
-
])
|
|
46
|
-
|
|
47
35
|
const NanospClickTable = new Map([
|
|
48
36
|
[OutputType.Base, 3],
|
|
49
37
|
[OutputType.Multisig, 5],
|
|
@@ -53,21 +41,28 @@ const NanospClickTable = new Map([
|
|
|
53
41
|
])
|
|
54
42
|
|
|
55
43
|
const StaxClickTable = new Map([
|
|
56
|
-
[OutputType.Base,
|
|
57
|
-
[OutputType.Multisig,
|
|
58
|
-
[OutputType.Token,
|
|
59
|
-
[OutputType.BaseAndToken,
|
|
60
|
-
[OutputType.MultisigAndToken,
|
|
44
|
+
[OutputType.Base, 1],
|
|
45
|
+
[OutputType.Multisig, 2],
|
|
46
|
+
[OutputType.Token, 2],
|
|
47
|
+
[OutputType.BaseAndToken, 2],
|
|
48
|
+
[OutputType.MultisigAndToken, 2],
|
|
49
|
+
])
|
|
50
|
+
|
|
51
|
+
const FlexClickTable = new Map([
|
|
52
|
+
[OutputType.Base, 1],
|
|
53
|
+
[OutputType.Multisig, 2],
|
|
54
|
+
[OutputType.Token, 2],
|
|
55
|
+
[OutputType.BaseAndToken, 2],
|
|
56
|
+
[OutputType.MultisigAndToken, 3],
|
|
61
57
|
])
|
|
62
58
|
|
|
63
59
|
function getOutputClickSize(outputType: OutputType) {
|
|
64
60
|
const model = getModel()
|
|
65
61
|
switch (model) {
|
|
66
|
-
case 'nanos': return NanosClickTable.get(outputType)!
|
|
67
62
|
case 'nanosp':
|
|
68
63
|
case 'nanox': return NanospClickTable.get(outputType)!
|
|
69
|
-
case 'stax':
|
|
70
|
-
case 'flex': return
|
|
64
|
+
case 'stax': return StaxClickTable.get(outputType)!
|
|
65
|
+
case 'flex': return FlexClickTable.get(outputType)!
|
|
71
66
|
default: throw new Error(`Unknown model ${model}`)
|
|
72
67
|
}
|
|
73
68
|
}
|
|
@@ -95,12 +90,16 @@ const STAX_APPROVE_POSITION = { x: 200, y: 515 }
|
|
|
95
90
|
const STAX_REJECT_POSITION = { x: 36, y: 606 }
|
|
96
91
|
const STAX_SETTINGS_POSITION = { x: 342, y: 55 }
|
|
97
92
|
const STAX_BLIND_SETTING_POSITION = { x: 342, y: 90 }
|
|
93
|
+
const STAX_GO_TO_SETTINGS = { x: 36, y: 606 }
|
|
94
|
+
const STAX_ACCEPT_RISK_POSITION = { x: 36, y: 606 }
|
|
98
95
|
|
|
99
96
|
const FLEX_CONTINUE_POSITION = { x: 430, y: 550 }
|
|
100
97
|
const FLEX_APPROVE_POSITION = { x: 240, y: 435 }
|
|
101
98
|
const FLEX_REJECT_POSITION = { x: 55, y: 530 }
|
|
102
99
|
const FLEX_SETTINGS_POSITION = { x: 405, y: 75 }
|
|
103
100
|
const FLEX_BLIND_SETTING_POSITION = { x: 405, y: 96 }
|
|
101
|
+
const FLEX_GO_TO_SETTINGS = { x: 55, y: 530 }
|
|
102
|
+
const FLEX_ACCEPT_RISK_POSITION = { x: 55, y: 530 }
|
|
104
103
|
|
|
105
104
|
async function touchPosition(pos: Position) {
|
|
106
105
|
await sleep(1000)
|
|
@@ -110,14 +109,24 @@ async function touchPosition(pos: Position) {
|
|
|
110
109
|
})
|
|
111
110
|
}
|
|
112
111
|
|
|
113
|
-
async function
|
|
112
|
+
async function longPress(pos: Position) {
|
|
113
|
+
await sleep(1000)
|
|
114
|
+
return fetch(`http://localhost:25000/finger`, {
|
|
115
|
+
method: 'POST',
|
|
116
|
+
body: JSON.stringify({ action: 'press-and-release', x: pos.x, y: pos.y, delay: 3 })
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function _touch(times: number, approve: boolean = false) {
|
|
114
121
|
const model = getModel()
|
|
115
122
|
const continuePos = model === 'stax' ? STAX_CONTINUE_POSITION : FLEX_CONTINUE_POSITION
|
|
116
123
|
for (let i = 0; i < times; i += 1) {
|
|
117
124
|
await touchPosition(continuePos)
|
|
118
125
|
}
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
if (approve) {
|
|
127
|
+
const approvePos = model === 'stax' ? STAX_APPROVE_POSITION : FLEX_APPROVE_POSITION
|
|
128
|
+
await longPress(approvePos)
|
|
129
|
+
}
|
|
121
130
|
}
|
|
122
131
|
|
|
123
132
|
export async function staxFlexApproveOnce() {
|
|
@@ -129,16 +138,19 @@ export async function staxFlexApproveOnce() {
|
|
|
129
138
|
}
|
|
130
139
|
|
|
131
140
|
async function touch(outputs: OutputType[], hasExternalInputs: boolean) {
|
|
132
|
-
await sleep(
|
|
141
|
+
await sleep(3000);
|
|
133
142
|
if (hasExternalInputs) {
|
|
134
143
|
await staxFlexApproveOnce()
|
|
135
144
|
}
|
|
136
145
|
|
|
146
|
+
_touch(1) // the first review page
|
|
147
|
+
await sleep(1000)
|
|
148
|
+
|
|
137
149
|
for (let index = 0; index < outputs.length; index += 1) {
|
|
138
150
|
await _touch(getOutputClickSize(outputs[index]))
|
|
139
151
|
}
|
|
140
152
|
|
|
141
|
-
await _touch(
|
|
153
|
+
await _touch(1, true) // fees
|
|
142
154
|
}
|
|
143
155
|
|
|
144
156
|
export async function approveTx(outputs: OutputType[], hasExternalInputs: boolean = false) {
|
|
@@ -147,7 +159,7 @@ export async function approveTx(outputs: OutputType[], hasExternalInputs: boolea
|
|
|
147
159
|
const isSelfTransfer = outputs.length === 0 && !hasExternalInputs
|
|
148
160
|
if (isSelfTransfer) {
|
|
149
161
|
if (isStaxOrFlex()) {
|
|
150
|
-
await _touch(2)
|
|
162
|
+
await _touch(2, true)
|
|
151
163
|
} else {
|
|
152
164
|
await clickAndApprove(2)
|
|
153
165
|
}
|
|
@@ -164,42 +176,43 @@ export async function approveTx(outputs: OutputType[], hasExternalInputs: boolea
|
|
|
164
176
|
export async function approveHash() {
|
|
165
177
|
if (!needToAutoApprove()) return
|
|
166
178
|
if (isStaxOrFlex()) {
|
|
167
|
-
return await _touch(
|
|
168
|
-
}
|
|
169
|
-
if (getModel() === 'nanos') {
|
|
170
|
-
await clickAndApprove(5)
|
|
171
|
-
} else {
|
|
172
|
-
await clickAndApprove(3)
|
|
179
|
+
return await _touch(2, true)
|
|
173
180
|
}
|
|
181
|
+
await clickAndApprove(3)
|
|
174
182
|
}
|
|
175
183
|
|
|
176
184
|
export async function approveAddress() {
|
|
177
185
|
if (!needToAutoApprove()) return
|
|
178
186
|
if (isStaxOrFlex()) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
await clickAndApprove(4)
|
|
183
|
-
} else {
|
|
184
|
-
await clickAndApprove(2)
|
|
187
|
+
await _touch(1)
|
|
188
|
+
await staxFlexApproveOnce()
|
|
189
|
+
return
|
|
185
190
|
}
|
|
191
|
+
await clickAndApprove(2)
|
|
186
192
|
}
|
|
187
193
|
|
|
188
|
-
function isStaxOrFlex(): boolean {
|
|
194
|
+
export function isStaxOrFlex(): boolean {
|
|
189
195
|
return !getModel().startsWith('nano')
|
|
190
196
|
}
|
|
191
197
|
|
|
192
|
-
export function
|
|
193
|
-
|
|
198
|
+
export async function skipBlindSigningWarning() {
|
|
199
|
+
if (!needToAutoApprove()) return
|
|
200
|
+
if (isStaxOrFlex()) {
|
|
201
|
+
await sleep(3000)
|
|
202
|
+
const goToSettings = getModel() === 'stax' ? STAX_GO_TO_SETTINGS : FLEX_GO_TO_SETTINGS
|
|
203
|
+
await touchPosition(goToSettings)
|
|
204
|
+
} else {
|
|
205
|
+
await clickAndApprove(3)
|
|
206
|
+
}
|
|
194
207
|
}
|
|
195
208
|
|
|
196
|
-
export function
|
|
209
|
+
export async function staxFlexAcceptRisk() {
|
|
197
210
|
if (!needToAutoApprove()) return
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
touchPosition(
|
|
211
|
+
await sleep(3000)
|
|
212
|
+
if (getModel() === 'stax') {
|
|
213
|
+
await touchPosition(STAX_ACCEPT_RISK_POSITION)
|
|
201
214
|
} else {
|
|
202
|
-
|
|
215
|
+
await touchPosition(FLEX_ACCEPT_RISK_POSITION)
|
|
203
216
|
}
|
|
204
217
|
}
|
|
205
218
|
|
package/test/wallet.test.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ALPH_TOKEN_ID, Address, DUST_AMOUNT, NodeProvider, ONE_ALPH, binToHex,
|
|
|
3
3
|
import { getSigner, mintToken, transfer } from '@alephium/web3-test'
|
|
4
4
|
import { PrivateKeyWallet } from '@alephium/web3-wallet'
|
|
5
5
|
import blake from 'blakejs'
|
|
6
|
-
import { approveAddress, approveHash, approveTx, createTransport, enableBlindSigning, getRandomInt,
|
|
6
|
+
import { approveAddress, approveHash, approveTx, createTransport, enableBlindSigning, getRandomInt, isStaxOrFlex, needToAutoApprove, OutputType, skipBlindSigningWarning, staxFlexAcceptRisk, staxFlexApproveOnce } from './utils'
|
|
7
7
|
import { TokenMetadata } from '../src/types'
|
|
8
8
|
import { randomBytes } from 'crypto'
|
|
9
9
|
import { merkleTokens, tokenMerkleProofs } from '../src/merkle'
|
|
@@ -37,7 +37,7 @@ describe('ledger wallet', () => {
|
|
|
37
37
|
const transport = await createTransport()
|
|
38
38
|
const app = new AlephiumApp(transport)
|
|
39
39
|
const version = await app.getVersion()
|
|
40
|
-
expect(version).toBe('0.4.
|
|
40
|
+
expect(version).toBe('0.4.2')
|
|
41
41
|
await app.close()
|
|
42
42
|
})
|
|
43
43
|
|
|
@@ -309,11 +309,7 @@ describe('ledger wallet', () => {
|
|
|
309
309
|
}
|
|
310
310
|
const encodedUnsignedTx = codec.unsignedTxCodec.encodeApiUnsignedTx(unsignedTx)
|
|
311
311
|
|
|
312
|
-
|
|
313
|
-
approveTx([OutputType.Nanos11, OutputType.Nanos10, OutputType.Nanos10, OutputType.Nanos10, OutputType.Nanos11])
|
|
314
|
-
} else {
|
|
315
|
-
approveTx(Array(5).fill(OutputType.BaseAndToken))
|
|
316
|
-
}
|
|
312
|
+
approveTx(Array(5).fill(OutputType.BaseAndToken))
|
|
317
313
|
const signature = await app.signUnsignedTx(path, Buffer.from(encodedUnsignedTx))
|
|
318
314
|
const txId = blake.blake2b(encodedUnsignedTx, undefined, 32)
|
|
319
315
|
expect(transactionVerifySignature(binToHex(txId), testAccount.publicKey, signature)).toBe(true)
|
|
@@ -547,7 +543,11 @@ describe('ledger wallet', () => {
|
|
|
547
543
|
|
|
548
544
|
await enableBlindSigning()
|
|
549
545
|
if (needToAutoApprove()) {
|
|
550
|
-
|
|
546
|
+
if (isStaxOrFlex()) {
|
|
547
|
+
staxFlexAcceptRisk().then(() => approveTx([]))
|
|
548
|
+
} else {
|
|
549
|
+
approveTx([])
|
|
550
|
+
}
|
|
551
551
|
} else {
|
|
552
552
|
// waiting for blind signing setting to be enabled
|
|
553
553
|
await sleep(20000)
|