@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/dist/src/index.d.ts +4 -2
- package/dist/src/index.js +15 -4
- package/dist/test/utils.d.ts +16 -0
- package/dist/test/utils.js +215 -0
- package/dist/test/{speculos.test.js → wallet.test.js} +140 -174
- package/package.json +7 -7
- package/src/index.ts +18 -4
- package/test/utils.ts +222 -0
- package/test/{speculos.test.ts → wallet.test.ts} +156 -166
- package/dist/test/release.test.js +0 -132
- package/dist/test/speculos.test.d.ts +0 -1
- package/test/release.test.ts +0 -152
- /package/dist/test/{release.test.d.ts → wallet.test.d.ts} +0 -0
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
|
|
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
|
-
|
|
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
|
|
35
|
+
const transport = await createTransport()
|
|
41
36
|
const app = new AlephiumApp(transport)
|
|
42
37
|
const version = await app.getVersion()
|
|
43
|
-
expect(version).toBe('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
|
|
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
|
|
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
|
|
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
|
-
|
|
78
|
-
const
|
|
79
|
-
const
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
return BigInt(balances.balance)
|
|
89
|
-
}
|
|
86
|
+
const [account] = await app.getAccount(path)
|
|
87
|
+
console.log(account)
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
await
|
|
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('
|
|
99
|
-
const transport = await
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 *
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
341
|
-
const transport = await
|
|
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:
|
|
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
|
-
|
|
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(
|
|
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
|
})
|