@alephium/ledger-app 0.3.0 → 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.
package/test/utils.ts ADDED
@@ -0,0 +1,222 @@
1
+ import SpeculosTransport from '@ledgerhq/hw-transport-node-speculos'
2
+ import fetch from 'node-fetch'
3
+ import { sleep } from '@alephium/web3'
4
+ import Transport from '@ledgerhq/hw-transport'
5
+ import NodeTransport from '@ledgerhq/hw-transport-node-hid'
6
+
7
+ async function pressButton(button: 'left' | 'right' | 'both') {
8
+ await sleep(1000)
9
+ return fetch(`http://localhost:25000/button/${button}`, {
10
+ method: 'POST',
11
+ body: JSON.stringify({ action: 'press-and-release' })
12
+ })
13
+ }
14
+
15
+ async function clickAndApprove(times: number) {
16
+ for (let i = 0; i < times; i++) {
17
+ await pressButton('right')
18
+ }
19
+ await pressButton('both')
20
+ }
21
+
22
+ export enum OutputType {
23
+ Base,
24
+ Multisig,
25
+ Token,
26
+ MultisigAndToken
27
+ }
28
+
29
+ const NanosClickTable = new Map([
30
+ [OutputType.Base, 5],
31
+ [OutputType.Multisig, 10],
32
+ [OutputType.Token, 11],
33
+ [OutputType.MultisigAndToken, 16],
34
+ ])
35
+
36
+ const NanospClickTable = new Map([
37
+ [OutputType.Base, 3],
38
+ [OutputType.Multisig, 5],
39
+ [OutputType.Token, 6],
40
+ [OutputType.MultisigAndToken, 8],
41
+ ])
42
+
43
+ const StaxClickTable = new Map([
44
+ [OutputType.Base, 2],
45
+ [OutputType.Multisig, 3],
46
+ [OutputType.Token, 3],
47
+ [OutputType.MultisigAndToken, 4],
48
+ ])
49
+
50
+ function getOutputClickSize(outputType: OutputType) {
51
+ const model = process.env.MODEL
52
+ switch (model) {
53
+ case 'nanos': return NanosClickTable.get(outputType)!
54
+ case 'nanosp':
55
+ case 'nanox': return NanospClickTable.get(outputType)!
56
+ case 'stax':
57
+ case 'flex': return StaxClickTable.get(outputType)!
58
+ default: throw new Error(`Unknown model ${model}`)
59
+ }
60
+ }
61
+
62
+ async function click(outputs: OutputType[], hasExternalInputs: boolean) {
63
+ await sleep(1000);
64
+ if (hasExternalInputs) {
65
+ await clickAndApprove(1)
66
+ }
67
+
68
+ for (let index = 0; index < outputs.length; index += 1) {
69
+ await clickAndApprove(getOutputClickSize(outputs[index]))
70
+ }
71
+
72
+ await clickAndApprove(1) // fees
73
+ }
74
+
75
+ interface Position {
76
+ x: number
77
+ y: number
78
+ }
79
+
80
+ const STAX_CONTINUE_POSITION = { x: 342, y: 606 }
81
+ const STAX_APPROVE_POSITION = { x: 200, y: 515 }
82
+ const STAX_REJECT_POSITION = { x: 36, y: 606 }
83
+ const STAX_SETTINGS_POSITION = { x: 342, y: 55 }
84
+ const STAX_BLIND_SETTING_POSITION = { x: 342, y: 90 }
85
+
86
+ const FLEX_CONTINUE_POSITION = { x: 430, y: 550 }
87
+ const FLEX_APPROVE_POSITION = { x: 240, y: 435 }
88
+ const FLEX_REJECT_POSITION = { x: 55, y: 530 }
89
+ const FLEX_SETTINGS_POSITION = { x: 405, y: 75 }
90
+ const FLEX_BLIND_SETTING_POSITION = { x: 405, y: 96 }
91
+
92
+ async function touchPosition(pos: Position) {
93
+ await sleep(1000)
94
+ return fetch(`http://localhost:25000/finger`, {
95
+ method: 'POST',
96
+ body: JSON.stringify({ action: 'press-and-release', x: pos.x, y: pos.y })
97
+ })
98
+ }
99
+
100
+ async function _touch(times: number) {
101
+ let continuePos = process.env.MODEL === 'stax' ? STAX_CONTINUE_POSITION : FLEX_CONTINUE_POSITION
102
+ for (let i = 0; i < times; i += 1) {
103
+ await touchPosition(continuePos)
104
+ }
105
+ let approvePos = process.env.MODEL === 'stax' ? STAX_APPROVE_POSITION : FLEX_APPROVE_POSITION
106
+ await touchPosition(approvePos)
107
+ }
108
+
109
+ export async function staxFlexApproveOnce() {
110
+ if (process.env.MODEL === 'stax') {
111
+ await touchPosition(STAX_APPROVE_POSITION)
112
+ } else {
113
+ await touchPosition(FLEX_APPROVE_POSITION)
114
+ }
115
+ }
116
+
117
+ async function touch(outputs: OutputType[], hasExternalInputs: boolean) {
118
+ await sleep(1000);
119
+ if (hasExternalInputs) {
120
+ await staxFlexApproveOnce()
121
+ }
122
+
123
+ for (let index = 0; index < outputs.length; index += 1) {
124
+ await _touch(getOutputClickSize(outputs[index]))
125
+ }
126
+
127
+ await _touch(2) // fees
128
+ }
129
+
130
+ export async function approveTx(outputs: OutputType[], hasExternalInputs: boolean = false) {
131
+ if (!needToAutoApprove()) return
132
+ const isSelfTransfer = outputs.length === 0 && !hasExternalInputs
133
+ if (isSelfTransfer) {
134
+ if (isStaxOrFlex()) {
135
+ await _touch(2)
136
+ } else {
137
+ await clickAndApprove(2)
138
+ }
139
+ return
140
+ }
141
+
142
+ if (isStaxOrFlex()) {
143
+ await touch(outputs, hasExternalInputs)
144
+ } else {
145
+ await click(outputs, hasExternalInputs)
146
+ }
147
+ }
148
+
149
+ export async function approveHash() {
150
+ if (!needToAutoApprove()) return
151
+ if (isStaxOrFlex()) {
152
+ return await _touch(3)
153
+ }
154
+ if (process.env.MODEL === 'nanos') {
155
+ await clickAndApprove(5)
156
+ } else {
157
+ await clickAndApprove(3)
158
+ }
159
+ }
160
+
161
+ export async function approveAddress() {
162
+ if (!needToAutoApprove()) return
163
+ if (isStaxOrFlex()) {
164
+ return await _touch(2)
165
+ }
166
+ if (process.env.MODEL === 'nanos') {
167
+ await clickAndApprove(4)
168
+ } else {
169
+ await clickAndApprove(2)
170
+ }
171
+ }
172
+
173
+ function isStaxOrFlex(): boolean {
174
+ return !process.env.MODEL!.startsWith('nano')
175
+ }
176
+
177
+ export function skipBlindSigningWarning() {
178
+ if (!needToAutoApprove()) return
179
+ if (isStaxOrFlex()) {
180
+ const rejectPos = process.env.MODEL === 'stax' ? STAX_REJECT_POSITION : FLEX_REJECT_POSITION
181
+ touchPosition(rejectPos)
182
+ } else {
183
+ clickAndApprove(3)
184
+ }
185
+ }
186
+
187
+ export async function enableBlindSigning() {
188
+ if (!needToAutoApprove()) return
189
+ if (isStaxOrFlex()) {
190
+ const settingsPos = process.env.MODEL === 'stax' ? STAX_SETTINGS_POSITION : FLEX_SETTINGS_POSITION
191
+ const blindSettingPos = process.env.MODEL === 'stax' ? STAX_BLIND_SETTING_POSITION : FLEX_BLIND_SETTING_POSITION
192
+ await touchPosition(settingsPos)
193
+ await touchPosition(blindSettingPos)
194
+ await touchPosition(settingsPos)
195
+ } else {
196
+ await clickAndApprove(2)
197
+ }
198
+ }
199
+
200
+ export function getRandomInt(min: number, max: number) {
201
+ min = Math.ceil(min)
202
+ max = Math.floor(max)
203
+ return Math.floor(Math.random() * (max - min) + min) // The maximum is exclusive and the minimum is inclusive
204
+ }
205
+
206
+ export function needToAutoApprove(): boolean {
207
+ switch (process.env.BACKEND) {
208
+ case "speculos": return true
209
+ case "device": return false
210
+ default: throw new Error(`Invalid backend: ${process.env.BACKEND}`)
211
+ }
212
+ }
213
+
214
+ const ApduPort = 9999
215
+
216
+ export async function createTransport(): Promise<Transport> {
217
+ switch (process.env.BACKEND) {
218
+ case "speculos": return SpeculosTransport.open({ apduPort: ApduPort })
219
+ case "device": return NodeTransport.open('')
220
+ default: throw new Error(`Invalid backend: ${process.env.BACKEND}`)
221
+ }
222
+ }
@@ -1,31 +1,12 @@
1
1
  import SpeculosTransport from '@ledgerhq/hw-transport-node-speculos'
