nexa-wallet-sdk 0.1.2
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/.parcel-cache/3e09f086f3c4d605-AssetGraph +0 -0
- package/.parcel-cache/5eac57ec674cdae8-AssetGraph +0 -0
- package/.parcel-cache/data.mdb +0 -0
- package/.parcel-cache/e43547b6c9167b58-RequestGraph +0 -0
- package/.parcel-cache/ecfe15d74834bbfd-BundleGraph +0 -0
- package/.parcel-cache/lock.mdb +0 -0
- package/.parcel-cache/snapshot-e43547b6c9167b58.txt +2 -0
- package/README.md +445 -0
- package/dist/browser/index.js +2456 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/index.d.ts +918 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2915 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2456 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +90 -0
- package/spec.md +257 -0
- package/src/index.ts +93 -0
- package/src/models/rostrum.entities.ts +159 -0
- package/src/models/transaction.entities.ts +46 -0
- package/src/models/wallet.entities.ts +42 -0
- package/src/network/RostrumProvider.ts +137 -0
- package/src/types.ts +0 -0
- package/src/utils/CommonUtils.ts +123 -0
- package/src/utils/TXUtils.ts +445 -0
- package/src/utils/TokenUtils.ts +75 -0
- package/src/utils/ValidationUtils.ts +86 -0
- package/src/utils/WalletUtils.ts +522 -0
- package/src/utils/WatchOnlyTXUtils.ts +275 -0
- package/src/wallet/Wallet.ts +397 -0
- package/src/wallet/WatchOnlyWallet.ts +169 -0
- package/src/wallet/accounts/AccountStore.ts +173 -0
- package/src/wallet/accounts/interfaces/BaseAccountInterface.ts +56 -0
- package/src/wallet/accounts/models/DappAccount.ts +80 -0
- package/src/wallet/accounts/models/DefaultAccount.ts +96 -0
- package/src/wallet/accounts/models/VaultAccount.ts +81 -0
- package/src/wallet/transactions/WalletTransactionCreator.ts +145 -0
- package/src/wallet/transactions/WatchOnlyTransactionCreator.ts +189 -0
- package/src/wallet/transactions/interfaces/TransactionCreator.ts +438 -0
- package/tests/core/tx/transactioncreator.test.ts +455 -0
- package/tests/core/tx/wallettransactioncreator.test.ts +362 -0
- package/tests/core/tx/watchonlytransactioncreator.test.ts +258 -0
- package/tests/core/wallet/accountstore.test.ts +341 -0
- package/tests/core/wallet/wallet.test.ts +69 -0
- package/tests/core/watchonlywallet/watchonlywallet.test.ts +251 -0
- package/tests/index.test.ts +12 -0
- package/tsconfig.json +113 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, vi } from 'vitest'
|
|
2
|
+
import { TransactionBuilder, Networks, PrivateKey } from 'libnexa-ts'
|
|
3
|
+
import WalletTransactionCreator from '../../../src/wallet/transactions/WalletTransactionCreator'
|
|
4
|
+
import { BaseAccount } from '../../../src/wallet/accounts/interfaces/BaseAccountInterface'
|
|
5
|
+
import { AddressKey } from '../../../src/models/wallet.entities'
|
|
6
|
+
|
|
7
|
+
// Mock the TXUtils functions
|
|
8
|
+
vi.mock('../../../src/utils/TXUtils', () => ({
|
|
9
|
+
populateTokenAuth: vi.fn().mockResolvedValue([{} as PrivateKey]),
|
|
10
|
+
buildCreateGroupTransaction: vi.fn().mockResolvedValue([{} as PrivateKey]),
|
|
11
|
+
populateAndDuplicateTokenAuths: vi.fn().mockResolvedValue([{} as PrivateKey]),
|
|
12
|
+
prepareDeleteTransaction: vi.fn().mockResolvedValue([{} as PrivateKey]),
|
|
13
|
+
populateTokenInputsAndChange: vi.fn().mockResolvedValue([{} as PrivateKey]),
|
|
14
|
+
populateNexaInputsAndChange: vi.fn().mockResolvedValue([{} as PrivateKey])
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
// Mock the rostrumProvider
|
|
18
|
+
vi.mock('../../../src/network/RostrumProvider', () => ({
|
|
19
|
+
rostrumProvider: {
|
|
20
|
+
getUtxo: vi.fn().mockResolvedValue({
|
|
21
|
+
tx_hash: 'mock-tx-hash',
|
|
22
|
+
amount: 1000000,
|
|
23
|
+
scriptpubkey: 'mock-scriptpubkey',
|
|
24
|
+
addresses: ['nexatest:address123']
|
|
25
|
+
}),
|
|
26
|
+
getBlockTip: vi.fn().mockResolvedValue({
|
|
27
|
+
height: 100000
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}))
|
|
31
|
+
|
|
32
|
+
describe('WalletTransactionCreator', () => {
|
|
33
|
+
let creator: WalletTransactionCreator
|
|
34
|
+
let mockAccount: BaseAccount
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
mockAccount = {
|
|
38
|
+
accountKeys: {
|
|
39
|
+
receiveKeys: [
|
|
40
|
+
{
|
|
41
|
+
key: { privateKey: {} as PrivateKey },
|
|
42
|
+
address: 'nexatest:receive123',
|
|
43
|
+
balance: '1000000',
|
|
44
|
+
tokensBalance: {}
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
changeKeys: [
|
|
48
|
+
{
|
|
49
|
+
key: { privateKey: {} as PrivateKey },
|
|
50
|
+
address: 'nexatest:change123',
|
|
51
|
+
balance: '500000',
|
|
52
|
+
tokensBalance: {}
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
} as BaseAccount
|
|
57
|
+
|
|
58
|
+
creator = new WalletTransactionCreator(mockAccount)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('constructor', () => {
|
|
62
|
+
test('should create instance with account', () => {
|
|
63
|
+
expect(creator).toBeInstanceOf(WalletTransactionCreator)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
test('should create instance with account and transaction builder', () => {
|
|
67
|
+
const txBuilder = new TransactionBuilder()
|
|
68
|
+
const creator = new WalletTransactionCreator(mockAccount, txBuilder)
|
|
69
|
+
expect(creator).toBeInstanceOf(WalletTransactionCreator)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
test('should throw error for account without receive keys', () => {
|
|
73
|
+
const invalidAccount = {
|
|
74
|
+
accountKeys: {
|
|
75
|
+
receiveKeys: [],
|
|
76
|
+
changeKeys: []
|
|
77
|
+
}
|
|
78
|
+
} as unknown as BaseAccount
|
|
79
|
+
|
|
80
|
+
expect(() => {
|
|
81
|
+
new WalletTransactionCreator(invalidAccount)
|
|
82
|
+
}).toThrow('No receive keys available in account')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('should throw error for account without account keys', () => {
|
|
86
|
+
const invalidAccount = {} as BaseAccount
|
|
87
|
+
|
|
88
|
+
expect(() => {
|
|
89
|
+
new WalletTransactionCreator(invalidAccount)
|
|
90
|
+
}).toThrow('Account keys are not initialized')
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('fromAccount', () => {
|
|
95
|
+
test('should set account and return this for chaining', () => {
|
|
96
|
+
const newAccount = {
|
|
97
|
+
accountKeys: {
|
|
98
|
+
receiveKeys: [{
|
|
99
|
+
key: {privateKey: {} as PrivateKey},
|
|
100
|
+
address: 'nexatest:new123',
|
|
101
|
+
balance: '0',
|
|
102
|
+
tokensBalance: {}
|
|
103
|
+
}],
|
|
104
|
+
changeKeys: []
|
|
105
|
+
}
|
|
106
|
+
} as unknown as BaseAccount
|
|
107
|
+
|
|
108
|
+
const result = creator.fromAccount(newAccount)
|
|
109
|
+
|
|
110
|
+
expect(result).toBe(creator)
|
|
111
|
+
expect(creator['_account']).toBe(newAccount)
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
describe('parseTxHex', () => {
|
|
116
|
+
test('should add parse operation to builder', () => {
|
|
117
|
+
const hex = 'deadbeef'
|
|
118
|
+
const result = creator.parseTxHex(hex)
|
|
119
|
+
|
|
120
|
+
expect(result).toBe(creator)
|
|
121
|
+
expect(creator.builder).toHaveLength(1)
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
describe('parseTxBuffer', () => {
|
|
126
|
+
test('should add parse operation to builder', () => {
|
|
127
|
+
const buffer = Buffer.from('deadbeef', 'hex')
|
|
128
|
+
const result = creator.parseTxBuffer(buffer)
|
|
129
|
+
|
|
130
|
+
expect(result).toBe(creator)
|
|
131
|
+
expect(creator.builder).toHaveLength(1)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
describe('mint', () => {
|
|
136
|
+
test('should add mint operation to builder', () => {
|
|
137
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
138
|
+
const amount = '1000'
|
|
139
|
+
|
|
140
|
+
const result = creator.mint(token, amount)
|
|
141
|
+
|
|
142
|
+
expect(result).toBe(creator)
|
|
143
|
+
expect(creator.builder).toHaveLength(1)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
test('should be chainable', () => {
|
|
147
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
148
|
+
const amount = '1000'
|
|
149
|
+
|
|
150
|
+
const result = creator
|
|
151
|
+
.mint(token, amount)
|
|
152
|
+
.mint(token, amount)
|
|
153
|
+
|
|
154
|
+
expect(result).toBe(creator)
|
|
155
|
+
expect(creator.builder).toHaveLength(2)
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
describe('melt', () => {
|
|
160
|
+
test('should add melt operation to builder', () => {
|
|
161
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
162
|
+
const amount = '1000'
|
|
163
|
+
|
|
164
|
+
const result = creator.melt(token, amount)
|
|
165
|
+
|
|
166
|
+
expect(result).toBe(creator)
|
|
167
|
+
expect(creator.builder).toHaveLength(1)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
test('should be chainable', () => {
|
|
171
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
172
|
+
const amount = '1000'
|
|
173
|
+
|
|
174
|
+
const result = creator
|
|
175
|
+
.melt(token, amount)
|
|
176
|
+
.melt(token, amount)
|
|
177
|
+
|
|
178
|
+
expect(result).toBe(creator)
|
|
179
|
+
expect(creator.builder).toHaveLength(2)
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
describe('populate', () => {
|
|
184
|
+
test('should add populate operation to builder', () => {
|
|
185
|
+
const result = creator.populate()
|
|
186
|
+
|
|
187
|
+
expect(result).toBe(creator)
|
|
188
|
+
expect(creator.builder).toHaveLength(1)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
test('should validate account before populating', () => {
|
|
192
|
+
const invalidCreator = new WalletTransactionCreator(mockAccount)
|
|
193
|
+
invalidCreator['_account'] = null as any
|
|
194
|
+
|
|
195
|
+
expect(() => {
|
|
196
|
+
invalidCreator.populate()
|
|
197
|
+
}).toThrow('Account must be set before performing transactions')
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
describe('sign', () => {
|
|
202
|
+
test('should add sign operation to builder', () => {
|
|
203
|
+
const result = creator.sign()
|
|
204
|
+
|
|
205
|
+
expect(result).toBe(creator)
|
|
206
|
+
expect(creator.builder).toHaveLength(1)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
test('should be chainable', () => {
|
|
210
|
+
const result = creator
|
|
211
|
+
.populate()
|
|
212
|
+
.sign()
|
|
213
|
+
|
|
214
|
+
expect(result).toBe(creator)
|
|
215
|
+
expect(creator.builder).toHaveLength(2)
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
describe('findPrivateKeyFromAddress', () => {
|
|
220
|
+
test('should find key for existing address', () => {
|
|
221
|
+
const result = creator['findPrivateKeyFromAddress']('nexatest:receive123')
|
|
222
|
+
|
|
223
|
+
expect(result).toBeDefined()
|
|
224
|
+
expect(result?.address).toBe('nexatest:receive123')
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
test('should find key in change addresses', () => {
|
|
228
|
+
const result = creator['findPrivateKeyFromAddress']('nexatest:change123')
|
|
229
|
+
|
|
230
|
+
expect(result).toBeDefined()
|
|
231
|
+
expect(result?.address).toBe('nexatest:change123')
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
test('should return undefined for non-existent address', () => {
|
|
235
|
+
const result = creator['findPrivateKeyFromAddress']('nexatest:nonexistent')
|
|
236
|
+
|
|
237
|
+
expect(result).toBeUndefined()
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
describe('validateAccount', () => {
|
|
242
|
+
test('should not throw for valid account', () => {
|
|
243
|
+
expect(() => {
|
|
244
|
+
creator['validateAccount']()
|
|
245
|
+
}).not.toThrow()
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
test('should throw for null account', () => {
|
|
249
|
+
creator['_account'] = null as any
|
|
250
|
+
|
|
251
|
+
expect(() => {
|
|
252
|
+
creator['validateAccount']()
|
|
253
|
+
}).toThrow('Account must be set before performing transactions')
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
test('should throw for account without keys', () => {
|
|
257
|
+
creator['_account'] = {} as BaseAccount
|
|
258
|
+
|
|
259
|
+
expect(() => {
|
|
260
|
+
creator['validateAccount']()
|
|
261
|
+
}).toThrow('Account keys are not initialized')
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
test('should throw for account without receive keys', () => {
|
|
265
|
+
creator['_account'] = {
|
|
266
|
+
accountKeys: {
|
|
267
|
+
receiveKeys: [],
|
|
268
|
+
changeKeys: []
|
|
269
|
+
}
|
|
270
|
+
} as unknown as BaseAccount
|
|
271
|
+
|
|
272
|
+
expect(() => {
|
|
273
|
+
creator['validateAccount']()
|
|
274
|
+
}).toThrow('No receive keys available in account')
|
|
275
|
+
})
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
describe('integration tests', () => {
|
|
279
|
+
test('should handle complete transaction flow', () => {
|
|
280
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
281
|
+
const amount = '1000'
|
|
282
|
+
const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
283
|
+
|
|
284
|
+
const result = creator
|
|
285
|
+
.onNetwork('testnet')
|
|
286
|
+
.sendTo(toAddr, amount)
|
|
287
|
+
.mint(token, amount)
|
|
288
|
+
.populate()
|
|
289
|
+
.sign()
|
|
290
|
+
|
|
291
|
+
expect(result).toBe(creator)
|
|
292
|
+
expect(creator.builder).toHaveLength(4) // sendTo, mint, populate, sign
|
|
293
|
+
expect(creator.network).toBe(Networks.testnet)
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
test('should handle token operations', () => {
|
|
297
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
298
|
+
const amount = '1000'
|
|
299
|
+
|
|
300
|
+
const result = creator
|
|
301
|
+
.mint(token, amount)
|
|
302
|
+
.melt(token, amount)
|
|
303
|
+
.populate()
|
|
304
|
+
.sign()
|
|
305
|
+
|
|
306
|
+
expect(result).toBe(creator)
|
|
307
|
+
expect(creator.builder).toHaveLength(4)
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
test('should handle token creation', () => {
|
|
311
|
+
const result = creator
|
|
312
|
+
.token('Test Token', 'TEST', 2, 'https://test.com', 'hash123')
|
|
313
|
+
.populate()
|
|
314
|
+
.sign()
|
|
315
|
+
|
|
316
|
+
expect(result).toBe(creator)
|
|
317
|
+
expect(creator.builder).toHaveLength(3)
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
test('should handle transaction parsing and signing', () => {
|
|
321
|
+
const hexTx = 'deadbeef'
|
|
322
|
+
|
|
323
|
+
const result = creator
|
|
324
|
+
.parseTxHex(hexTx)
|
|
325
|
+
.sign()
|
|
326
|
+
|
|
327
|
+
expect(result).toBe(creator)
|
|
328
|
+
expect(creator.builder).toHaveLength(2)
|
|
329
|
+
})
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
describe('error handling', () => {
|
|
333
|
+
test('should handle async errors in builder functions', async () => {
|
|
334
|
+
const errorFunction = vi.fn().mockRejectedValue(new Error('Test error'))
|
|
335
|
+
creator.builder = [errorFunction]
|
|
336
|
+
|
|
337
|
+
await expect(creator.build()).rejects.toThrow('Test error')
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
test('should handle validation errors during operations', () => {
|
|
341
|
+
const invalidCreator = new WalletTransactionCreator(mockAccount)
|
|
342
|
+
invalidCreator['_account'] = null as any
|
|
343
|
+
|
|
344
|
+
expect(() => {
|
|
345
|
+
invalidCreator.mint('token', '1000')
|
|
346
|
+
}).not.toThrow() // Error should be thrown when builder executes, not when adding to builder
|
|
347
|
+
})
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
describe('network handling', () => {
|
|
351
|
+
test('should set network correctly', () => {
|
|
352
|
+
const result = creator.onNetwork('testnet')
|
|
353
|
+
|
|
354
|
+
expect(result).toBe(creator)
|
|
355
|
+
expect(creator.network).toBe(Networks.testnet)
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
test('should default to mainnet', () => {
|
|
359
|
+
expect(creator.network).toBe(Networks.mainnet)
|
|
360
|
+
})
|
|
361
|
+
})
|
|
362
|
+
})
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, vi } from 'vitest'
|
|
2
|
+
import { TransactionBuilder, Networks } from 'libnexa-ts'
|
|
3
|
+
import WatchOnlyTransactionCreator from '../../../src/wallet/transactions/WatchOnlyTransactionCreator'
|
|
4
|
+
import { WatchOnlyAddress } from '../../../src/models/wallet.entities'
|
|
5
|
+
|
|
6
|
+
// Mock the WatchOnlyTXUtils functions
|
|
7
|
+
vi.mock('../../../src/utils/WatchOnlyTXUtils', () => ({
|
|
8
|
+
watchOnlyPopulateTokenAuth: vi.fn().mockResolvedValue(['address1']),
|
|
9
|
+
watchOnlyBuildCreateGroupTransaction: vi.fn().mockResolvedValue(['address2']),
|
|
10
|
+
watchOnlyPopulateAndDuplicateTokenAuths: vi.fn().mockResolvedValue(['address3']),
|
|
11
|
+
watchOnlyPrepareDeleteTransaction: vi.fn().mockResolvedValue(['address4']),
|
|
12
|
+
watchOnlyPopulateTokenInputsAndChange: vi.fn().mockResolvedValue(['address5']),
|
|
13
|
+
watchOnlyPopulateNexaInputsAndChange: vi.fn().mockResolvedValue(['address6'])
|
|
14
|
+
}))
|
|
15
|
+
|
|
16
|
+
describe('WatchOnlyTransactionCreator', () => {
|
|
17
|
+
let creator: WatchOnlyTransactionCreator
|
|
18
|
+
let mockAddresses: WatchOnlyAddress[]
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
mockAddresses = [
|
|
22
|
+
{ address: 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' },
|
|
23
|
+
{ address: 'nexatest:nqtsq5g5dsgh6mwjchqypn8hvdrjue0xpmz293fl7rm926xv' }
|
|
24
|
+
]
|
|
25
|
+
creator = new WatchOnlyTransactionCreator()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('constructor', () => {
|
|
29
|
+
test('should create instance without transaction builder', () => {
|
|
30
|
+
const creator = new WatchOnlyTransactionCreator()
|
|
31
|
+
expect(creator).toBeInstanceOf(WatchOnlyTransactionCreator)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('should create instance with transaction builder', () => {
|
|
35
|
+
const txBuilder = new TransactionBuilder()
|
|
36
|
+
const creator = new WatchOnlyTransactionCreator(txBuilder)
|
|
37
|
+
expect(creator).toBeInstanceOf(WatchOnlyTransactionCreator)
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe('parseTxBuffer', () => {
|
|
42
|
+
test('should not throw error and return this for chaining', () => {
|
|
43
|
+
const buffer = Buffer.from('test')
|
|
44
|
+
const result = creator.parseTxBuffer(buffer)
|
|
45
|
+
expect(result).toBe(creator)
|
|
46
|
+
expect(creator.builder).toHaveLength(1)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('parseTxHex', () => {
|
|
51
|
+
test('should not throw error and return this for chaining', () => {
|
|
52
|
+
const hex = 'deadbeef'
|
|
53
|
+
const result = creator.parseTxHex(hex)
|
|
54
|
+
expect(result).toBe(creator)
|
|
55
|
+
expect(creator.builder).toHaveLength(1)
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
describe('from', () => {
|
|
60
|
+
test('should accept single address string', () => {
|
|
61
|
+
const address = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
62
|
+
const result = creator.onNetwork('testnet').from(address)
|
|
63
|
+
|
|
64
|
+
expect(result).toBe(creator) // Should return this for chaining
|
|
65
|
+
expect(creator['_availableAddresses']).toHaveLength(1)
|
|
66
|
+
expect(creator['_availableAddresses'][0].address).toBe(address)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('should accept array of address strings', () => {
|
|
70
|
+
const addresses = [
|
|
71
|
+
'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc',
|
|
72
|
+
'nexatest:nqtsq5g5dsgh6mwjchqypn8hvdrjue0xpmz293fl7rm926xv'
|
|
73
|
+
]
|
|
74
|
+
const result = creator.onNetwork('testnet').from(addresses)
|
|
75
|
+
|
|
76
|
+
expect(result).toBe(creator)
|
|
77
|
+
expect(creator['_availableAddresses']).toHaveLength(2)
|
|
78
|
+
expect(creator['_availableAddresses'][0].address).toBe(addresses[0])
|
|
79
|
+
expect(creator['_availableAddresses'][1].address).toBe(addresses[1])
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('should accept array of WatchOnlyAddress objects', () => {
|
|
83
|
+
const result = creator.from(mockAddresses)
|
|
84
|
+
|
|
85
|
+
expect(result).toBe(creator)
|
|
86
|
+
expect(creator['_availableAddresses']).toHaveLength(2)
|
|
87
|
+
expect(creator['_availableAddresses'][0]).toEqual(mockAddresses[0])
|
|
88
|
+
expect(creator['_availableAddresses'][1]).toEqual(mockAddresses[1])
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('should accept single WatchOnlyAddress object', () => {
|
|
92
|
+
const address = mockAddresses[0]
|
|
93
|
+
const result = creator.from(address)
|
|
94
|
+
|
|
95
|
+
expect(result).toBe(creator)
|
|
96
|
+
expect(creator['_availableAddresses']).toHaveLength(1)
|
|
97
|
+
expect(creator['_availableAddresses'][0]).toEqual(address)
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
describe('mint', () => {
|
|
102
|
+
test('should add mint operation to builder', () => {
|
|
103
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
104
|
+
const amount = '1000'
|
|
105
|
+
const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
106
|
+
|
|
107
|
+
const result = creator.mint(token, amount, toAddr)
|
|
108
|
+
|
|
109
|
+
expect(result).toBe(creator)
|
|
110
|
+
expect(creator.builder).toHaveLength(1)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('should be chainable', () => {
|
|
114
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
115
|
+
const amount = '1000'
|
|
116
|
+
const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
117
|
+
|
|
118
|
+
const result = creator
|
|
119
|
+
.mint(token, amount, toAddr)
|
|
120
|
+
.mint(token, amount, toAddr)
|
|
121
|
+
|
|
122
|
+
expect(result).toBe(creator)
|
|
123
|
+
expect(creator.builder).toHaveLength(2)
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
describe('melt', () => {
|
|
128
|
+
test('should add melt operation to builder', () => {
|
|
129
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
130
|
+
const amount = '1000'
|
|
131
|
+
const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
132
|
+
|
|
133
|
+
const result = creator.melt(token, amount, toAddr)
|
|
134
|
+
|
|
135
|
+
expect(result).toBe(creator)
|
|
136
|
+
expect(creator.builder).toHaveLength(1)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test('should be chainable', () => {
|
|
140
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
141
|
+
const amount = '1000'
|
|
142
|
+
const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
143
|
+
|
|
144
|
+
const result = creator
|
|
145
|
+
.melt(token, amount, toAddr)
|
|
146
|
+
.melt(token, amount, toAddr)
|
|
147
|
+
|
|
148
|
+
expect(result).toBe(creator)
|
|
149
|
+
expect(creator.builder).toHaveLength(2)
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
describe('populate', () => {
|
|
154
|
+
test('should add populate operation to builder', () => {
|
|
155
|
+
const result = creator.populate()
|
|
156
|
+
|
|
157
|
+
expect(result).toBe(creator)
|
|
158
|
+
expect(creator.builder).toHaveLength(1)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test('should be chainable', () => {
|
|
162
|
+
const result = creator
|
|
163
|
+
.from(mockAddresses)
|
|
164
|
+
.populate()
|
|
165
|
+
|
|
166
|
+
expect(result).toBe(creator)
|
|
167
|
+
expect(creator.builder).toHaveLength(1)
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
describe('integration tests', () => {
|
|
172
|
+
test('should handle complete transaction flow', () => {
|
|
173
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
174
|
+
const amount = '1000'
|
|
175
|
+
const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
176
|
+
|
|
177
|
+
const result = creator
|
|
178
|
+
.onNetwork('testnet')
|
|
179
|
+
.from(mockAddresses)
|
|
180
|
+
.mint(token, amount, toAddr)
|
|
181
|
+
.melt(token, amount, toAddr)
|
|
182
|
+
.populate()
|
|
183
|
+
|
|
184
|
+
expect(result).toBe(creator)
|
|
185
|
+
expect(creator.builder).toHaveLength(3) // mint, melt, populate
|
|
186
|
+
expect(creator.network).toBe(Networks.testnet)
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
test('should handle token operations and populate', () => {
|
|
190
|
+
const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
191
|
+
const amount = '1000'
|
|
192
|
+
const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
193
|
+
|
|
194
|
+
const result = creator
|
|
195
|
+
.from(mockAddresses)
|
|
196
|
+
.sendTo(toAddr, amount)
|
|
197
|
+
.sendToToken(toAddr, amount, token)
|
|
198
|
+
.populate()
|
|
199
|
+
|
|
200
|
+
expect(result).toBe(creator)
|
|
201
|
+
expect(creator.builder).toHaveLength(3) // sendTo, sendToToken, populate
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
test('should handle token creation', () => {
|
|
205
|
+
const result = creator
|
|
206
|
+
.from(mockAddresses)
|
|
207
|
+
.token('Test Token', 'TEST', 2, 'https://test.com', 'hash')
|
|
208
|
+
.populate()
|
|
209
|
+
|
|
210
|
+
expect(result).toBe(creator)
|
|
211
|
+
expect(creator.builder).toHaveLength(2) // token, populate
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
test('should handle consolidate transaction', () => {
|
|
215
|
+
const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc'
|
|
216
|
+
|
|
217
|
+
const result = creator
|
|
218
|
+
.from(mockAddresses)
|
|
219
|
+
.consolidate(toAddr)
|
|
220
|
+
.populate()
|
|
221
|
+
|
|
222
|
+
expect(result).toBe(creator)
|
|
223
|
+
expect(creator.builder).toHaveLength(2) // consolidate, populate
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
describe('network handling', () => {
|
|
228
|
+
test('should set network correctly', () => {
|
|
229
|
+
const result = creator.onNetwork('testnet')
|
|
230
|
+
|
|
231
|
+
expect(result).toBe(creator)
|
|
232
|
+
expect(creator.network).toBe(Networks.testnet)
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
test('should default to mainnet', () => {
|
|
236
|
+
expect(creator.network).toBe(Networks.mainnet)
|
|
237
|
+
})
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
describe('error handling', () => {
|
|
241
|
+
test('should handle empty addresses array', () => {
|
|
242
|
+
const result = creator.from([])
|
|
243
|
+
|
|
244
|
+
expect(result).toBe(creator)
|
|
245
|
+
expect(creator['_availableAddresses']).toHaveLength(0)
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
test('should handle null/undefined addresses', () => {
|
|
249
|
+
// Test with addresses that don't have the address property
|
|
250
|
+
const invalidAddress = {} as WatchOnlyAddress
|
|
251
|
+
const result = creator.from(invalidAddress)
|
|
252
|
+
|
|
253
|
+
expect(result).toBe(creator)
|
|
254
|
+
// Should not add invalid addresses
|
|
255
|
+
expect(creator['_availableAddresses']).toHaveLength(0)
|
|
256
|
+
})
|
|
257
|
+
})
|
|
258
|
+
})
|