@fedimint/core-web 0.0.3 → 0.0.5

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.
Files changed (61) hide show
  1. package/README.md +4 -4
  2. package/dist/FedimintWallet.d.ts +42 -65
  3. package/dist/FedimintWallet.d.ts.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/services/BalanceService.d.ts +34 -0
  7. package/dist/services/BalanceService.d.ts.map +1 -0
  8. package/dist/services/FederationService.d.ts +11 -0
  9. package/dist/services/FederationService.d.ts.map +1 -0
  10. package/dist/services/LightningService.d.ts +18 -0
  11. package/dist/services/LightningService.d.ts.map +1 -0
  12. package/dist/services/MintService.d.ts +15 -0
  13. package/dist/services/MintService.d.ts.map +1 -0
  14. package/dist/services/RecoveryService.d.ts +13 -0
  15. package/dist/services/RecoveryService.d.ts.map +1 -0
  16. package/dist/services/index.d.ts +6 -0
  17. package/dist/services/index.d.ts.map +1 -0
  18. package/dist/types/wallet.d.ts +16 -11
  19. package/dist/types/wallet.d.ts.map +1 -1
  20. package/dist/utils/logger.d.ts +17 -0
  21. package/dist/utils/logger.d.ts.map +1 -0
  22. package/dist/worker/WorkerClient.d.ts +44 -0
  23. package/dist/worker/WorkerClient.d.ts.map +1 -0
  24. package/dist/worker/index.d.ts +2 -0
  25. package/dist/worker/index.d.ts.map +1 -0
  26. package/dist/worker.js +1 -1
  27. package/dist/worker.js.map +1 -1
  28. package/package.json +9 -9
  29. package/src/FedimintWallet.test.ts +77 -0
  30. package/src/FedimintWallet.ts +91 -466
  31. package/src/services/BalanceService.test.ts +50 -0
  32. package/src/services/BalanceService.ts +50 -0
  33. package/src/services/FederationService.test.ts +58 -0
  34. package/src/services/FederationService.ts +22 -0
  35. package/src/services/LightningService.test.ts +168 -0
  36. package/src/services/LightningService.ts +144 -0
  37. package/src/services/MintService.test.ts +19 -0
  38. package/src/services/MintService.ts +96 -0
  39. package/src/services/RecoveryService.ts +26 -0
  40. package/src/services/index.ts +5 -0
  41. package/src/test/TestFedimintWallet.ts +17 -0
  42. package/src/test/TestingService.ts +59 -0
  43. package/src/test/setupTests.ts +43 -0
  44. package/src/types/wallet.ts +20 -13
  45. package/src/utils/logger.ts +61 -0
  46. package/src/worker/WorkerClient.ts +229 -0
  47. package/src/worker/index.ts +1 -0
  48. package/src/worker/worker.js +96 -0
  49. package/src/worker/worker.test.ts +90 -0
  50. package/node_modules/fedimint-client-wasm/fedimint_client_wasm.d.ts +0 -49
  51. package/node_modules/fedimint-client-wasm/fedimint_client_wasm.js +0 -4
  52. package/node_modules/fedimint-client-wasm/fedimint_client_wasm_bg.js +0 -1411
  53. package/node_modules/fedimint-client-wasm/fedimint_client_wasm_bg.wasm +0 -0
  54. package/node_modules/fedimint-client-wasm/package.json +0 -26
  55. package/src/worker.js +0 -80
  56. package/wasm/fedimint_client_wasm.d.ts +0 -49
  57. package/wasm/fedimint_client_wasm.js +0 -4
  58. package/wasm/fedimint_client_wasm_bg.js +0 -1411
  59. package/wasm/fedimint_client_wasm_bg.wasm +0 -0
  60. package/wasm/fedimint_client_wasm_bg.wasm.d.ts +0 -110
  61. package/wasm/package.json +0 -26
