@fedimint/core-web 0.0.6 → 0.0.8
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/README.md +6 -71
- package/dist/{FedimintWallet.d.ts → dts/FedimintWallet.d.ts} +3 -3
- package/dist/dts/FedimintWallet.d.ts.map +1 -0
- package/dist/dts/index.d.ts +3 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/{services → dts/services}/BalanceService.d.ts +5 -4
- package/dist/dts/services/BalanceService.d.ts.map +1 -0
- package/dist/{services → dts/services}/FederationService.d.ts +1 -1
- package/dist/dts/services/FederationService.d.ts.map +1 -0
- package/dist/dts/services/LightningService.d.ts +21 -0
- package/dist/dts/services/LightningService.d.ts.map +1 -0
- package/dist/{services → dts/services}/MintService.d.ts +6 -5
- package/dist/dts/services/MintService.d.ts.map +1 -0
- package/dist/{services → dts/services}/RecoveryService.d.ts +1 -1
- package/dist/dts/services/RecoveryService.d.ts.map +1 -0
- package/dist/dts/services/index.d.ts.map +1 -0
- package/dist/dts/types/index.d.ts +4 -0
- package/dist/dts/types/index.d.ts.map +1 -0
- package/dist/dts/types/utils.d.ts +16 -0
- package/dist/dts/types/utils.d.ts.map +1 -0
- package/dist/{types → dts/types}/wallet.d.ts +4 -14
- package/dist/dts/types/wallet.d.ts.map +1 -0
- package/dist/dts/types/worker.d.ts +4 -0
- package/dist/dts/types/worker.d.ts.map +1 -0
- package/dist/dts/utils/logger.d.ts.map +1 -0
- package/dist/{worker → dts/worker}/WorkerClient.d.ts +4 -4
- package/dist/dts/worker/WorkerClient.d.ts.map +1 -0
- package/dist/dts/worker/index.d.ts.map +1 -0
- package/dist/index.d.ts +298 -5
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.js.map +1 -1
- package/package.json +8 -5
- package/src/FedimintWallet.test.ts +43 -60
- package/src/FedimintWallet.ts +20 -14
- package/src/index.ts +2 -22
- package/src/services/BalanceService.ts +5 -4
- package/src/services/FederationService.test.ts +1 -1
- package/src/services/FederationService.ts +1 -1
- package/src/services/LightningService.test.ts +103 -63
- package/src/services/LightningService.ts +84 -47
- package/src/services/MintService.test.ts +16 -2
- package/src/services/MintService.ts +8 -8
- package/src/services/RecoveryService.ts +1 -1
- package/src/test/TestFedimintWallet.ts +10 -1
- package/src/test/TestingService.ts +49 -30
- package/src/test/crypto.ts +44 -0
- package/src/test/fixtures.test.ts +18 -0
- package/src/test/{setupTests.ts → fixtures.ts} +25 -4
- package/src/types/index.ts +3 -0
- package/src/types/utils.ts +25 -0
- package/src/types/wallet.ts +4 -23
- package/src/types/worker.ts +13 -0
- package/src/worker/WorkerClient.test.ts +6 -0
- package/src/worker/WorkerClient.ts +28 -20
- package/src/worker/worker.js +9 -0
- package/src/worker/worker.test.ts +2 -2
- package/dist/FedimintWallet.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/services/BalanceService.d.ts.map +0 -1
- package/dist/services/FederationService.d.ts.map +0 -1
- package/dist/services/LightningService.d.ts +0 -18
- package/dist/services/LightningService.d.ts.map +0 -1
- package/dist/services/MintService.d.ts.map +0 -1
- package/dist/services/RecoveryService.d.ts.map +0 -1
- package/dist/services/index.d.ts.map +0 -1
- package/dist/types/wallet.d.ts.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/worker/WorkerClient.d.ts.map +0 -1
- package/dist/worker/index.d.ts.map +0 -1
- /package/dist/{services → dts/services}/index.d.ts +0 -0
- /package/dist/{utils → dts/utils}/logger.d.ts +0 -0
- /package/dist/{worker → dts/worker}/index.d.ts +0 -0
package/src/FedimintWallet.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WorkerClient } from './worker
|
|
1
|
+
import { WorkerClient } from './worker'
|
|
2
2
|
import {
|
|
3
3
|
BalanceService,
|
|
4
4
|
MintService,
|
|
@@ -19,7 +19,7 @@ export class FedimintWallet {
|
|
|
19
19
|
public federation: FederationService
|
|
20
20
|
public recovery: RecoveryService
|
|
21
21
|
|
|
22
|
-
private _openPromise: Promise<void> |
|
|
22
|
+
private _openPromise: Promise<void> | undefined = undefined
|
|
23
23
|
private _resolveOpen: () => void = () => {}
|
|
24
24
|
private _isOpen: boolean = false
|
|
25
25
|
|
|
@@ -85,9 +85,9 @@ export class FedimintWallet {
|
|
|
85
85
|
await this._client.initialize()
|
|
86
86
|
// TODO: Determine if this should be safe or throw
|
|
87
87
|
if (this._isOpen) throw new Error('The FedimintWallet is already open.')
|
|
88
|
-
const { success } = await this._client.sendSingleMessage
|
|
89
|
-
|
|
90
|
-
})
|
|
88
|
+
const { success } = await this._client.sendSingleMessage<{
|
|
89
|
+
success: boolean
|
|
90
|
+
}>('open', { clientName })
|
|
91
91
|
if (success) {
|
|
92
92
|
this._isOpen = !!success
|
|
93
93
|
this._resolveOpen()
|
|
@@ -105,13 +105,19 @@ export class FedimintWallet {
|
|
|
105
105
|
throw new Error(
|
|
106
106
|
'The FedimintWallet is already open. You can only call `joinFederation` on closed clients.',
|
|
107
107
|
)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
108
|
+
try {
|
|
109
|
+
const response = await this._client.sendSingleMessage<{
|
|
110
|
+
success: boolean
|
|
111
|
+
}>('join', { inviteCode, clientName })
|
|
112
|
+
if (response.success) {
|
|
113
|
+
this._isOpen = true
|
|
114
|
+
this._resolveOpen()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return response.success
|
|
118
|
+
} catch (e) {
|
|
119
|
+
logger.error('Error joining federation', e)
|
|
120
|
+
return false
|
|
115
121
|
}
|
|
116
122
|
}
|
|
117
123
|
|
|
@@ -120,9 +126,9 @@ export class FedimintWallet {
|
|
|
120
126
|
* After this call, the FedimintWallet instance should be discarded.
|
|
121
127
|
*/
|
|
122
128
|
async cleanup() {
|
|
123
|
-
this._openPromise =
|
|
129
|
+
this._openPromise = undefined
|
|
124
130
|
this._isOpen = false
|
|
125
|
-
this._client.cleanup()
|
|
131
|
+
await this._client.cleanup()
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
isOpen() {
|
package/src/index.ts
CHANGED
|
@@ -1,22 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
LightningGateway,
|
|
4
|
-
RouteHint,
|
|
5
|
-
FeeToAmount,
|
|
6
|
-
OutgoingLightningPayment,
|
|
7
|
-
PayType,
|
|
8
|
-
LnPayState,
|
|
9
|
-
CreateBolt11Response,
|
|
10
|
-
} from './types/wallet.js'
|
|
11
|
-
|
|
12
|
-
export { FedimintWallet }
|
|
13
|
-
|
|
14
|
-
export type {
|
|
15
|
-
LightningGateway,
|
|
16
|
-
RouteHint,
|
|
17
|
-
FeeToAmount,
|
|
18
|
-
OutgoingLightningPayment,
|
|
19
|
-
PayType,
|
|
20
|
-
LnPayState,
|
|
21
|
-
CreateBolt11Response,
|
|
22
|
-
}
|
|
1
|
+
export { FedimintWallet } from './FedimintWallet'
|
|
2
|
+
export type * from './types'
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MSats } from '../types'
|
|
1
2
|
import { WorkerClient } from '../worker'
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -9,19 +10,19 @@ export class BalanceService {
|
|
|
9
10
|
constructor(private client: WorkerClient) {}
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
* Get the balance of the current wallet
|
|
13
|
+
* Get the balance of the current wallet in milli-satoshis (MSats)
|
|
13
14
|
*
|
|
14
15
|
* @example
|
|
15
16
|
* ```ts
|
|
16
17
|
* const balance = await wallet.balance.getBalance()
|
|
17
18
|
* ```
|
|
18
19
|
*/
|
|
19
|
-
async getBalance(): Promise<
|
|
20
|
+
async getBalance(): Promise<MSats> {
|
|
20
21
|
return await this.client.rpcSingle('', 'get_balance', {})
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
|
-
* Subscribe to the balance of the current wallet
|
|
25
|
+
* Subscribe to the balance of the current wallet in milli-satoshis (MSats)
|
|
25
26
|
*
|
|
26
27
|
* @example
|
|
27
28
|
* ```ts
|
|
@@ -34,7 +35,7 @@ export class BalanceService {
|
|
|
34
35
|
* ```
|
|
35
36
|
*/
|
|
36
37
|
subscribeBalance(
|
|
37
|
-
onSuccess: (balance:
|
|
38
|
+
onSuccess: (balance: MSats) => void = () => {},
|
|
38
39
|
onError: (error: string) => void = () => {},
|
|
39
40
|
) {
|
|
40
41
|
const unsubscribe = this.client.rpcStream<string>(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { expect } from 'vitest'
|
|
2
|
-
import {
|
|
2
|
+
import { keyPair } from '../test/crypto'
|
|
3
|
+
import { walletTest } from '../test/fixtures'
|
|
3
4
|
|
|
4
5
|
walletTest(
|
|
5
6
|
'createInvoice should create a bolt11 invoice',
|
|
@@ -20,11 +21,23 @@ walletTest(
|
|
|
20
21
|
|
|
21
22
|
// Test with expiry time
|
|
22
23
|
await expect(
|
|
23
|
-
wallet.lightning.createInvoice(100, 'test', 1000
|
|
24
|
+
wallet.lightning.createInvoice(100, 'test', 1000),
|
|
24
25
|
).resolves.toBeDefined()
|
|
25
26
|
},
|
|
26
27
|
)
|
|
27
28
|
|
|
29
|
+
walletTest('createInvoice with expiry', async ({ wallet }) => {
|
|
30
|
+
expect(wallet).toBeDefined()
|
|
31
|
+
expect(wallet.isOpen()).toBe(true)
|
|
32
|
+
|
|
33
|
+
const invoice = await wallet.lightning.createInvoice(100, 'test', 1000)
|
|
34
|
+
expect(invoice).toBeDefined()
|
|
35
|
+
expect(invoice).toMatchObject({
|
|
36
|
+
invoice: expect.any(String),
|
|
37
|
+
operation_id: expect.any(String),
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
28
41
|
walletTest(
|
|
29
42
|
'listGateways should return a list of gateways',
|
|
30
43
|
async ({ wallet }) => {
|
|
@@ -35,11 +48,7 @@ walletTest(
|
|
|
35
48
|
const gateways = await wallet.lightning.listGateways()
|
|
36
49
|
expect(wallet.testing.getRequestCounter()).toBe(counterBefore + 1)
|
|
37
50
|
expect(gateways).toBeDefined()
|
|
38
|
-
expect(gateways).toMatchObject(
|
|
39
|
-
{
|
|
40
|
-
info: expect.any(Object),
|
|
41
|
-
},
|
|
42
|
-
])
|
|
51
|
+
expect(gateways).toMatchObject(expect.any(Array))
|
|
43
52
|
},
|
|
44
53
|
)
|
|
45
54
|
|
|
@@ -74,42 +83,6 @@ walletTest('getGateway should return a gateway', async ({ wallet }) => {
|
|
|
74
83
|
})
|
|
75
84
|
})
|
|
76
85
|
|
|
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
86
|
walletTest(
|
|
114
87
|
'payInvoice should throw on insufficient funds',
|
|
115
88
|
async ({ wallet }) => {
|
|
@@ -126,7 +99,7 @@ walletTest(
|
|
|
126
99
|
const counterBefore = wallet.testing.getRequestCounter()
|
|
127
100
|
// Insufficient funds
|
|
128
101
|
try {
|
|
129
|
-
await wallet.lightning.payInvoice(invoice.invoice
|
|
102
|
+
await wallet.lightning.payInvoice(invoice.invoice)
|
|
130
103
|
expect.unreachable('Should throw error')
|
|
131
104
|
} catch (error) {
|
|
132
105
|
expect(error).toBeDefined()
|
|
@@ -139,30 +112,97 @@ walletTest(
|
|
|
139
112
|
|
|
140
113
|
walletTest(
|
|
141
114
|
'payInvoice should pay a bolt11 invoice',
|
|
142
|
-
{ timeout:
|
|
115
|
+
{ timeout: 20_000 },
|
|
116
|
+
async ({ fundedWallet }) => {
|
|
117
|
+
expect(fundedWallet).toBeDefined()
|
|
118
|
+
expect(fundedWallet.isOpen()).toBe(true)
|
|
119
|
+
const initialBalance = await fundedWallet.balance.getBalance()
|
|
120
|
+
expect(initialBalance).toBeGreaterThan(0)
|
|
121
|
+
const externalInvoice = await fundedWallet.testing.createFaucetInvoice(1)
|
|
122
|
+
const gatewayInfo = await fundedWallet.testing.getFaucetGatewayInfo()
|
|
123
|
+
const payment = await fundedWallet.lightning.payInvoice(
|
|
124
|
+
externalInvoice,
|
|
125
|
+
gatewayInfo,
|
|
126
|
+
)
|
|
127
|
+
expect(payment).toMatchObject({
|
|
128
|
+
contract_id: expect.any(String),
|
|
129
|
+
fee: expect.any(Number),
|
|
130
|
+
payment_type: expect.any(Object),
|
|
131
|
+
})
|
|
132
|
+
const finalBalance = await fundedWallet.balance.getBalance()
|
|
133
|
+
expect(finalBalance).toBeLessThan(initialBalance)
|
|
134
|
+
},
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
walletTest(
|
|
138
|
+
'createInvoiceTweaked should create a bolt11 invoice with a tweaked public key',
|
|
143
139
|
async ({ wallet }) => {
|
|
144
140
|
expect(wallet).toBeDefined()
|
|
145
141
|
expect(wallet.isOpen()).toBe(true)
|
|
146
142
|
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const invoice = await wallet.lightning.
|
|
143
|
+
// Make an ephemeral key pair
|
|
144
|
+
const { publicKey, secretKey } = keyPair()
|
|
145
|
+
const tweak = 1
|
|
146
|
+
|
|
147
|
+
// Create an invoice paying to the tweaked public key
|
|
148
|
+
const invoice = await wallet.lightning.createInvoiceTweaked(
|
|
149
|
+
1000,
|
|
150
|
+
'test tweaked',
|
|
151
|
+
publicKey,
|
|
152
|
+
tweak,
|
|
153
|
+
)
|
|
154
|
+
expect(invoice).toBeDefined()
|
|
155
|
+
expect(invoice).toMatchObject({
|
|
156
|
+
invoice: expect.any(String),
|
|
157
|
+
operation_id: expect.any(String),
|
|
158
|
+
})
|
|
159
|
+
},
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
walletTest(
|
|
163
|
+
'scanReceivesForTweaks should return the operation id',
|
|
164
|
+
async ({ wallet }) => {
|
|
165
|
+
expect(wallet).toBeDefined()
|
|
166
|
+
expect(wallet.isOpen()).toBe(true)
|
|
167
|
+
|
|
168
|
+
// Make an ephemeral key pair
|
|
169
|
+
const { publicKey, secretKey } = keyPair()
|
|
170
|
+
const tweak = 1
|
|
171
|
+
|
|
172
|
+
const gatewayInfo = await wallet.testing.getFaucetGatewayInfo()
|
|
173
|
+
|
|
174
|
+
// Create an invoice paying to the tweaked public key
|
|
175
|
+
const invoice = await wallet.lightning.createInvoiceTweaked(
|
|
176
|
+
1000,
|
|
177
|
+
'test tweaked',
|
|
178
|
+
publicKey,
|
|
179
|
+
tweak,
|
|
180
|
+
undefined,
|
|
181
|
+
gatewayInfo,
|
|
182
|
+
)
|
|
153
183
|
await expect(
|
|
154
|
-
wallet.testing.
|
|
184
|
+
wallet.testing.payFaucetInvoice(invoice.invoice),
|
|
155
185
|
).resolves.toBeDefined()
|
|
156
|
-
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
186
|
+
|
|
187
|
+
// Scan for the receive
|
|
188
|
+
const operationIds = await wallet.lightning.scanReceivesForTweaks(
|
|
189
|
+
secretKey,
|
|
190
|
+
[tweak],
|
|
191
|
+
{},
|
|
192
|
+
)
|
|
193
|
+
expect(operationIds).toBeDefined()
|
|
194
|
+
expect(operationIds).toHaveLength(1)
|
|
195
|
+
|
|
196
|
+
// Subscribe to claiming the receive
|
|
197
|
+
const subscription = await wallet.lightning.subscribeLnClaim(
|
|
198
|
+
operationIds[0],
|
|
199
|
+
(state) => {
|
|
200
|
+
expect(state).toBeDefined()
|
|
201
|
+
expect(state).toMatchObject({
|
|
202
|
+
state: 'claimed',
|
|
203
|
+
})
|
|
204
|
+
},
|
|
205
|
+
)
|
|
206
|
+
expect(subscription).toBeDefined()
|
|
167
207
|
},
|
|
168
208
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WorkerClient } from '../worker'
|
|
2
|
-
import {
|
|
2
|
+
import type {
|
|
3
3
|
CreateBolt11Response,
|
|
4
4
|
GatewayInfo,
|
|
5
5
|
JSONObject,
|
|
@@ -7,75 +7,103 @@ import {
|
|
|
7
7
|
LightningGateway,
|
|
8
8
|
LnPayState,
|
|
9
9
|
LnReceiveState,
|
|
10
|
+
MSats,
|
|
10
11
|
OutgoingLightningPayment,
|
|
11
|
-
} from '../types
|
|
12
|
+
} from '../types'
|
|
12
13
|
|
|
13
14
|
export class LightningService {
|
|
14
15
|
constructor(private client: WorkerClient) {}
|
|
15
16
|
|
|
16
|
-
async
|
|
17
|
-
amount:
|
|
17
|
+
async createInvoice(
|
|
18
|
+
amount: MSats,
|
|
18
19
|
description: string,
|
|
19
|
-
expiryTime
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
) {
|
|
20
|
+
expiryTime?: number, // in seconds
|
|
21
|
+
gatewayInfo?: GatewayInfo,
|
|
22
|
+
extraMeta?: JSONObject,
|
|
23
|
+
): Promise<CreateBolt11Response> {
|
|
24
|
+
const gateway = gatewayInfo ?? (await this._getDefaultGatewayInfo())
|
|
23
25
|
return await this.client.rpcSingle('ln', 'create_bolt11_invoice', {
|
|
24
26
|
amount,
|
|
25
27
|
description,
|
|
26
|
-
expiry_time: expiryTime,
|
|
27
|
-
extra_meta: extraMeta,
|
|
28
|
-
gateway
|
|
28
|
+
expiry_time: expiryTime ?? null,
|
|
29
|
+
extra_meta: extraMeta ?? {},
|
|
30
|
+
gateway,
|
|
29
31
|
})
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
async
|
|
33
|
-
amount:
|
|
34
|
+
async createInvoiceTweaked(
|
|
35
|
+
amount: MSats,
|
|
34
36
|
description: string,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
tweakKey: string,
|
|
38
|
+
index: number,
|
|
39
|
+
expiryTime?: number, // in seconds
|
|
40
|
+
gatewayInfo?: GatewayInfo,
|
|
41
|
+
extraMeta?: JSONObject,
|
|
37
42
|
): Promise<CreateBolt11Response> {
|
|
38
|
-
await this.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const gateway = gatewayInfo ?? (await this._getDefaultGatewayInfo())
|
|
44
|
+
return await this.client.rpcSingle(
|
|
45
|
+
'ln',
|
|
46
|
+
'create_bolt11_invoice_for_user_tweaked',
|
|
47
|
+
{
|
|
48
|
+
amount,
|
|
49
|
+
description,
|
|
50
|
+
expiry_time: expiryTime ?? null,
|
|
51
|
+
user_key: tweakKey,
|
|
52
|
+
index,
|
|
53
|
+
extra_meta: extraMeta ?? {},
|
|
54
|
+
gateway,
|
|
55
|
+
},
|
|
56
|
+
)
|
|
47
57
|
}
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
// Returns the operation ids of payments received to the tweaks of the user secret key
|
|
60
|
+
async scanReceivesForTweaks(
|
|
61
|
+
tweakKey: string,
|
|
62
|
+
indices: number[],
|
|
63
|
+
extraMeta?: JSONObject,
|
|
64
|
+
): Promise<string[]> {
|
|
65
|
+
return await this.client.rpcSingle('ln', 'scan_receive_for_user_tweaked', {
|
|
66
|
+
user_key: tweakKey,
|
|
67
|
+
indices,
|
|
68
|
+
extra_meta: extraMeta ?? {},
|
|
58
69
|
})
|
|
59
70
|
}
|
|
60
71
|
|
|
61
|
-
private async _getDefaultGatewayInfo(): Promise<
|
|
72
|
+
private async _getDefaultGatewayInfo(): Promise<GatewayInfo> {
|
|
73
|
+
await this.updateGatewayCache()
|
|
62
74
|
const gateways = await this.listGateways()
|
|
63
|
-
return gateways[0]
|
|
75
|
+
return gateways[0]?.info
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
async payInvoice(
|
|
67
79
|
invoice: string,
|
|
68
|
-
|
|
80
|
+
gatewayInfo?: GatewayInfo,
|
|
81
|
+
extraMeta?: JSONObject,
|
|
69
82
|
): Promise<OutgoingLightningPayment> {
|
|
70
|
-
await this.
|
|
71
|
-
const gateway = await this._getDefaultGatewayInfo()
|
|
83
|
+
const gateway = gatewayInfo ?? (await this._getDefaultGatewayInfo())
|
|
72
84
|
return await this.client.rpcSingle('ln', 'pay_bolt11_invoice', {
|
|
73
|
-
maybe_gateway: gateway
|
|
85
|
+
maybe_gateway: gateway,
|
|
74
86
|
invoice,
|
|
75
|
-
extra_meta: extraMeta,
|
|
87
|
+
extra_meta: extraMeta ?? {},
|
|
76
88
|
})
|
|
77
89
|
}
|
|
78
90
|
|
|
91
|
+
subscribeLnClaim(
|
|
92
|
+
operationId: string,
|
|
93
|
+
onSuccess: (state: LnReceiveState) => void = () => {},
|
|
94
|
+
onError: (error: string) => void = () => {},
|
|
95
|
+
) {
|
|
96
|
+
const unsubscribe = this.client.rpcStream(
|
|
97
|
+
'ln',
|
|
98
|
+
'subscribe_ln_claim',
|
|
99
|
+
{ operation_id: operationId },
|
|
100
|
+
onSuccess,
|
|
101
|
+
onError,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
return unsubscribe
|
|
105
|
+
}
|
|
106
|
+
|
|
79
107
|
subscribeLnPay(
|
|
80
108
|
operationId: string,
|
|
81
109
|
onSuccess: (state: LnPayState) => void = () => {},
|
|
@@ -110,17 +138,26 @@ export class LightningService {
|
|
|
110
138
|
|
|
111
139
|
async waitForReceive(operationId: string): Promise<LnReceiveState> {
|
|
112
140
|
return new Promise((resolve, reject) => {
|
|
113
|
-
|
|
141
|
+
let unsubscribe: () => void
|
|
142
|
+
const timeoutId = setTimeout(() => {
|
|
143
|
+
reject(new Error('Timeout waiting for receive'))
|
|
144
|
+
}, 15000)
|
|
145
|
+
|
|
146
|
+
unsubscribe = this.subscribeLnReceive(
|
|
114
147
|
operationId,
|
|
115
148
|
(res) => {
|
|
116
|
-
if (res === 'claimed')
|
|
149
|
+
if (res === 'claimed') {
|
|
150
|
+
clearTimeout(timeoutId)
|
|
151
|
+
unsubscribe()
|
|
152
|
+
resolve(res)
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
(error) => {
|
|
156
|
+
clearTimeout(timeoutId)
|
|
157
|
+
unsubscribe()
|
|
158
|
+
reject(error)
|
|
117
159
|
},
|
|
118
|
-
reject,
|
|
119
160
|
)
|
|
120
|
-
setTimeout(() => {
|
|
121
|
-
unsubscribe()
|
|
122
|
-
reject(new Error('Timeout waiting for receive'))
|
|
123
|
-
}, 10000)
|
|
124
161
|
})
|
|
125
162
|
}
|
|
126
163
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expect } from 'vitest'
|
|
2
|
-
import { walletTest } from '../test/
|
|
2
|
+
import { walletTest } from '../test/fixtures'
|
|
3
3
|
|
|
4
4
|
walletTest('redeemEcash should error on invalid ecash', async ({ wallet }) => {
|
|
5
5
|
expect(wallet).toBeDefined()
|
|
@@ -9,7 +9,7 @@ walletTest('redeemEcash should error on invalid ecash', async ({ wallet }) => {
|
|
|
9
9
|
})
|
|
10
10
|
|
|
11
11
|
walletTest(
|
|
12
|
-
'reissueExternalNotes should
|
|
12
|
+
'reissueExternalNotes should throw if wallet is empty',
|
|
13
13
|
async ({ wallet }) => {
|
|
14
14
|
expect(wallet).toBeDefined()
|
|
15
15
|
expect(wallet.isOpen()).toBe(true)
|
|
@@ -17,3 +17,17 @@ walletTest(
|
|
|
17
17
|
await expect(wallet.mint.reissueExternalNotes('test')).rejects.toThrow()
|
|
18
18
|
},
|
|
19
19
|
)
|
|
20
|
+
|
|
21
|
+
walletTest('spendNotes should throw if wallet is empty', async ({ wallet }) => {
|
|
22
|
+
expect(wallet).toBeDefined()
|
|
23
|
+
expect(wallet.isOpen()).toBe(true)
|
|
24
|
+
|
|
25
|
+
await expect(wallet.mint.spendNotes(100)).rejects.toThrow()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
walletTest('parseNotes should parse notes', async ({ wallet }) => {
|
|
29
|
+
expect(wallet).toBeDefined()
|
|
30
|
+
expect(wallet.isOpen()).toBe(true)
|
|
31
|
+
|
|
32
|
+
await expect(wallet.mint.reissueExternalNotes('test')).rejects.toThrow()
|
|
33
|
+
})
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { WorkerClient } from '../worker'
|
|
2
|
-
import {
|
|
2
|
+
import type {
|
|
3
3
|
Duration,
|
|
4
4
|
JSONObject,
|
|
5
5
|
JSONValue,
|
|
6
6
|
MintSpendNotesResponse,
|
|
7
|
+
MSats,
|
|
7
8
|
ReissueExternalNotesState,
|
|
8
|
-
} from '../types
|
|
9
|
+
} from '../types'
|
|
9
10
|
|
|
10
11
|
export class MintService {
|
|
11
12
|
constructor(private client: WorkerClient) {}
|
|
@@ -44,12 +45,11 @@ export class MintService {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
async spendNotes(
|
|
47
|
-
minAmount:
|
|
48
|
+
minAmount: MSats,
|
|
48
49
|
// Tells the wallet to automatically try to cancel the spend if it hasn't completed
|
|
49
|
-
// after the specified number of
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
tryCancelAfter: number | Duration = 0,
|
|
50
|
+
// after the specified number of seconds. If the receiver has already redeemed
|
|
51
|
+
// the notes at this time, the notes will not be cancelled.
|
|
52
|
+
tryCancelAfter: number | Duration = 3600 * 24, // defaults to 1 day
|
|
53
53
|
includeInvite: boolean = false,
|
|
54
54
|
extraMeta: JSONValue = {},
|
|
55
55
|
): Promise<MintSpendNotesResponse> {
|
|
@@ -77,7 +77,7 @@ export class MintService {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
async
|
|
80
|
+
async parseNotes(oobNotes: string): Promise<MSats> {
|
|
81
81
|
return await this.client.rpcSingle('mint', 'validate_notes', {
|
|
82
82
|
oob_notes: oobNotes,
|
|
83
83
|
})
|
|
@@ -7,7 +7,16 @@ export class TestFedimintWallet extends FedimintWallet {
|
|
|
7
7
|
|
|
8
8
|
constructor() {
|
|
9
9
|
super()
|
|
10
|
-
this.testing = new TestingService(this.getWorkerClient())
|
|
10
|
+
this.testing = new TestingService(this.getWorkerClient(), this.lightning)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async fundWallet(amount: number) {
|
|
14
|
+
const info = await this.testing.getFaucetGatewayInfo()
|
|
15
|
+
const invoice = await this.lightning.createInvoice(amount, '', 1000, info)
|
|
16
|
+
await Promise.all([
|
|
17
|
+
this.testing.payFaucetInvoice(invoice.invoice),
|
|
18
|
+
this.lightning.waitForReceive(invoice.operation_id),
|
|
19
|
+
])
|
|
11
20
|
}
|
|
12
21
|
|
|
13
22
|
// Method to expose the WorkerClient
|