@fedimint/core-web 0.0.4 → 0.0.6

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 (45) hide show
  1. package/README.md +4 -4
  2. package/dist/FedimintWallet.d.ts +9 -4
  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 +26 -0
  7. package/dist/services/BalanceService.d.ts.map +1 -1
  8. package/dist/services/FederationService.d.ts +0 -1
  9. package/dist/services/FederationService.d.ts.map +1 -1
  10. package/dist/services/LightningService.d.ts +6 -5
  11. package/dist/services/LightningService.d.ts.map +1 -1
  12. package/dist/services/MintService.d.ts +3 -3
  13. package/dist/services/MintService.d.ts.map +1 -1
  14. package/dist/types/wallet.d.ts +24 -11
  15. package/dist/types/wallet.d.ts.map +1 -1
  16. package/dist/utils/logger.d.ts +17 -0
  17. package/dist/utils/logger.d.ts.map +1 -0
  18. package/dist/worker/WorkerClient.d.ts +3 -0
  19. package/dist/worker/WorkerClient.d.ts.map +1 -1
  20. package/dist/worker.js +1 -1
  21. package/dist/worker.js.map +1 -1
  22. package/package.json +4 -6
  23. package/src/FedimintWallet.test.ts +12 -9
  24. package/src/FedimintWallet.ts +35 -22
  25. package/src/services/BalanceService.test.ts +50 -0
  26. package/src/services/BalanceService.ts +26 -0
  27. package/src/services/FederationService.test.ts +58 -0
  28. package/src/services/FederationService.ts +0 -10
  29. package/src/services/LightningService.test.ts +168 -0
  30. package/src/services/LightningService.ts +21 -5
  31. package/src/services/MintService.test.ts +19 -0
  32. package/src/services/MintService.ts +38 -18
  33. package/src/test/TestFedimintWallet.ts +17 -0
  34. package/src/test/TestingService.ts +59 -0
  35. package/src/test/setupTests.ts +43 -0
  36. package/src/types/wallet.ts +32 -13
  37. package/src/utils/logger.ts +61 -0
  38. package/src/worker/WorkerClient.ts +41 -2
  39. package/src/worker/worker.js +67 -56
  40. package/src/worker/worker.test.ts +90 -0
  41. package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm.d.ts +0 -49
  42. package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm.js +0 -4
  43. package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm_bg.js +0 -1411
  44. package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm_bg.wasm +0 -0
  45. package/node_modules/@fedimint/fedimint-client-wasm/package.json +0 -23
@@ -6,11 +6,12 @@ import {
6
6
  FederationService,
7
7
  RecoveryService,
8
8
  } from './services'
9
+ import { logger, type LogLevel } from './utils/logger'
9
10
 
10
11
  const DEFAULT_CLIENT_NAME = 'fm-default' as const
11
12
 