2
2
  import AlephiumApp, { GROUP_NUM } from '../src'
3
- import fetch from 'node-fetch'
4
- import { ALPH_TOKEN_ID, Address, KeyType, NodeProvider, ONE_ALPH, binToHex, codec, groupOfAddress, node, transactionVerifySignature, waitForTxConfirmation, web3 } from '@alephium/web3'
3
+ import { ALPH_TOKEN_ID, Address, NodeProvider, ONE_ALPH, binToHex, codec, groupOfAddress, node, sleep, transactionVerifySignature, waitForTxConfirmation, web3 } from '@alephium/web3'
5
4
  import { getSigner, mintToken, transfer } from '@alephium/web3-test'
6
5
  import { PrivateKeyWallet } from '@alephium/web3-wallet'
7
6
  import blake from 'blakejs'
7
+ import { approveAddress, approveHash, approveTx, createTransport, enableBlindSigning, getRandomInt, needToAutoApprove, OutputType, skipBlindSigningWarning, staxFlexApproveOnce } from './utils'
8
8
 
9
- function sleep(ms) {
10
- return new Promise((resolve) => setTimeout(resolve, ms))
11
- }
12
-
13
- async function pressButton(button: 'left' | 'right' | 'both') {
14
- await sleep(500)
15
- return fetch(`http://localhost:25000/button/${button}`, {
16
- method: 'POST',
17
- body: JSON.stringify({ action: 'press-and-release' })
18
- })
19
- }
20
-
21
- function getRandomInt(min, max) {
22
- min = Math.ceil(min)
23
- max = Math.floor(max)
24
- return Math.floor(Math.random() * (max - min) + min) // The maximum is exclusive and the minimum is inclusive
25
- }
26
-
27
- describe('sdk', () => {
28
- const apduPort = 9999
9
+ describe('ledger wallet', () => {
29
10
  const nodeProvider = new NodeProvider("http://127.0.0.1:22973")
30
11
  web3.setCurrentNodeProvider(nodeProvider)
31
12
  let pathIndex: number
@@ -36,16 +17,30 @@ describe('sdk', () => {
36
17
  path = `m/44'/1234'/0'/0/` + pathIndex
37
18
  })
38
19
 
20
+ async function transferToAddress(address: Address, amount: bigint = ONE_ALPH * 10n) {
21
+ const balance0 = await getALPHBalance(address)
22
+ const fromAccount = await getSigner()
23
+ const transferResult = await transfer(fromAccount, address, ALPH_TOKEN_ID, amount)
24
+ await waitForTxConfirmation(transferResult.txId, 1, 1000)
25
+ const balance1 = await getALPHBalance(address)
26
+ expect(balance1 - balance0).toEqual(amount)
27
+ }
28
+
29
+ async function getALPHBalance(address: Address) {
30
+ const balances = await nodeProvider.addresses.getAddressesAddressBalance(address)
31
+ return BigInt(balances.balance)
32
+ }
33
+
39
34
  it('should get version', async () => {
40
- const transport = await SpeculosTransport.open({ apduPort })
35
+ const transport = await createTransport()
41
36
  const app = new AlephiumApp(transport)
42
37
  const version = await app.getVersion()
43
- expect(version).toBe('0.2.0')
38
+ expect(version).toBe('0.4.0')
44
39
  await app.close()
45
40
  })
46
41
 
47
42
  it('should get public key', async () => {
48
- const transport = await SpeculosTransport.open({ apduPort })
43
+ const transport = await createTransport()
49
44
  const app = new AlephiumApp(transport)
50
45
  const [account, hdIndex] = await app.getAccount(path)
51
46
  expect(hdIndex).toBe(pathIndex)
@@ -53,8 +48,18 @@ describe('sdk', () => {
53
48
  await app.close()
54
49
  })
55
50
 
51
+ it('should get public key and confirm address', async () => {
52
+ const transport = await createTransport()
53
+ const app = new AlephiumApp(transport)
54
+ approveAddress()
55
+ const [account, hdIndex] = await app.getAccount(path, undefined, undefined, true)
56
+ expect(hdIndex).toBe(pathIndex)
57
+ console.log(account)
58
+ await app.close()
59
+ }, 30000)
60
+
56
61
  it('should get public key for group', async () => {
57
- const transport = await SpeculosTransport.open({ apduPort })
62
+ const transport = await createTransport()
58
63
  const app = new AlephiumApp(transport)
59
64
  for (let group = 0; group < GROUP_NUM; group++) {
60
65
  const [account, hdIndex] = await app.getAccount(path, group)
@@ -66,7 +71,7 @@ describe('sdk', () => {
66
71
  })
67
72
 
68
73
  it('should get public key for group for Schnorr signature', async () => {
69
- const transport = await SpeculosTransport.open({ apduPort })
74
+ const transport = await createTransport()
70
75
  const app = new AlephiumApp(transport)
71
76
  for (let group = 0; group < GROUP_NUM; group++) {
72
77
  await expect(app.getAccount(path, group, 'bip340-schnorr')).rejects.toThrow('BIP340-Schnorr is not supported yet')
@@ -74,29 +79,24 @@ describe('sdk', () => {
74
79
  await app.close()
75
80
  })
76
81
 
77
- async function transferToAddress(address: Address, amount: bigint = ONE_ALPH * 10n) {
78
- const balance0 = await getALPHBalance(address)
79
- const fromAccount = await getSigner()
80
- const transferResult = await transfer(fromAccount, address, ALPH_TOKEN_ID, amount)
81
- await waitForTxConfirmation(transferResult.txId, 1, 1000)
82
- const balance1 = await getALPHBalance(address)
83
- expect(balance1 - balance0).toEqual(amount)
84
- }
82
+ it('should sign hash', async () => {
83
+ const transport = await createTransport()
84
+ const app = new AlephiumApp(transport)
85
85
 
86
- async function getALPHBalance(address: Address) {
87
- const balances = await nodeProvider.addresses.getAddressesAddressBalance(address)
88
- return BigInt(balances.balance)
89
- }
86
+ const [account] = await app.getAccount(path)
87
+ console.log(account)
90
88
 
91
- async function clickAndApprove(times: number) {
92
- for (let i = 0; i < times; i++) {
93
- await pressButton('right')
94
- }
95
- await pressButton('both')
96
- }
89
+ const hash = Buffer.from(blake.blake2b(Buffer.from([0, 1, 2, 3, 4]), undefined, 32))
90
+ approveHash()
91
+ const signature = await app.signHash(path, hash)
92
+ console.log(signature)
93
+ await app.close()
94
+
95
+ expect(transactionVerifySignature(hash.toString('hex'), account.publicKey, signature)).toBe(true)
96
+ }, 10000)
97
97
 
98
- it('should transfer alph to p2pkh address', async () => {
99
- const transport = await SpeculosTransport.open({ apduPort })
98
+ it('shoudl transfer alph to one address', async () => {
99
+ const transport = await createTransport()
100
100
  const app = new AlephiumApp(transport)
101
101
  const [testAccount] = await app.getAccount(path)
102
102
  await transferToAddress(testAccount.address)
@@ -107,30 +107,46 @@ describe('sdk', () => {
107
107
  {
108
108
  address: '1BmVCLrjttchZMW7i6df7mTdCKzHpy38bgDbVL1GqV6P7',
109
109
  attoAlphAmount: (ONE_ALPH * 2n).toString(),
110
- },
110
+ }
111
+ ]
112
+ })
113
+
114
+ approveTx([OutputType.Base])
115
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))
116
+ expect(transactionVerifySignature(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true)
117
+
118
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
119
+ unsignedTx: buildTxResult.unsignedTx,
120
+ signature: signature
121
+ })
122
+ await waitForTxConfirmation(submitResult.txId, 1, 1000)
123
+ const balance = await getALPHBalance(testAccount.address)
124
+ expect(balance < (ONE_ALPH * 8n)).toEqual(true)
125
+
126
+ await app.close()
127
+ }, 120000)
128
+
129
+ it('should transfer alph to multiple addresses', async () => {
130
+ const transport = await createTransport()
131
+ const app = new AlephiumApp(transport)
132
+ const [testAccount] = await app.getAccount(path)
133
+ await transferToAddress(testAccount.address)
134
+
135
+ const buildTxResult = await nodeProvider.transactions.postTransactionsBuild({
136
+ fromPublicKey: testAccount.publicKey,
137
+ destinations: [
111
138
  {
112
139
  address: '1BmVCLrjttchZMW7i6df7mTdCKzHpy38bgDbVL1GqV6P7',
140
+ attoAlphAmount: (ONE_ALPH * 2n).toString(),
141
+ },
142
+ {
143
+ address: '1F1fu6GjuN9yUVRFVcgQKWwiTg8RMzKFv1BZFDwFcfWJq',
113
144
  attoAlphAmount: (ONE_ALPH * 3n).toString(),
114
145
  },
115
146
  ]
116
147
  })
117
148
 
118
- function approve(index: number) {
119
- if (index >= 7) return
120
- if (index >= 3) { // outputs and signature
121
- setTimeout(async () => {
122
- await clickAndApprove(6)
123
- approve(index + 1)
124
- }, 1000)
125
- } else {
126
- setTimeout(async () => {
127
- await clickAndApprove(3)
128
- approve(index + 1)
129
- }, 1000)
130
- }
131
- }
132
-
133
- approve(0)
149
+ approveTx(Array(2).fill(OutputType.Base))
134
150
  const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))
135
151
  expect(transactionVerifySignature(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true)
136
152
 
@@ -146,7 +162,7 @@ describe('sdk', () => {
146
162
  }, 120000)
147
163
 
148
164
  it('should transfer alph to multisig address', async () => {
149
- const transport = await SpeculosTransport.open({ apduPort })
165
+ const transport = await createTransport()
150
166
  const app = new AlephiumApp(transport)
151
167
  const [testAccount] = await app.getAccount(path)
152
168
  await transferToAddress(testAccount.address)
@@ -158,35 +174,11 @@ describe('sdk', () => {
158
174
  {
159
175
  address: multiSigAddress,
160
176
  attoAlphAmount: (ONE_ALPH * 2n).toString(),
161
- },
162
- {
163
- address: multiSigAddress,
164
- attoAlphAmount: (ONE_ALPH * 3n).toString(),
165
- },
177
+ }
166
178
  ]
167
179
  })
168
180
 
169
- function approve(index: number) {
170
- if (index >= 7) return
171
- if (index == 3 || index == 4) { // multi-sig outputs
172
- setTimeout(async () => {
173
- await clickAndApprove(11)
174
- approve(index + 1)
175
- }, 1000)
176
- } else if (index > 4) { // change output and signature
177
- setTimeout(async () => {
178
- await clickAndApprove(6)
179
- approve(index + 1)
180
- }, 1000)
181
- } else {
182
- setTimeout(async () => {
183
- await clickAndApprove(3)
184
- approve(index + 1)
185
- }, 1000)
186
- }
187
- }
188
-
189
- approve(0);
181
+ approveTx([OutputType.Multisig]);
190
182
  const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))
191
183
  expect(transactionVerifySignature(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true)
192
184
 
@@ -196,13 +188,13 @@ describe('sdk', () => {
196
188
  })
197
189
  await waitForTxConfirmation(submitResult.txId, 1, 1000)
198
190
  const balance1 = await getALPHBalance(testAccount.address)
199
- expect(balance1 < (ONE_ALPH * 5n)).toEqual(true)
191
+ expect(balance1 < (ONE_ALPH * 8n)).toEqual(true)
200
192
 
201
193
  await app.close()
202
194
  }, 120000)
203
195
 
204
196
  it('should transfer token to multisig address', async () => {
205
- const transport = await SpeculosTransport.open({ apduPort })
197
+ const transport = await createTransport()
206
198
  const app = new AlephiumApp(transport)
207
199
  const [testAccount] = await app.getAccount(path)
208
200
  await transferToAddress(testAccount.address)
@@ -226,37 +218,7 @@ describe('sdk', () => {
226
218
  ]
227
219
  })
228
220
 
229
- function approve(index: number) {
230
- if (index > 7) return
231
- if (index <= 2) {
232
- setTimeout(async () => {
233
- await clickAndApprove(3)
234
- approve(index + 1)
235
- }, 1000)
236
- } else if (index === 3) { // multi-sig token output
237
- setTimeout(async () => {
238
- await clickAndApprove(17)
239
- approve(index + 1)
240
- }, 1000)
241
- } else if (index === 4) { // multi-sig alph output
242
- setTimeout(async () => {
243
- await clickAndApprove(11)
244
- approve(index + 1)
245
- }, 1000)
246
- } else if (index === 5) { // token change output
247
- setTimeout(async () => {
248
- await clickAndApprove(12)
249
- approve(index + 1)
250
- }, 1000)
251
- } else if (index >= 6) { // alph change output and signature
252
- setTimeout(async () => {
253
- await clickAndApprove(6)
254
- approve(index + 1)
255
- }, 1000)
256
- }
257
- }
258
-
259
- approve(0);
221
+ approveTx([OutputType.MultisigAndToken, OutputType.Multisig])
260
222
  const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))
261
223
  expect(transactionVerifySignature(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true)
262
224
 
@@ -278,7 +240,7 @@ describe('sdk', () => {
278
240
  }, 120000)
279
241
 
280
242
  it('should transfer from multiple inputs', async () => {
281
- const transport = await SpeculosTransport.open({ apduPort })
243
+ const transport = await createTransport()
282
244
  const app = new AlephiumApp(transport)
283
245
  const [testAccount] = await app.getAccount(path)
284
246
  for (let i = 0; i < 20; i += 1) {
@@ -295,22 +257,7 @@ describe('sdk', () => {
295
257
  ]
296
258
  })
297
259
 
298
- function approve(index: number) {
299
- if (index >= 6) return
300
- if (index >= 3) { // outputs and signature
301
- setTimeout(async () => {
302
- await clickAndApprove(6)
303
- approve(index + 1)
304
- }, 1000)
305
- } else {
306
- setTimeout(async () => {
307
- await clickAndApprove(3)
308
- approve(index + 1)
309
- }, 1000)
310
- }
311
- }
312
-
313
- approve(0)
260
+ approveTx([OutputType.Base])
314
261
  const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))
315
262
  expect(transactionVerifySignature(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true)
316
263
 
@@ -337,8 +284,8 @@ describe('sdk', () => {
337
284
  return { account, unlockScript }
338
285
  }
339
286
 
340
- it('should transfer from different input addresses', async () => {
341
- const transport = await SpeculosTransport.open({ apduPort })
287
+ it('should test external inputs', async () => {
288
+ const transport = await createTransport()
342
289
  const app = new AlephiumApp(transport)
343
290
  const [testAccount] = await app.getAccount(path)
344
291
  const { account: newAccount, unlockScript: unlockScript0 } = getAccount(testAccount.group)
@@ -373,7 +320,7 @@ describe('sdk', () => {
373
320
  hint: 0,
374
321
  key: '',
375
322
  attoAlphAmount: (ONE_ALPH * 3n).toString(),
376
- address: testAccount.address,
323
+ address: newAccount.address,
377
324
  tokens: [],
378
325
  lockTime: 0,
379
326
  message: ''
@@ -385,27 +332,7 @@ describe('sdk', () => {
385
332
  unsignedTx: binToHex(txBytes)
386
333
  })
387
334
 
388
- function approve(index: number) {
389
- if (index > 6) return
390
- if (index === 3 || index === 4) { // inputs
391
- setTimeout(async () => {
392
- await clickAndApprove(5)
393
- approve(index + 1)
394
- }, 1000)
395
- } else if (index >= 5) { // outputs and tx id
396
- setTimeout(async () => {
397
- await clickAndApprove(6)
398
- approve(index + 1)
399
- }, 1000)
400
- } else {
401
- setTimeout(async () => {
402
- await clickAndApprove(3)
403
- approve(index + 1)
404
- }, 1000)
405
- }
406
- }
407
-
408
- approve(0)
335
+ approveTx([OutputType.Base], true)
409
336
  const signature1 = await app.signUnsignedTx(path, Buffer.from(txBytes))
410
337
  expect(transactionVerifySignature(signResult0.txId, testAccount.publicKey, signature1)).toBe(true)
411
338
 
@@ -414,9 +341,72 @@ describe('sdk', () => {
414
341
  signatures: [signResult0.signature, signature1]
415
342
  })
416
343
  await waitForTxConfirmation(submitResult.txId, 1, 1000)
417
- const balance = await getALPHBalance(testAccount.address)
344
+ const balance = await getALPHBalance(newAccount.address)
418
345
  expect(balance).toEqual(ONE_ALPH * 3n)
419
346
 
420
347
  await app.close()
421
348
  }, 120000)
349
+
350
+ it('should test self transfer tx', async () => {
351
+ const transport = await createTransport()
352
+ const app = new AlephiumApp(transport)
353
+ const [testAccount] = await app.getAccount(path)
354
+ await transferToAddress(testAccount.address)
355
+
356
+ const buildTxResult = await nodeProvider.transactions.postTransactionsBuild({
357
+ fromPublicKey: testAccount.publicKey,
358
+ destinations: [
359
+ {
360
+ address: testAccount.address,
361
+ attoAlphAmount: (ONE_ALPH * 2n).toString(),
362
+ }
363
+ ]
364
+ })
365
+
366
+ approveTx([])
367
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))
368
+ expect(transactionVerifySignature(buildTxResult.txId, testAccount.publicKey, signature)).toBe(true)
369
+
370
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
371
+ unsignedTx: buildTxResult.unsignedTx,
372
+ signature: signature
373
+ })
374
+ await waitForTxConfirmation(submitResult.txId, 1, 1000)
375
+ const balance = await getALPHBalance(testAccount.address)
376
+ expect(balance > (ONE_ALPH * 9n)).toEqual(true)
377
+
378
+ await app.close()
379
+ }, 12000)
380
+
381
+ it('should test script execution tx', async () => {
382
+ const transport = await createTransport()
383
+ const app = new AlephiumApp(transport)
384
+ const [testAccount] = await app.getAccount(path)
385
+ await transferToAddress(testAccount.address)
386
+ const buildTxResult = await nodeProvider.contracts.postContractsUnsignedTxDeployContract({
387
+ fromPublicKey: testAccount.publicKey,
388
+ bytecode: '00010c010000000002d38d0b3636020000'
389
+ })
390
+
391
+ setTimeout(() => skipBlindSigningWarning(), 1000)
392
+ await expect(app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))).rejects.toThrow()
393
+
394
+ await enableBlindSigning()
395
+ if (needToAutoApprove()) {
396
+ staxFlexApproveOnce().then(() => approveTx([]))
397
+ } else {
398
+ // waiting for blind signing setting to be enabled
399
+ await sleep(20000)
400
+ }
401
+ const signature = await app.signUnsignedTx(path, Buffer.from(buildTxResult.unsignedTx, 'hex'))
402
+ const submitResult = await nodeProvider.transactions.postTransactionsSubmit({
403
+ unsignedTx: buildTxResult.unsignedTx,
404
+ signature: signature
405
+ })
406
+ await waitForTxConfirmation(submitResult.txId, 1, 1000)
407
+ const details = await nodeProvider.transactions.getTransactionsDetailsTxid(submitResult.txId)
408
+ expect(details.scriptExecutionOk).toEqual(true)
409
+
410
+ await app.close()
411
+ }, 120000)
422
412
  })