@fedimint/core-web 0.0.2 → 0.0.3
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/LICENSE +21 -0
- package/README.md +34 -13
- package/dist/FedimintWallet.d.ts +47 -12
- package/dist/FedimintWallet.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/wallet.d.ts +19 -3
- package/dist/types/wallet.d.ts.map +1 -1
- package/dist/worker.js +2 -0
- package/dist/worker.js.map +1 -0
- package/node_modules/fedimint-client-wasm/fedimint_client_wasm.d.ts +49 -0
- package/node_modules/fedimint-client-wasm/fedimint_client_wasm.js +4 -0
- package/node_modules/fedimint-client-wasm/fedimint_client_wasm_bg.js +1411 -0
- package/{dist/assets/fedimint_client_wasm_bg-DxOUItb-.wasm → node_modules/fedimint-client-wasm/fedimint_client_wasm_bg.wasm} +0 -0
- package/node_modules/fedimint-client-wasm/package.json +26 -0
- package/package.json +10 -5
- package/src/FedimintWallet.ts +225 -91
- package/src/types/wallet.ts +25 -2
- package/src/worker.js +80 -0
- package/wasm/fedimint_client_wasm.d.ts +41 -96
- package/wasm/fedimint_client_wasm.js +4 -1120
- package/wasm/fedimint_client_wasm_bg.js +1197 -659
- package/wasm/fedimint_client_wasm_bg.wasm +0 -0
- package/wasm/fedimint_client_wasm_bg.wasm.d.ts +108 -32
- package/wasm/package.json +26 -0
- package/dist/wasm.worker.d.ts +0 -1
- package/dist/wasm.worker.d.ts.map +0 -1
- package/src/vite-env.d.ts +0 -1
- package/src/wasm.worker.ts +0 -41
|
Binary file
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fedimint-client-wasm",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"collaborators": [
|
|
5
|
+
"The Fedimint Developers"
|
|
6
|
+
],
|
|
7
|
+
"description": "fedimint client for wasm",
|
|
8
|
+
"version": "0.5.0-alpha",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/fedimint/fedimint"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"fedimint_client_wasm_bg.wasm",
|
|
16
|
+
"fedimint_client_wasm.js",
|
|
17
|
+
"fedimint_client_wasm_bg.js",
|
|
18
|
+
"fedimint_client_wasm.d.ts"
|
|
19
|
+
],
|
|
20
|
+
"main": "fedimint_client_wasm.js",
|
|
21
|
+
"types": "fedimint_client_wasm.d.ts",
|
|
22
|
+
"sideEffects": [
|
|
23
|
+
"./fedimint_client_wasm.js",
|
|
24
|
+
"./snippets/*"
|
|
25
|
+
]
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedimint/core-web",
|
|
3
3
|
"description": "Library for building web apps with a fedimint client",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.3",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/fedimint/fedimint-web-sdk.git",
|
|
@@ -9,20 +9,25 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
12
|
+
"src",
|
|
13
|
+
"wasm"
|
|
14
14
|
],
|
|
15
15
|
"sideEffects": false,
|
|
16
16
|
"type": "module",
|
|
17
17
|
"main": "./dist/index.js",
|
|
18
18
|
"types": "./dist/index.d.ts",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"fedimint-client-wasm": "file:./wasm"
|
|
21
|
+
},
|
|
22
|
+
"bundledDependencies": [
|
|
23
|
+
"fedimint-client-wasm"
|
|
24
|
+
],
|
|
19
25
|
"devDependencies": {
|
|
20
26
|
"@rollup/plugin-terser": "^0.4.4",
|
|
21
27
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
22
|
-
"@rollup/plugin-wasm": "^6.2.2",
|
|
23
28
|
"@types/node": "^20.14.8",
|
|
24
|
-
"@web/rollup-plugin-import-meta-assets": "^2.2.1",
|
|
25
29
|
"rollup": "^4.21.2",
|
|
30
|
+
"rollup-plugin-typescript2": "^0.36.0",
|
|
26
31
|
"tslib": "^2.7.0",
|
|
27
32
|
"typescript": "^5.2.2"
|
|
28
33
|
},
|
package/src/FedimintWallet.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import init, { RpcHandle, WasmClient } from '../wasm/fedimint_client_wasm.js'
|
|
2
1
|
import {
|
|
3
2
|
JSONValue,
|
|
4
3
|
JSONObject,
|
|
@@ -10,42 +9,87 @@ import {
|
|
|
10
9
|
StreamError,
|
|
11
10
|
CreateBolt11Response,
|
|
12
11
|
ModuleKind,
|
|
13
|
-
|
|
12
|
+
GatewayInfo,
|
|
13
|
+
CancelFunction,
|
|
14
|
+
} from './types/wallet'
|
|
14
15
|
|
|
15
16
|
const DEFAULT_CLIENT_NAME = 'fm-default' as const
|
|
16
17
|
|
|
17
18
|
export class FedimintWallet {
|
|
18
|
-
private
|
|
19
|
+
private worker: Worker | null = null
|
|
19
20
|
private initPromise: Promise<void> | null = null
|
|
20
|
-
private openPromise: Promise<void>
|
|
21
|
+
private openPromise: Promise<void>
|
|
21
22
|
private resolveOpen: () => void = () => {}
|
|
23
|
+
private _isOpen: boolean = false
|
|
24
|
+
private requestCounter: number = 0
|
|
25
|
+
private requestCallbacks: Map<number, (value: any) => void> = new Map()
|
|
22
26
|
|
|
23
|
-
constructor(lazy: boolean = false) {
|
|
24
|
-
if (lazy) return
|
|
25
|
-
this.initialize()
|
|
27
|
+
constructor(lazy: boolean = false, open: boolean = true) {
|
|
26
28
|
this.openPromise = new Promise((resolve) => {
|
|
27
29
|
this.resolveOpen = resolve
|
|
28
30
|
})
|
|
31
|
+
if (lazy) return
|
|
32
|
+
this.initialize()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async waitForOpen() {
|
|
36
|
+
if (this._isOpen) return
|
|
37
|
+
return this.openPromise
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private getNextRequestId(): number {
|
|
41
|
+
return ++this.requestCounter
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Sends a single message and deletes the request callback
|
|
45
|
+
// The first response
|
|
46
|
+
private sendSingleMessage(type: string, payload?: any): Promise<any> {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const requestId = this.getNextRequestId()
|
|
49
|
+
this.requestCallbacks.set(requestId, (data) => {
|
|
50
|
+
this.requestCallbacks.delete(requestId)
|
|
51
|
+
if (data.data) resolve(data.data)
|
|
52
|
+
else if (data.error) reject(data.error)
|
|
53
|
+
})
|
|
54
|
+
try {
|
|
55
|
+
this.worker!.postMessage({ type, payload, requestId })
|
|
56
|
+
} catch (e) {
|
|
57
|
+
reject(e)
|
|
58
|
+
}
|
|
59
|
+
})
|
|
29
60
|
}
|
|
30
61
|
|
|
31
62
|
// Setup
|
|
32
|
-
|
|
63
|
+
initialize() {
|
|
33
64
|
if (this.initPromise) return this.initPromise
|
|
34
|
-
|
|
35
|
-
this.
|
|
36
|
-
|
|
37
|
-
})
|
|
65
|
+
this.worker = new Worker(new URL('./worker.js', import.meta.url))
|
|
66
|
+
this.worker.onmessage = this.handleWorkerMessage.bind(this)
|
|
67
|
+
this.initPromise = this.sendSingleMessage('init')
|
|
38
68
|
return this.initPromise
|
|
39
69
|
}
|
|
40
70
|
|
|
71
|
+
private handleWorkerMessage(event: MessageEvent) {
|
|
72
|
+
const { type, requestId, ...data } = event.data
|
|
73
|
+
const streamCallback = this.requestCallbacks.get(requestId)
|
|
74
|
+
// TODO: Handle errors... maybe have another callbacks list for errors?
|
|
75
|
+
if (streamCallback) {
|
|
76
|
+
streamCallback(data) // {data: something} OR {error: something}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
41
80
|
async open(clientName: string = DEFAULT_CLIENT_NAME) {
|
|
42
81
|
await this.initialize()
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
82
|
+
// TODO: Determine if this should be safe or throw
|
|
83
|
+
if (this._isOpen)
|
|
84
|
+
throw new Error(
|
|
85
|
+
'The FedimintWallet is already open. You can only call `FedimintWallet.open on closed clients.`',
|
|
86
|
+
)
|
|
87
|
+
const { success } = await this.sendSingleMessage('open', { clientName })
|
|
88
|
+
if (success) {
|
|
89
|
+
this._isOpen = !!success
|
|
90
|
+
this.resolveOpen()
|
|
91
|
+
}
|
|
92
|
+
return success
|
|
49
93
|
}
|
|
50
94
|
|
|
51
95
|
async joinFederation(
|
|
@@ -53,12 +97,43 @@ export class FedimintWallet {
|
|
|
53
97
|
clientName: string = DEFAULT_CLIENT_NAME,
|
|
54
98
|
) {
|
|
55
99
|
await this.initialize()
|
|
56
|
-
this
|
|
57
|
-
this.
|
|
100
|
+
// TODO: Determine if this should be safe or throw
|
|
101
|
+
if (this._isOpen)
|
|
102
|
+
throw new Error(
|
|
103
|
+
'Failed to Join Federation. You have already joined a federation, and you can only join one federation per wallet.',
|
|
104
|
+
)
|
|
105
|
+
const response = await this.sendSingleMessage('join', {
|
|
106
|
+
inviteCode,
|
|
107
|
+
clientName,
|
|
108
|
+
})
|
|
109
|
+
if (response.success) this._isOpen = true
|
|
58
110
|
}
|
|
59
111
|
|
|
60
|
-
|
|
61
|
-
|
|
112
|
+
/**
|
|
113
|
+
* @summary Initiates an RPC stream with the specified module and method.
|
|
114
|
+
*
|
|
115
|
+
* @description
|
|
116
|
+
* This function sets up an RPC stream by sending a request to a worker and
|
|
117
|
+
* handling responses asynchronously. It ensures that unsubscription is handled
|
|
118
|
+
* correctly, even if the unsubscribe function is called before the subscription
|
|
119
|
+
* is fully established, by deferring the unsubscription attempt using `setTimeout`.
|
|
120
|
+
*
|
|
121
|
+
* The function operates in a non-blocking manner, leveraging Promises to manage
|
|
122
|
+
* asynchronous operations and callbacks to handle responses.
|
|
123
|
+
*
|
|
124
|
+
*
|
|
125
|
+
* @template Response - The expected type of the successful response.
|
|
126
|
+
* @template Body - The type of the request body.
|
|
127
|
+
* @param module - The module kind to interact with.
|
|
128
|
+
* @param method - The method name to invoke on the module.
|
|
129
|
+
* @param body - The request payload.
|
|
130
|
+
* @param onSuccess - Callback invoked with the response data on success.
|
|
131
|
+
* @param onError - Callback invoked with error information if an error occurs.
|
|
132
|
+
* @param onEnd - Optional callback invoked when the stream ends.
|
|
133
|
+
* @returns A function that can be called to cancel the subscription.
|
|
134
|
+
*
|
|
135
|
+
*/
|
|
136
|
+
private _rpcStream<
|
|
62
137
|
Response extends JSONValue = JSONValue,
|
|
63
138
|
Body extends JSONValue = JSONValue,
|
|
64
139
|
>(
|
|
@@ -67,42 +142,94 @@ export class FedimintWallet {
|
|
|
67
142
|
body: Body,
|
|
68
143
|
onSuccess: (res: Response) => void,
|
|
69
144
|
onError: (res: StreamError['error']) => void,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
145
|
+
onEnd: () => void = () => {},
|
|
146
|
+
): CancelFunction {
|
|
147
|
+
const requestId = this.getNextRequestId()
|
|
148
|
+
|
|
149
|
+
let unsubscribe: (value: void) => void = () => {}
|
|
150
|
+
let isSubscribed = false
|
|
151
|
+
|
|
152
|
+
const unsubscribePromise = new Promise<void>((resolve) => {
|
|
153
|
+
unsubscribe = () => {
|
|
154
|
+
if (isSubscribed) {
|
|
155
|
+
// If already subscribed, resolve immediately to trigger unsubscription
|
|
156
|
+
resolve()
|
|
82
157
|
} else {
|
|
83
|
-
|
|
158
|
+
// If not yet subscribed, defer the unsubscribe attempt to the next event loop tick
|
|
159
|
+
// This ensures that subscription setup has time to complete
|
|
160
|
+
setTimeout(() => unsubscribe(), 0)
|
|
84
161
|
}
|
|
85
|
-
}
|
|
86
|
-
)
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// Initiate the inner RPC stream setup asynchronously
|
|
166
|
+
this._rpcStreamInner(
|
|
167
|
+
requestId,
|
|
168
|
+
module,
|
|
169
|
+
method,
|
|
170
|
+
body,
|
|
171
|
+
onSuccess,
|
|
172
|
+
onError,
|
|
173
|
+
onEnd,
|
|
174
|
+
unsubscribePromise,
|
|
175
|
+
).then(() => {
|
|
176
|
+
isSubscribed = true
|
|
177
|
+
})
|
|
178
|
+
|
|
87
179
|
return unsubscribe
|
|
88
180
|
}
|
|
89
181
|
|
|
182
|
+
private async _rpcStreamInner<
|
|
183
|
+
Response extends JSONValue = JSONValue,
|
|
184
|
+
Body extends JSONValue = JSONValue,
|
|
185
|
+
>(
|
|
186
|
+
requestId: number,
|
|
187
|
+
module: ModuleKind,
|
|
188
|
+
method: string,
|
|
189
|
+
body: Body,
|
|
190
|
+
onSuccess: (res: Response) => void,
|
|
191
|
+
onError: (res: StreamError['error']) => void,
|
|
192
|
+
onEnd: () => void = () => {},
|
|
193
|
+
unsubscribePromise: Promise<void>,
|
|
194
|
+
// Unsubscribe function
|
|
195
|
+
): Promise<void> {
|
|
196
|
+
await this.openPromise
|
|
197
|
+
if (!this.worker || !this._isOpen)
|
|
198
|
+
throw new Error('FedimintWallet is not open')
|
|
199
|
+
|
|
200
|
+
this.requestCallbacks.set(requestId, (response: StreamResult<Response>) => {
|
|
201
|
+
if (response.error !== undefined) {
|
|
202
|
+
onError(response.error)
|
|
203
|
+
} else if (response.data !== undefined) {
|
|
204
|
+
onSuccess(response.data)
|
|
205
|
+
} else if (response.end !== undefined) {
|
|
206
|
+
this.requestCallbacks.delete(requestId)
|
|
207
|
+
onEnd()
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
this.worker.postMessage({
|
|
211
|
+
type: 'rpc',
|
|
212
|
+
payload: { module, method, body },
|
|
213
|
+
requestId,
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
unsubscribePromise.then(() => {
|
|
217
|
+
console.trace('UNSUBSCRIBING', requestId)
|
|
218
|
+
this.worker?.postMessage({
|
|
219
|
+
type: 'unsubscribe',
|
|
220
|
+
requestId,
|
|
221
|
+
})
|
|
222
|
+
this.requestCallbacks.delete(requestId)
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
|
|
90
226
|
private async _rpcSingle<Response extends JSONValue = JSONValue>(
|
|
91
227
|
module: ModuleKind,
|
|
92
228
|
method: string,
|
|
93
229
|
body: JSONValue,
|
|
94
230
|
): Promise<Response> {
|
|
95
231
|
return new Promise((resolve, reject) => {
|
|
96
|
-
|
|
97
|
-
this._fed.rpc(module, method, JSON.stringify(body), (res: string) => {
|
|
98
|
-
// TODO: Validate the response?
|
|
99
|
-
const parsed = JSON.parse(res) as StreamResult<Response>
|
|
100
|
-
if (parsed.error) {
|
|
101
|
-
reject(parsed.error)
|
|
102
|
-
} else {
|
|
103
|
-
resolve(parsed.data)
|
|
104
|
-
}
|
|
105
|
-
})
|
|
232
|
+
this._rpcStream<Response>(module, method, body, resolve, reject)
|
|
106
233
|
})
|
|
107
234
|
}
|
|
108
235
|
|
|
@@ -148,12 +275,7 @@ export class FedimintWallet {
|
|
|
148
275
|
onError,
|
|
149
276
|
)
|
|
150
277
|
|
|
151
|
-
return
|
|
152
|
-
unsubscribe.then((unsub) => {
|
|
153
|
-
unsub.cancel()
|
|
154
|
-
unsub.free()
|
|
155
|
-
})
|
|
156
|
-
}
|
|
278
|
+
return unsubscribe
|
|
157
279
|
}
|
|
158
280
|
|
|
159
281
|
async spendNotes(
|
|
@@ -195,12 +317,7 @@ export class FedimintWallet {
|
|
|
195
317
|
onError,
|
|
196
318
|
)
|
|
197
319
|
|
|
198
|
-
return
|
|
199
|
-
unsubscribe.then((unsub) => {
|
|
200
|
-
unsub.cancel()
|
|
201
|
-
unsub.free()
|
|
202
|
-
})
|
|
203
|
-
}
|
|
320
|
+
return unsubscribe
|
|
204
321
|
}
|
|
205
322
|
|
|
206
323
|
async awaitSpendOobRefund(operationId: string): Promise<JSONValue> {
|
|
@@ -214,13 +331,14 @@ export class FedimintWallet {
|
|
|
214
331
|
* After this call, the FedimintWallet instance should be discarded.
|
|
215
332
|
*/
|
|
216
333
|
async cleanup() {
|
|
217
|
-
|
|
218
|
-
this.
|
|
219
|
-
this.openPromise =
|
|
334
|
+
this.worker?.terminate()
|
|
335
|
+
this.worker = null
|
|
336
|
+
this.openPromise = Promise.resolve()
|
|
337
|
+
this.requestCallbacks.clear()
|
|
220
338
|
}
|
|
221
339
|
|
|
222
340
|
isOpen() {
|
|
223
|
-
return this.
|
|
341
|
+
return this.worker !== null && this._isOpen
|
|
224
342
|
}
|
|
225
343
|
|
|
226
344
|
async getConfig(): Promise<JSONValue> {
|
|
@@ -261,12 +379,7 @@ export class FedimintWallet {
|
|
|
261
379
|
onError,
|
|
262
380
|
)
|
|
263
381
|
|
|
264
|
-
return
|
|
265
|
-
unsubscribe.then((unsub) => {
|
|
266
|
-
unsub.cancel()
|
|
267
|
-
unsub.free()
|
|
268
|
-
})
|
|
269
|
-
}
|
|
382
|
+
return unsubscribe
|
|
270
383
|
}
|
|
271
384
|
|
|
272
385
|
subscribeToRecoveryProgress(
|
|
@@ -281,39 +394,69 @@ export class FedimintWallet {
|
|
|
281
394
|
progress: JSONValue
|
|
282
395
|
}>('', 'subscribe_to_recovery_progress', {}, onSuccess, onError)
|
|
283
396
|
|
|
284
|
-
return
|
|
285
|
-
unsubscribe.then((unsub) => {
|
|
286
|
-
unsub.cancel()
|
|
287
|
-
unsub.free()
|
|
288
|
-
})
|
|
289
|
-
}
|
|
397
|
+
return unsubscribe
|
|
290
398
|
}
|
|
291
399
|
|
|
292
400
|
// Lightning Network module methods
|
|
293
401
|
|
|
402
|
+
async createBolt11InvoiceWithGateway(
|
|
403
|
+
amount: number,
|
|
404
|
+
description: string,
|
|
405
|
+
expiryTime: number | null = null,
|
|
406
|
+
extraMeta: JSONObject = {},
|
|
407
|
+
gatewayInfo: GatewayInfo,
|
|
408
|
+
) {
|
|
409
|
+
return await this._rpcSingle('ln', 'create_bolt11_invoice', {
|
|
410
|
+
amount,
|
|
411
|
+
description,
|
|
412
|
+
expiry_time: expiryTime,
|
|
413
|
+
extra_meta: extraMeta,
|
|
414
|
+
gateway: gatewayInfo,
|
|
415
|
+
})
|
|
416
|
+
}
|
|
417
|
+
|
|
294
418
|
async createBolt11Invoice(
|
|
295
419
|
amount: number,
|
|
296
420
|
description: string,
|
|
297
421
|
expiryTime: number | null = null,
|
|
298
422
|
extraMeta: JSONObject = {},
|
|
299
|
-
gateway: LightningGateway | null = null,
|
|
300
423
|
): Promise<CreateBolt11Response> {
|
|
424
|
+
await this.updateGatewayCache()
|
|
425
|
+
const gateway = await this._getDefaultGatewayInfo()
|
|
301
426
|
return await this._rpcSingle('ln', 'create_bolt11_invoice', {
|
|
302
427
|
amount,
|
|
303
428
|
description,
|
|
304
429
|
expiry_time: expiryTime,
|
|
305
430
|
extra_meta: extraMeta,
|
|
306
|
-
gateway,
|
|
431
|
+
gateway: gateway.info,
|
|
307
432
|
})
|
|
308
433
|
}
|
|
309
434
|
|
|
435
|
+
async payBolt11InvoiceWithGateway(
|
|
436
|
+
invoice: string,
|
|
437
|
+
gatewayInfo: GatewayInfo,
|
|
438
|
+
extraMeta: JSONObject = {},
|
|
439
|
+
) {
|
|
440
|
+
return await this._rpcSingle('ln', 'pay_bolt11_invoice', {
|
|
441
|
+
maybe_gateway: gatewayInfo,
|
|
442
|
+
invoice,
|
|
443
|
+
extra_meta: extraMeta,
|
|
444
|
+
})
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async _getDefaultGatewayInfo(): Promise<LightningGateway> {
|
|
448
|
+
const gateways = await this.listGateways()
|
|
449
|
+
return gateways[0]
|
|
450
|
+
}
|
|
451
|
+
|
|
310
452
|
async payBolt11Invoice(
|
|
311
453
|
invoice: string,
|
|
312
|
-
maybeGateway: LightningGateway | null = null,
|
|
313
454
|
extraMeta: JSONObject = {},
|
|
314
455
|
): Promise<OutgoingLightningPayment> {
|
|
456
|
+
await this.updateGatewayCache()
|
|
457
|
+
const gateway = await this._getDefaultGatewayInfo()
|
|
315
458
|
return await this._rpcSingle('ln', 'pay_bolt11_invoice', {
|
|
316
|
-
maybe_gateway:
|
|
459
|
+
maybe_gateway: gateway.info,
|
|
317
460
|
invoice,
|
|
318
461
|
extra_meta: extraMeta,
|
|
319
462
|
})
|
|
@@ -332,12 +475,7 @@ export class FedimintWallet {
|
|
|
332
475
|
onError,
|
|
333
476
|
)
|
|
334
477
|
|
|
335
|
-
return
|
|
336
|
-
unsubscribe.then((unsub) => {
|
|
337
|
-
unsub.cancel()
|
|
338
|
-
unsub.free()
|
|
339
|
-
})
|
|
340
|
-
}
|
|
478
|
+
return unsubscribe
|
|
341
479
|
}
|
|
342
480
|
|
|
343
481
|
subscribeLnReceive(
|
|
@@ -353,12 +491,7 @@ export class FedimintWallet {
|
|
|
353
491
|
onError,
|
|
354
492
|
)
|
|
355
493
|
|
|
356
|
-
return
|
|
357
|
-
unsubscribe.then((unsub) => {
|
|
358
|
-
unsub.cancel()
|
|
359
|
-
unsub.free()
|
|
360
|
-
})
|
|
361
|
-
}
|
|
494
|
+
return unsubscribe
|
|
362
495
|
}
|
|
363
496
|
|
|
364
497
|
async getGateway(
|
|
@@ -376,6 +509,7 @@ export class FedimintWallet {
|
|
|
376
509
|
}
|
|
377
510
|
|
|
378
511
|
async updateGatewayCache(): Promise<void> {
|
|
512
|
+
console.trace('Updating gateway cache')
|
|
379
513
|
await this._rpcSingle('ln', 'update_gateway_cache', {})
|
|
380
514
|
}
|
|
381
515
|
}
|
package/src/types/wallet.ts
CHANGED
|
@@ -10,7 +10,7 @@ type JSONValue =
|
|
|
10
10
|
|
|
11
11
|
type JSONObject = Record<string, JSONValue>
|
|
12
12
|
|
|
13
|
-
type
|
|
13
|
+
type GatewayInfo = {
|
|
14
14
|
gateway_id: string
|
|
15
15
|
api: string
|
|
16
16
|
node_pub_key: string
|
|
@@ -18,6 +18,14 @@ type LightningGateway = {
|
|
|
18
18
|
route_hints: RouteHint[]
|
|
19
19
|
fees: FeeToAmount
|
|
20
20
|
}
|
|
21
|
+
type LightningGateway = {
|
|
22
|
+
info: GatewayInfo
|
|
23
|
+
vetted: boolean
|
|
24
|
+
ttl: {
|
|
25
|
+
nanos: number
|
|
26
|
+
secs: number
|
|
27
|
+
}
|
|
28
|
+
}
|
|
21
29
|
|
|
22
30
|
type RouteHint = {
|
|
23
31
|
// TODO: Define the structure of RouteHint
|
|
@@ -64,14 +72,27 @@ type CreateBolt11Response = {
|
|
|
64
72
|
type StreamError = {
|
|
65
73
|
error: string
|
|
66
74
|
data: never
|
|
75
|
+
end: never
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
type StreamSuccess<T extends JSONValue> = {
|
|
70
79
|
data: T
|
|
71
80
|
error: never
|
|
81
|
+
end: never
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type StreamEnd = {
|
|
85
|
+
end: string
|
|
86
|
+
data: never
|
|
87
|
+
error: never
|
|
72
88
|
}
|
|
73
89
|
|
|
74
|
-
type StreamResult<T extends JSONValue> =
|
|
90
|
+
type StreamResult<T extends JSONValue> =
|
|
91
|
+
| StreamSuccess<T>
|
|
92
|
+
| StreamError
|
|
93
|
+
| StreamEnd
|
|
94
|
+
|
|
95
|
+
type CancelFunction = () => void
|
|
75
96
|
|
|
76
97
|
export {
|
|
77
98
|
JSONValue,
|
|
@@ -84,8 +105,10 @@ export {
|
|
|
84
105
|
LnPayState,
|
|
85
106
|
LnReceiveState,
|
|
86
107
|
CreateBolt11Response,
|
|
108
|
+
GatewayInfo,
|
|
87
109
|
StreamError,
|
|
88
110
|
StreamSuccess,
|
|
89
111
|
StreamResult,
|
|
90
112
|
ModuleKind,
|
|
113
|
+
CancelFunction,
|
|
91
114
|
}
|
package/src/worker.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// import { WasmClient } from '../wasm/fedimint_client_wasm.js'
|
|
2
|
+
// import { WasmClient } from 'fedimint-client-wasm'
|
|
3
|
+
// import wasm from '../wasm/fedimint_client_wasm_bg.wasm'
|
|
4
|
+
|
|
5
|
+
let WasmClient = null
|
|
6
|
+
let client = null
|
|
7
|
+
|
|
8
|
+
const streamCancelMap = new Map()
|
|
9
|
+
|
|
10
|
+
const handleFree = (requestId) => {
|
|
11
|
+
streamCancelMap.delete(requestId)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
self.onmessage = async (event) => {
|
|
15
|
+
const { type, payload, requestId } = event.data
|
|
16
|
+
|
|
17
|
+
if (type === 'init') {
|
|
18
|
+
WasmClient = (await import('fedimint-client-wasm')).WasmClient
|
|
19
|
+
self.postMessage({ type: 'initialized', data: {}, requestId })
|
|
20
|
+
} else if (type === 'open') {
|
|
21
|
+
const { clientName } = payload
|
|
22
|
+
client = (await WasmClient.open(clientName)) || null
|
|
23
|
+
self.postMessage({
|
|
24
|
+
type: 'open',
|
|
25
|
+
data: { success: !!client },
|
|
26
|
+
requestId,
|
|
27
|
+
})
|
|
28
|
+
} else if (type === 'join') {
|
|
29
|
+
const { inviteCode, clientName: joinClientName } = payload
|
|
30
|
+
try {
|
|
31
|
+
client = await WasmClient.join_federation(joinClientName, inviteCode)
|
|
32
|
+
self.postMessage({
|
|
33
|
+
type: 'join',
|
|
34
|
+
data: { success: !!client },
|
|
35
|
+
requestId,
|
|
36
|
+
})
|
|
37
|
+
} catch (e) {
|
|
38
|
+
self.postMessage({ type: 'error', error: e.message, requestId })
|
|
39
|
+
}
|
|
40
|
+
} else if (type === 'rpc') {
|
|
41
|
+
const { module, method, body } = payload
|
|
42
|
+
if (!client) {
|
|
43
|
+
self.postMessage({
|
|
44
|
+
type: 'error',
|
|
45
|
+
error: 'WasmClient not initialized',
|
|
46
|
+
requestId,
|
|
47
|
+
})
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
const rpcHandle = await client.rpc(
|
|
51
|
+
module,
|
|
52
|
+
method,
|
|
53
|
+
JSON.stringify(body),
|
|
54
|
+
(res) => {
|
|
55
|
+
const data = JSON.parse(res)
|
|
56
|
+
self.postMessage({ type: 'rpcResponse', requestId, ...data })
|
|
57
|
+
|
|
58
|
+
if (data.end === undefined) return
|
|
59
|
+
|
|
60
|
+
// Handle stream ending
|
|
61
|
+
const handle = streamCancelMap.get(requestId)
|
|
62
|
+
handle?.free()
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
streamCancelMap.set(requestId, rpcHandle)
|
|
66
|
+
} else if (type === 'unsubscribe') {
|
|
67
|
+
const rpcHandle = streamCancelMap.get(requestId)
|
|
68
|
+
if (rpcHandle) {
|
|
69
|
+
rpcHandle.cancel()
|
|
70
|
+
rpcHandle.free()
|
|
71
|
+
streamCancelMap.delete(requestId)
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
self.postMessage({
|
|
75
|
+
type: 'error',
|
|
76
|
+
error: 'Unknown message type',
|
|
77
|
+
requestId,
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
}
|