@@ -0,0 +1,58 @@
1
+ import { expect } from 'vitest'
2
+ import { walletTest } from '../test/setupTests'
3
+
4
+ walletTest(
5
+ 'getConfig should return the federation config',
6
+ async ({ wallet }) => {
7
+ expect(wallet).toBeDefined()
8
+ expect(wallet.isOpen()).toBe(true)
9
+ const counterBefore = wallet.testing.getRequestCounter()
10
+ await expect(wallet.federation.getConfig()).resolves.toMatchObject({
11
+ api_endpoints: expect.any(Object),
12
+ broadcast_public_keys: expect.any(Object),
13
+ consensus_version: expect.any(Object),
14
+ meta: expect.any(Object),
15
+ modules: expect.any(Object),
16
+ })
17
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
18
+ },
19
+ )
20
+
21
+ walletTest(
22
+ 'getFederationId should return the federation id',
23
+ async ({ wallet }) => {
24
+ expect(wallet).toBeDefined()
25
+ expect(wallet.isOpen()).toBe(true)
26
+
27
+ const counterBefore = wallet.testing.getRequestCounter()
28
+ const federationId = await wallet.federation.getFederationId()
29
+ expect(federationId).toBeTypeOf('string')
30
+ expect(federationId).toHaveLength(64)
31
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
32
+ },
33
+ )
34
+
35
+ walletTest(
36
+ 'getInviteCode should return the invite code',
37
+ async ({ wallet }) => {
38
+ expect(wallet).toBeDefined()
39
+ expect(wallet.isOpen()).toBe(true)
40
+
41
+ const counterBefore = wallet.testing.getRequestCounter()
42
+ const inviteCode = await wallet.federation.getInviteCode(0)
43
+ expect(inviteCode).toBeTypeOf('string')
44
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
45
+ },
46
+ )
47
+
48
+ walletTest(
49
+ 'listOperations should return the list of operations',
50
+ async ({ wallet }) => {
51
+ expect(wallet).toBeDefined()
52
+ expect(wallet.isOpen()).toBe(true)
53
+
54
+ const counterBefore = wallet.testing.getRequestCounter()
55
+ await expect(wallet.federation.listOperations()).resolves.toMatchObject([])
56
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
57
+ },
58
+ )
@@ -0,0 +1,22 @@
1
+ import { JSONValue } from '../types/wallet'
2
+ import { WorkerClient } from '../worker'
3
+
4
+ export class FederationService {
5
+ constructor(private client: WorkerClient) {}
6
+
7
+ async getConfig(): Promise<JSONValue> {
8
+ return await this.client.rpcSingle('', 'get_config', {})
9
+ }
10
+
11
+ async getFederationId(): Promise<string> {
12
+ return await this.client.rpcSingle('', 'get_federation_id', {})
13
+ }
14
+
15
+ async getInviteCode(peer: number): Promise<string | null> {
16
+ return await this.client.rpcSingle('', 'get_invite_code', { peer })
17
+ }
18
+
19
+ async listOperations(): Promise<JSONValue[]> {
20
+ return await this.client.rpcSingle('', 'list_operations', {})
21
+ }
22
+ }
@@ -0,0 +1,168 @@
1
+ import { expect } from 'vitest'
2
+ import { walletTest } from '../test/setupTests'
3
+
4
+ walletTest(
5
+ 'createInvoice should create a bolt11 invoice',
6
+ async ({ wallet }) => {
7
+ expect(wallet).toBeDefined()
8
+ expect(wallet.isOpen()).toBe(true)
9
+
10
+ const counterBefore = wallet.testing.getRequestCounter()
11
+ const invoice = await wallet.lightning.createInvoice(100, 'test')
12
+ expect(invoice).toBeDefined()
13
+ expect(invoice).toMatchObject({
14
+ invoice: expect.any(String),
15
+ operation_id: expect.any(String),
16
+ })
17
+ // 3 requests were made, one for the invoice, one for refreshing the
18
+ // gateway cache, one for getting the gateway info
19
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 3)
20
+
21
+ // Test with expiry time
22
+ await expect(
23
+ wallet.lightning.createInvoice(100, 'test', 1000, {}),
24
+ ).resolves.toBeDefined()
25
+ },
26
+ )
27
+
28
+ walletTest(
29
+ 'listGateways should return a list of gateways',
30
+ async ({ wallet }) => {
31
+ expect(wallet).toBeDefined()
32
+ expect(wallet.isOpen()).toBe(true)
33
+
34
+ const counterBefore = wallet.testing.getRequestCounter()
35
+ const gateways = await wallet.lightning.listGateways()
36
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
37
+ expect(gateways).toBeDefined()
38
+ expect(gateways).toMatchObject([
39
+ {
40
+ info: expect.any(Object),
41
+ },
42
+ ])
43
+ },
44
+ )
45
+
46
+ walletTest(
47
+ 'updateGatewayCache should update the gateway cache',
48
+ async ({ wallet }) => {
49
+ expect(wallet).toBeDefined()
50
+ expect(wallet.isOpen()).toBe(true)
51
+
52
+ const counterBefore = wallet.testing.getRequestCounter()
53
+ await expect(wallet.lightning.updateGatewayCache()).resolves.toBeDefined()
54
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
55
+ },
56
+ )
57
+
58
+ walletTest('getGateway should return a gateway', async ({ wallet }) => {
59
+ expect(wallet).toBeDefined()
60
+ expect(wallet.isOpen()).toBe(true)
61
+
62
+ const counterBefore = wallet.testing.getRequestCounter()
63
+ const gateway = await wallet.lightning.getGateway()
64
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
65
+ expect(gateway).toMatchObject({
66
+ api: expect.any(String),
67
+ fees: expect.any(Object),
68
+ gateway_id: expect.any(String),
69
+ gateway_redeem_key: expect.any(String),
70
+ lightning_alias: expect.any(String),
71
+ mint_channel_id: expect.any(Number),
72
+ node_pub_key: expect.any(String),
73
+ route_hints: expect.any(Array),
74
+ })
75
+ })
76
+
77
+ walletTest(
78
+ 'createInvoiceWithGateway should create a bolt11 invoice with a gateway',
79
+ async ({ wallet }) => {
80
+ expect(wallet).toBeDefined()
81
+ expect(wallet.isOpen()).toBe(true)
82
+
83
+ const gateways = await wallet.lightning.listGateways()
84
+ const gateway = gateways[0]
85
+ expect(gateway).toBeDefined()
86
+
87
+ const counterBefore = wallet.testing.getRequestCounter()
88
+ const invoice = await wallet.lightning.createInvoiceWithGateway(
89
+ 100,
90
+ 'test',
91
+ null,
92
+ {},
93
+ gateway.info,
94
+ )
95
+ expect(invoice).toBeDefined()
96
+ expect(invoice).toMatchObject({
97
+ invoice: expect.any(String),
98
+ operation_id: expect.any(String),
99
+ })
100
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
101
+ await expect(
102
+ wallet.lightning.createInvoiceWithGateway(
103
+ 100,
104
+ 'test',
105
+ 1000,
106
+ {},
107
+ gateway.info,
108
+ ),
109
+ ).resolves.toBeDefined()
110
+ },
111
+ )
112
+
113
+ walletTest(
114
+ 'payInvoice should throw on insufficient funds',
115
+ async ({ wallet }) => {
116
+ expect(wallet).toBeDefined()
117
+ expect(wallet.isOpen()).toBe(true)
118
+
119
+ const invoice = await wallet.lightning.createInvoice(100, 'test')
120
+ expect(invoice).toBeDefined()
121
+ expect(invoice).toMatchObject({
122
+ invoice: expect.any(String),
123
+ operation_id: expect.any(String),
124
+ })
125
+
126
+ const counterBefore = wallet.testing.getRequestCounter()
127
+ // Insufficient funds
128
+ try {
129
+ await wallet.lightning.payInvoice(invoice.invoice, {})
130
+ expect.unreachable('Should throw error')
131
+ } catch (error) {
132
+ expect(error).toBeDefined()
133
+ }
134
+ // 3 requests were made, one for paying the invoice, one for refreshing the
135
+ // gateway cache, one for getting the gateway info
136
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 3)
137
+ },
138
+ )
139
+
140
+ walletTest(
141
+ 'payInvoice should pay a bolt11 invoice',
142
+ { timeout: 45000 },
143
+ async ({ wallet }) => {
144
+ expect(wallet).toBeDefined()
145
+ expect(wallet.isOpen()).toBe(true)
146
+
147
+ const gateways = await wallet.lightning.listGateways()
148
+ const gateway = gateways[0]
149
+ if (!gateway) {
150
+ expect.unreachable('Gateway not found')
151
+ }
152
+ const invoice = await wallet.lightning.createInvoice(10000, 'test')
153
+ await expect(
154
+ wallet.testing.payWithFaucet(invoice.invoice),
155
+ ).resolves.toBeDefined()
156
+ await wallet.lightning.waitForReceive(invoice.operation_id)
157
+ // Wait for balance to fully update
158
+ await new Promise((resolve) => setTimeout(resolve, 1000))
159
+ const externalInvoice = await wallet.testing.getExternalInvoice(10)
160
+ const payment = await wallet.lightning.payInvoice(externalInvoice.pr)
161
+ expect(payment).toBeDefined()
162
+ expect(payment).toMatchObject({
163
+ contract_id: expect.any(String),
164
+ fee: expect.any(Number),
165
+ payment_type: expect.any(Object),
166
+ })
167
+ },
168
+ )
@@ -0,0 +1,144 @@
1
+ import { WorkerClient } from '../worker'
2
+ import {
3
+ CreateBolt11Response,
4
+ GatewayInfo,
5
+ JSONObject,
6
+ JSONValue,
7
+ LightningGateway,
8
+ LnPayState,
9
+ LnReceiveState,
10
+ OutgoingLightningPayment,
11
+ } from '../types/wallet'
12
+
13
+ export class LightningService {
14
+ constructor(private client: WorkerClient) {}
15
+
16
+ async createInvoiceWithGateway(
17
+ amount: number,
18
+ description: string,
19
+ expiryTime: number | null = null,
20
+ extraMeta: JSONObject = {},
21
+ gatewayInfo: GatewayInfo,
22
+ ) {
23
+ return await this.client.rpcSingle('ln', 'create_bolt11_invoice', {
24
+ amount,
25
+ description,
26
+ expiry_time: expiryTime,
27
+ extra_meta: extraMeta,
28
+ gateway: gatewayInfo,
29
+ })
30
+ }
31
+
32
+ async createInvoice(
33
+ amount: number,
34
+ description: string,
35
+ expiryTime: number | null = null,
36
+ extraMeta: JSONObject = {},
37
+ ): Promise<CreateBolt11Response> {
38
+ await this.updateGatewayCache()
39
+ const gateway = await this._getDefaultGatewayInfo()
40
+ return await this.client.rpcSingle('ln', 'create_bolt11_invoice', {
41
+ amount,
42
+ description,
43
+ expiry_time: expiryTime,
44
+ extra_meta: extraMeta,
45
+ gateway: gateway.info,
46
+ })
47
+ }
48
+
49
+ async payInvoiceWithGateway(
50
+ invoice: string,
51
+ gatewayInfo: GatewayInfo,
52
+ extraMeta: JSONObject = {},
53
+ ) {
54
+ return await this.client.rpcSingle('ln', 'pay_bolt11_invoice', {
55
+ maybe_gateway: gatewayInfo,
56
+ invoice,
57
+ extra_meta: extraMeta,
58
+ })
59
+ }
60
+
61
+ private async _getDefaultGatewayInfo(): Promise<LightningGateway> {
62
+ const gateways = await this.listGateways()
63
+ return gateways[0]
64
+ }
65
+
66
+ async payInvoice(
67
+ invoice: string,
68
+ extraMeta: JSONObject = {},
69
+ ): Promise<OutgoingLightningPayment> {
70
+ await this.updateGatewayCache()
71
+ const gateway = await this._getDefaultGatewayInfo()
72
+ return await this.client.rpcSingle('ln', 'pay_bolt11_invoice', {
73
+ maybe_gateway: gateway.info,
74
+ invoice,
75
+ extra_meta: extraMeta,
76
+ })
77
+ }
78
+
79
+ subscribeLnPay(
80
+ operationId: string,
81
+ onSuccess: (state: LnPayState) => void = () => {},
82
+ onError: (error: string) => void = () => {},
83
+ ) {
84
+ const unsubscribe = this.client.rpcStream(
85
+ 'ln',
86
+ 'subscribe_ln_pay',
87
+ { operation_id: operationId },
88
+ onSuccess,
89
+ onError,
90
+ )
91
+
92
+ return unsubscribe
93
+ }
94
+
95
+ subscribeLnReceive(
96
+ operationId: string,
97
+ onSuccess: (state: LnReceiveState) => void = () => {},
98
+ onError: (error: string) => void = () => {},
99
+ ) {
100
+ const unsubscribe = this.client.rpcStream(
101
+ 'ln',
102
+ 'subscribe_ln_receive',
103
+ { operation_id: operationId },
104
+ onSuccess,
105
+ onError,
106
+ )
107
+
108
+ return unsubscribe
109
+ }
110
+
111
+ async waitForReceive(operationId: string): Promise<LnReceiveState> {
112
+ return new Promise((resolve, reject) => {
113
+ const unsubscribe = this.subscribeLnReceive(
114
+ operationId,
115
+ (res) => {
116
+ if (res === 'claimed') resolve(res)
117
+ },
118
+ reject,
119
+ )
120
+ setTimeout(() => {
121
+ unsubscribe()
122
+ reject(new Error('Timeout waiting for receive'))
123
+ }, 10000)
124
+ })
125
+ }
126
+
127
+ async getGateway(
128
+ gatewayId: string | null = null,
129
+ forceInternal: boolean = false,
130
+ ): Promise<LightningGateway | null> {
131
+ return await this.client.rpcSingle('ln', 'get_gateway', {
132
+ gateway_id: gatewayId,
133
+ force_internal: forceInternal,
134
+ })
135
+ }
136
+
137
+ async listGateways(): Promise<LightningGateway[]> {
138
+ return await this.client.rpcSingle('ln', 'list_gateways', {})
139
+ }
140
+
141
+ async updateGatewayCache(): Promise<JSONValue> {
142
+ return await this.client.rpcSingle('ln', 'update_gateway_cache', {})
143
+ }
144
+ }
@@ -0,0 +1,19 @@
1
+ import { expect } from 'vitest'
2
+ import { walletTest } from '../test/setupTests'
3
+
4
+ walletTest('redeemEcash should error on invalid ecash', async ({ wallet }) => {
5
+ expect(wallet).toBeDefined()
6
+ expect(wallet.isOpen()).toBe(true)
7
+
8
+ await expect(wallet.mint.redeemEcash('test')).rejects.toThrow()
9
+ })
10
+
11
+ walletTest(
12
+ 'reissueExternalNotes should reissue external notes',
13
+ async ({ wallet }) => {
14
+ expect(wallet).toBeDefined()
15
+ expect(wallet.isOpen()).toBe(true)
16
+
17
+ await expect(wallet.mint.reissueExternalNotes('test')).rejects.toThrow()
18
+ },
19
+ )
@@ -0,0 +1,96 @@
1
+ import { WorkerClient } from '../worker'
2
+ import {
3
+ JSONObject,
4
+ JSONValue,
5
+ ReissueExternalNotesState,
6
+ } from '../types/wallet'
7
+
8
+ export class MintService {
9
+ constructor(private client: WorkerClient) {}
10
+
11
+ async redeemEcash(notes: string): Promise<void> {
12
+ await this.client.rpcSingle('mint', 'reissue_external_notes', {
13
+ oob_notes: notes, // "out of band notes"
14
+ extra_meta: null,
15
+ })
16
+ }
17
+
18
+ async reissueExternalNotes(
19
+ oobNotes: string,
20
+ extraMeta: JSONObject = {},
21
+ ): Promise<string> {
22
+ return await this.client.rpcSingle('mint', 'reissue_external_notes', {
23
+ oob_notes: oobNotes,
24
+ extra_meta: extraMeta,
25
+ })
26
+ }
27
+
28
+ subscribeReissueExternalNotes(
29
+ operationId: string,
30
+ onSuccess: (state: JSONValue) => void = () => {},
31
+ onError: (error: string) => void = () => {},
32
+ ) {
33
+ const unsubscribe = this.client.rpcStream<ReissueExternalNotesState>(
34
+ 'mint',
35
+ 'subscribe_reissue_external_notes',
36
+ { operation_id: operationId },
37
+ onSuccess,
38
+ onError,
39
+ )
40
+
41
+ return unsubscribe
42
+ }
43
+
44
+ async spendNotes(
45
+ minAmount: number,
46
+ // Tells the wallet to automatically try to cancel the spend if it hasn't completed
47
+ // after the specified number of milliseconds.
48
+ // If the receiver has already redeemed the notes at this time,
49
+ // the notes will not be cancelled
50
+ tryCancelAfter: number = 0,
51
+ includeInvite: boolean = false,
52
+ extraMeta: JSONValue = {},
53
+ ): Promise<JSONValue> {
54
+ console.error('tryCancelAfter', tryCancelAfter)
55
+ return await this.client.rpcSingle('mint', 'spend_notes', {
56
+ min_amount: minAmount,
57
+ try_cancel_after: null,
58
+ include_invite: includeInvite,
59
+ extra_meta: extraMeta,
60
+ })
61
+ }
62
+
63
+ async validateNotes(oobNotes: string): Promise<number> {
64
+ return await this.client.rpcSingle('mint', 'validate_notes', {
65
+ oob_notes: oobNotes,
66
+ })
67
+ }
68
+
69
+ async tryCancelSpendNotes(operationId: string): Promise<void> {
70
+ await this.client.rpcSingle('mint', 'try_cancel_spend_notes', {
71
+ operation_id: operationId,
72
+ })
73
+ }
74
+
75
+ subscribeSpendNotes(
76
+ operationId: string,
77
+ onSuccess: (state: JSONValue) => void = () => {},
78
+ onError: (error: string) => void = () => {},
79
+ ) {
80
+ const unsubscribe = this.client.rpcStream(
81
+ 'mint',
82
+ 'subscribe_spend_notes',
83
+ { operation_id: operationId },
84
+ (res) => onSuccess(res),
85
+ onError,
86
+ )
87
+
88
+ return unsubscribe
89
+ }
90
+
91
+ async awaitSpendOobRefund(operationId: string): Promise<JSONValue> {
92
+ return await this.client.rpcSingle('mint', 'await_spend_oob_refund', {
93
+ operation_id: operationId,
94
+ })
95
+ }
96
+ }
@@ -0,0 +1,26 @@
1
+ import { JSONValue } from '../types/wallet'
2
+ import { WorkerClient } from '../worker'
3
+
4
+ export class RecoveryService {
5
+ constructor(private client: WorkerClient) {}
6
+
7
+ async hasPendingRecoveries(): Promise<boolean> {
8
+ return await this.client.rpcSingle('', 'has_pending_recoveries', {})
9
+ }
10
+
11
+ async waitForAllRecoveries(): Promise<void> {
12
+ await this.client.rpcSingle('', 'wait_for_all_recoveries', {})
13
+ }
14
+
15
+ subscribeToRecoveryProgress(
16
+ onSuccess: (progress: { module_id: number; progress: JSONValue }) => void,
17
+ onError: (error: string) => void,
18
+ ): () => void {
19
+ const unsubscribe = this.client.rpcStream<{
20
+ module_id: number
21
+ progress: JSONValue
22
+ }>('', 'subscribe_to_recovery_progress', {}, onSuccess, onError)
23
+
24
+ return unsubscribe
25
+ }
26
+ }
@@ -0,0 +1,5 @@
1
+ export { MintService } from './MintService'
2
+ export { BalanceService } from './BalanceService'
3
+ export { LightningService } from './LightningService'
4
+ export { RecoveryService } from './RecoveryService'
5
+ export { FederationService } from './FederationService'
@@ -0,0 +1,17 @@
1
+ import { FedimintWallet } from '../FedimintWallet'
2
+ import { WorkerClient } from '../worker/WorkerClient'
3
+ import { TestingService } from './TestingService'
4
+
5
+ export class TestFedimintWallet extends FedimintWallet {
6
+ public testing: TestingService
7
+
8
+ constructor() {
9
+ super()
10
+ this.testing = new TestingService(this.getWorkerClient())
11
+ }
12
+
13
+ // Method to expose the WorkerClient
14
+ getWorkerClient(): WorkerClient {
15
+ return this['_client']
16
+ }
17
+ }
@@ -0,0 +1,59 @@
1
+ import { WorkerClient } from '../worker'
2
+
3
+ export const TESTING_INVITE =
4
+ 'fed11qgqrsdnhwden5te0v9cxjtt4dekxzamxw4kz6mmjvvkhydted9ukg6r9xfsnx7th0fhn26tf093juamwv4u8gtnpwpcz7qqpyz0e327ua8geceutfrcaezwt22mk6s2rdy09kg72jrcmncng2gn0kp2m5sk'
5
+
6
+ // This is a testing service that allows for inspecting the internals
7
+ // of the WorkerClient. It is not intended for use in production.
8
+ export class TestingService {
9
+ public TESTING_INVITE: string
10
+ constructor(private client: WorkerClient) {
11
+ // Solo Mint on mutinynet
12
+ this.TESTING_INVITE = TESTING_INVITE
13
+ }
14
+
15
+ getRequestCounter() {
16
+ return this.client._getRequestCounter()
17
+ }
18
+
19
+ getRequestCallbackMap() {
20
+ return this.client._getRequestCallbackMap()
21
+ }
22
+
23
+ async payWithFaucet(invoice: string) {
24
+ try {
25
+ const response = await fetch(
26
+ `https://faucet.mutinynet.com/api/lnurlw/callback?k1=k1&pr=${invoice}`,
27
+ )
28
+
29
+ if (!response.ok) {
30
+ throw new Error(
31
+ `HTTP error! Failed to pay invoice. status: ${response.status}`,
32
+ )
33
+ }
34
+
35
+ return await response.json()
36
+ } catch (error) {
37
+ console.error('Error paying with faucet', error)
38
+ throw error
39
+ }
40
+ }
41
+
42
+ async getExternalInvoice(amount: number) {
43
+ try {
44
+ const response = await fetch(
45
+ `https://lnurl-staging.mutinywallet.com/lnurlp/refund/callback?amount=${amount}`,
46
+ )
47
+ if (!response.ok) {
48
+ throw new Error(
49
+ `HTTP error! Failed to get external invoice. status: ${response.status}`,
50
+ )
51
+ }
52
+
53
+ return await response.json()
54
+ } catch (error) {
55
+ console.error('Error getting external invoice', error)
56
+ throw error
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,43 @@
1
+ import { expect, test } from 'vitest'
2
+ import { TestFedimintWallet } from './TestFedimintWallet'
3
+
4
+ /**
5
+ * Adds Fixtures for setting up and tearing down a test FedimintWallet instance
6
+ */
7
+ export const walletTest = test.extend<{ wallet: TestFedimintWallet }>({
8
+ wallet: async ({}, use) => {
9
+ const randomTestingId = Math.random().toString(36).substring(2, 15)
10
+ const wallet = new TestFedimintWallet()
11
+ expect(wallet).toBeDefined()
12
+
13
+ await expect(
14
+ wallet.joinFederation(wallet.testing.TESTING_INVITE, randomTestingId),
15
+ ).resolves.toBeUndefined()
16
+ await use(wallet)
17
+
18
+ // clear up browser resources
19
+ await wallet.cleanup()
20
+ // remove the wallet db
21
+ indexedDB.deleteDatabase(randomTestingId)
22
+ },
23
+ })
24
+
25
+ /**
26
+ * Adds Fixtures for setting up and tearing down a test Worker instance
27
+ */
28
+ export const workerTest = test.extend<{
29
+ worker: Worker
30
+ clientName: string
31
+ }>({
32
+ worker: async ({}, use) => {
33
+ const worker = new Worker(new URL('../worker/worker.js', import.meta.url), {
34
+ type: 'module',
35
+ })
36
+ await use(worker)
37
+ worker.terminate()
38
+ },
39
+ clientName: async ({}, use) => {
40
+ const randomTestingId = Math.random().toString(36).substring(2, 15)
41
+ await use(randomTestingId)
42
+ },
43
+ })