12
13
  export class FedimintWallet {
13
- private client: WorkerClient
14
+ private _client: WorkerClient
14
15
 
15
16
  public balance: BalanceService
16
17
  public mint: MintService
@@ -18,14 +19,13 @@ export class FedimintWallet {
18
19
  public federation: FederationService
19
20
  public recovery: RecoveryService
20
21
 
21
- private openPromise: Promise<void> | null = null
22
- private resolveOpen: () => void = () => {}
22
+ private _openPromise: Promise<void> | null = null
23
+ private _resolveOpen: () => void = () => {}
23
24
  private _isOpen: boolean = false
24
25
 
25
26
  /**
26
27
  * Creates a new instance of FedimintWallet.
27
28
  *
28
- * @description
29
29
  * This constructor initializes a FedimintWallet instance, which manages communication
30
30
  * with a Web Worker. The Web Worker is responsible for running WebAssembly code that
31
31
  * handles the core Fedimint Client operations.
@@ -53,15 +53,17 @@ export class FedimintWallet {
53
53
  * lazyWallet.open();
54
54
  */
55
55
  constructor(lazy: boolean = false) {
56
- this.openPromise = new Promise((resolve) => {
57
- this.resolveOpen = resolve
56
+ this._openPromise = new Promise((resolve) => {
57
+ this._resolveOpen = resolve
58
58
  })
59
- this.client = new WorkerClient()
60
- this.mint = new MintService(this.client)
61
- this.lightning = new LightningService(this.client)
62
- this.balance = new BalanceService(this.client)
63
- this.federation = new FederationService(this.client)
64
- this.recovery = new RecoveryService(this.client)
59
+ this._client = new WorkerClient()
60
+ this.mint = new MintService(this._client)
61
+ this.lightning = new LightningService(this._client)
62
+ this.balance = new BalanceService(this._client)
63
+ this.federation = new FederationService(this._client)
64
+ this.recovery = new RecoveryService(this._client)
65
+
66
+ logger.info('FedimintWallet instantiated')
65
67
 
66
68
  if (!lazy) {
67
69
  this.initialize()
@@ -69,24 +71,26 @@ export class FedimintWallet {
69
71
  }
70
72
 
71
73
  async initialize() {
72
- await this.client.initialize()
74
+ logger.info('Initializing WorkerClient')
75
+ await this._client.initialize()
76
+ logger.info('WorkerClient initialized')
73
77
  }
74
78
 
75
79
  async waitForOpen() {
76
80
  if (this._isOpen) return Promise.resolve()
77
- return this.openPromise
81
+ return this._openPromise
78
82
  }
79
83
 
80
84
  async open(clientName: string = DEFAULT_CLIENT_NAME) {
81
- await this.client.initialize()
85
+ await this._client.initialize()
82
86
  // TODO: Determine if this should be safe or throw
83
87
  if (this._isOpen) throw new Error('The FedimintWallet is already open.')
84
- const { success } = await this.client.sendSingleMessage('open', {
88
+ const { success } = await this._client.sendSingleMessage('open', {
85
89
  clientName,
86
90
  })
87
91
  if (success) {
88
92
  this._isOpen = !!success
89
- this.resolveOpen()
93
+ this._resolveOpen()
90
94
  }
91
95
  return success
92
96
  }
@@ -95,19 +99,19 @@ export class FedimintWallet {
95
99
  inviteCode: string,
96
100
  clientName: string = DEFAULT_CLIENT_NAME,
97
101
  ) {
98
- await this.client.initialize()
102
+ await this._client.initialize()
99
103
  // TODO: Determine if this should be safe or throw
100
104
  if (this._isOpen)
101
105
  throw new Error(
102
106
  'The FedimintWallet is already open. You can only call `joinFederation` on closed clients.',
103
107
  )
104
- const response = await this.client.sendSingleMessage('join', {
108
+ const response = await this._client.sendSingleMessage('join', {
105
109
  inviteCode,
106
110
  clientName,
107
111
  })
108
112
  if (response.success) {
109
113
  this._isOpen = true
110
- this.resolveOpen()
114
+ this._resolveOpen()
111
115
  }
112
116
  }
113
117
 
@@ -116,12 +120,21 @@ export class FedimintWallet {
116
120
  * After this call, the FedimintWallet instance should be discarded.
117
121
  */
118
122
  async cleanup() {
119
- this.openPromise = null
123
+ this._openPromise = null
120
124
  this._isOpen = false
121
- this.client.cleanup()
125
+ this._client.cleanup()
122
126
  }
123
127
 
124
128
  isOpen() {
125
129
  return this._isOpen
126
130
  }
131
+
132
+ /**
133
+ * Sets the log level for the library.
134
+ * @param level The desired log level ('DEBUG', 'INFO', 'WARN', 'ERROR', 'NONE').
135
+ */
136
+ setLogLevel(level: LogLevel) {
137
+ logger.setLevel(level)
138
+ logger.info(`Log level set to ${level}.`)
139
+ }
127
140
  }
@@ -0,0 +1,50 @@
1
+ import { test, expect } from 'vitest'
2
+ import { TestFedimintWallet } from '../test/TestFedimintWallet'
3
+ import { beforeAll } from 'vitest'
4
+
5
+ let randomTestingId: string
6
+ let wallet: TestFedimintWallet
7
+
8
+ beforeAll(async () => {
9
+ randomTestingId = Math.random().toString(36).substring(2, 15)
10
+ wallet = new TestFedimintWallet()
11
+ expect(wallet).toBeDefined()
12
+ await expect(
13
+ wallet.joinFederation(wallet.testing.TESTING_INVITE, randomTestingId),
14
+ ).resolves.toBeUndefined()
15
+ expect(wallet.isOpen()).toBe(true)
16
+
17
+ // Cleanup after all tests
18
+ return async () => {
19
+ // clear up browser resources
20
+ await wallet.cleanup()
21
+ // remove the wallet db
22
+ indexedDB.deleteDatabase(randomTestingId)
23
+ // swap out the randomTestingId for a new one, to avoid raciness
24
+ randomTestingId = Math.random().toString(36).substring(2, 15)
25
+ }
26
+ })
27
+
28
+ test('getBalance should be initially zero', async () => {
29
+ expect(wallet).toBeDefined()
30
+ expect(wallet.isOpen()).toBe(true)
31
+ const beforeGetBalance = wallet.testing.getRequestCounter()
32
+ await expect(wallet.balance.getBalance()).resolves.toEqual(0)
33
+ expect(wallet.testing.getRequestCounter()).toBe(beforeGetBalance + 1)
34
+ })
35
+
36
+ test('subscribe balance', async () => {
37
+ expect(wallet).toBeDefined()
38
+ expect(wallet.isOpen()).toBe(true)
39
+
40
+ const counterBefore = wallet.testing.getRequestCounter()
41
+ const callbacksBefore = wallet.testing.getRequestCallbackMap().size
42
+ const unsubscribe = await wallet.balance.subscribeBalance((balance) => {
43
+ expect(balance).toEqual(0)
44
+ })
45
+ expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
46
+ expect(wallet.testing.getRequestCallbackMap().size).toBe(callbacksBefore + 1)
47
+
48
+ await expect(wallet.balance.getBalance()).resolves.toEqual(0)
49
+ expect(unsubscribe()).toBeUndefined()
50
+ })
@@ -1,12 +1,38 @@
1
1
  import { WorkerClient } from '../worker'
2
2
 
3
+ /**
4
+ * Balance Service
5
+ *
6
+ * The Balance Service provides methods to interact with the balance of a Fedimint wallet.
7
+ */
3
8
  export class BalanceService {
4
9
  constructor(private client: WorkerClient) {}
5
10
 
11
+ /**
12
+ * Get the balance of the current wallet
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const balance = await wallet.balance.getBalance()
17
+ * ```
18
+ */
6
19
  async getBalance(): Promise<number> {
7
20
  return await this.client.rpcSingle('', 'get_balance', {})
8
21
  }
9
22
 
23
+ /**
24
+ * Subscribe to the balance of the current wallet
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const unsubscribe = wallet.balance.subscribeBalance((balance) => {
29
+ * console.log(balance)
30
+ * })
31
+ *
32
+ * // ...Cleanup Later
33
+ * unsubscribe()
34
+ * ```
35
+ */
10
36
  subscribeBalance(
11
37
  onSuccess: (balance: number) => void = () => {},
12
38
  onError: (error: string) => void = () => {},
@@ -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
+ )
@@ -16,16 +16,6 @@ export class FederationService {
16
16
  return await this.client.rpcSingle('', 'get_invite_code', { peer })
17
17
  }
18
18
 
19
- async joinFederation(inviteCode: string, clientName: string): Promise<void> {
20
- const response = await this.client.sendSingleMessage('join', {
21
- inviteCode,
22
- clientName,
23
- })
24
- if (!response.success) {
25
- throw new Error('Failed to join federation')
26
- }
27
- }
28
-
29
19
  async listOperations(): Promise<JSONValue[]> {
30
20
  return await this.client.rpcSingle('', 'list_operations', {})
31
21
  }
@@ -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
+ )
@@ -13,7 +13,7 @@ import {
13
13
  export class LightningService {
14
14
  constructor(private client: WorkerClient) {}
15
15
 
16
- async createBolt11InvoiceWithGateway(
16
+ async createInvoiceWithGateway(
17
17
  amount: number,
18
18
  description: string,
19
19
  expiryTime: number | null = null,
@@ -29,7 +29,7 @@ export class LightningService {
29
29
  })
30
30
  }
31
31
 
32
- async createBolt11Invoice(
32
+ async createInvoice(
33
33
  amount: number,
34
34
  description: string,
35
35
  expiryTime: number | null = null,
@@ -46,7 +46,7 @@ export class LightningService {
46
46
  })
47
47
  }
48
48
 
49
- async payBolt11InvoiceWithGateway(
49
+ async payInvoiceWithGateway(
50
50
  invoice: string,
51
51
  gatewayInfo: GatewayInfo,
52
52
  extraMeta: JSONObject = {},
@@ -58,12 +58,12 @@ export class LightningService {
58
58
  })
59
59
  }
60
60
 
61
- async _getDefaultGatewayInfo(): Promise<LightningGateway> {
61
+ private async _getDefaultGatewayInfo(): Promise<LightningGateway> {
62
62
  const gateways = await this.listGateways()
63
63
  return gateways[0]
64
64
  }
65
65
 
66
- async payBolt11Invoice(
66
+ async payInvoice(
67
67
  invoice: string,
68
68
  extraMeta: JSONObject = {},
69
69
  ): Promise<OutgoingLightningPayment> {
@@ -108,6 +108,22 @@ export class LightningService {
108
108
  return unsubscribe
109
109
  }
110
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
+
111
127
  async getGateway(
112
128
  gatewayId: string | null = null,
113
129
  forceInternal: boolean = false,
@@ -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
+ )
@@ -1,5 +1,11 @@
1
1
  import { WorkerClient } from '../worker'
2
- import { JSONObject, JSONValue } from '../types/wallet'
2
+ import {
3
+ Duration,
4
+ JSONObject,
5
+ JSONValue,
6
+ MintSpendNotesResponse,
7
+ ReissueExternalNotesState,
8
+ } from '../types/wallet'
3
9
 
4
10
  export class MintService {
5
11
  constructor(private client: WorkerClient) {}
@@ -13,7 +19,7 @@ export class MintService {
13
19
 
14
20
  async reissueExternalNotes(
15
21
  oobNotes: string,
16
- extraMeta: JSONObject,
22
+ extraMeta: JSONObject = {},
17
23
  ): Promise<string> {
18
24
  return await this.client.rpcSingle('mint', 'reissue_external_notes', {
19
25
  oob_notes: oobNotes,
@@ -26,12 +32,6 @@ export class MintService {
26
32
  onSuccess: (state: JSONValue) => void = () => {},
27
33
  onError: (error: string) => void = () => {},
28
34
  ) {
29
- type ReissueExternalNotesState =
30
- | 'Created'
31
- | 'Issuing'
32
- | 'Done'
33
- | { Failed: { error: string } }
34
-
35
35
  const unsubscribe = this.client.rpcStream<ReissueExternalNotesState>(
36
36
  'mint',
37
37
  'subscribe_reissue_external_notes',
@@ -45,16 +45,36 @@ export class MintService {
45
45
 
46
46
  async spendNotes(
47
47
  minAmount: number,
48
- tryCancelAfter: number,
49
- includeInvite: boolean,
50
- extraMeta: JSONValue,
51
- ): Promise<JSONValue> {
52
- return await this.client.rpcSingle('mint', 'spend_notes', {
53
- min_amount: minAmount,
54
- try_cancel_after: tryCancelAfter,
55
- include_invite: includeInvite,
56
- extra_meta: extraMeta,
57
- })
48
+ // Tells the wallet to automatically try to cancel the spend if it hasn't completed
49
+ // after the specified number of milliseconds.
50
+ // If the receiver has already redeemed the notes at this time,
51
+ // the notes will not be cancelled
52
+ tryCancelAfter: number | Duration = 0,
53
+ includeInvite: boolean = false,
54
+ extraMeta: JSONValue = {},
55
+ ): Promise<MintSpendNotesResponse> {
56
+ const duration =
57
+ typeof tryCancelAfter === 'number'
58
+ ? { nanos: 0, secs: tryCancelAfter }
59
+ : tryCancelAfter
60
+
61
+ const res = await this.client.rpcSingle<Array<string>>(
62
+ 'mint',
63
+ 'spend_notes',
64
+ {
65
+ min_amount: minAmount,
66
+ try_cancel_after: duration,
67
+ include_invite: includeInvite,
68
+ extra_meta: extraMeta,
69
+ },
70
+ )
71
+ const notes = res[1]
72
+ const operationId = res[0]
73
+
74
+ return {
75
+ notes,
76
+ operation_id: operationId,
77
+ }
58
78
  }
59
79
 
60
80
  async validateNotes(oobNotes: string): Promise<number> {
@@ -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
+ }