@fedimint/core-web 0.0.2 → 0.0.4
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 +40 -33
- package/dist/FedimintWallet.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/BalanceService.d.ts +8 -0
- package/dist/services/BalanceService.d.ts.map +1 -0
- package/dist/services/FederationService.d.ts +12 -0
- package/dist/services/FederationService.d.ts.map +1 -0
- package/dist/services/LightningService.d.ts +17 -0
- package/dist/services/LightningService.d.ts.map +1 -0
- package/dist/services/MintService.d.ts +15 -0
- package/dist/services/MintService.d.ts.map +1 -0
- package/dist/services/RecoveryService.d.ts +13 -0
- package/dist/services/RecoveryService.d.ts.map +1 -0
- package/dist/services/index.d.ts +6 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/types/wallet.d.ts +19 -3
- package/dist/types/wallet.d.ts.map +1 -1
- package/dist/worker/WorkerClient.d.ts +41 -0
- package/dist/worker/WorkerClient.d.ts.map +1 -0
- package/dist/worker/index.d.ts +2 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker.js +2 -0
- package/dist/worker.js.map +1 -0
- package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm.d.ts +49 -0
- package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm.js +4 -0
- package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm_bg.js +1411 -0
- package/{wasm → node_modules/@fedimint/fedimint-client-wasm}/fedimint_client_wasm_bg.wasm +0 -0
- package/node_modules/@fedimint/fedimint-client-wasm/package.json +23 -0
- package/package.json +12 -5
- package/src/FedimintWallet.test.ts +74 -0
- package/src/FedimintWallet.ts +88 -342
- package/src/services/BalanceService.ts +24 -0
- package/src/services/FederationService.ts +32 -0
- package/src/services/LightningService.ts +128 -0
- package/src/services/MintService.ts +93 -0
- package/src/services/RecoveryService.ts +26 -0
- package/src/services/index.ts +5 -0
- package/src/types/wallet.ts +25 -2
- package/src/worker/WorkerClient.ts +190 -0
- package/src/worker/index.ts +1 -0
- package/src/worker/worker.js +85 -0
- package/dist/assets/fedimint_client_wasm_bg-DxOUItb-.wasm +0 -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
- package/wasm/fedimint_client_wasm.d.ts +0 -104
- package/wasm/fedimint_client_wasm.js +0 -1120
- package/wasm/fedimint_client_wasm_bg.js +0 -873
- package/wasm/fedimint_client_wasm_bg.wasm.d.ts +0 -34
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fedimint/fedimint-client-wasm",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Wasm-pack output for fedimint-client-wasm",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/fedimint/fedimint"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"fedimint_client_wasm_bg.wasm",
|
|
13
|
+
"fedimint_client_wasm.js",
|
|
14
|
+
"fedimint_client_wasm_bg.js",
|
|
15
|
+
"fedimint_client_wasm.d.ts"
|
|
16
|
+
],
|
|
17
|
+
"main": "fedimint_client_wasm.js",
|
|
18
|
+
"types": "fedimint_client_wasm.d.ts",
|
|
19
|
+
"sideEffects": [
|
|
20
|
+
"./fedimint_client_wasm.js",
|
|
21
|
+
"./snippets/*"
|
|
22
|
+
]
|
|
23
|
+
}
|
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.4",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/fedimint/fedimint-web-sdk.git",
|
|
@@ -9,20 +9,27 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
|
-
"wasm",
|
|
13
12
|
"src"
|
|
14
13
|
],
|
|
15
|
-
"sideEffects":
|
|
14
|
+
"sideEffects": [
|
|
15
|
+
"./dist/worker.js",
|
|
16
|
+
"./dist/index.js"
|
|
17
|
+
],
|
|
16
18
|
"type": "module",
|
|
17
19
|
"main": "./dist/index.js",
|
|
18
20
|
"types": "./dist/index.d.ts",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@fedimint/fedimint-client-wasm": "file:./wasm"
|
|
23
|
+
},
|
|
24
|
+
"bundleDependencies": [
|
|
25
|
+
"@fedimint/fedimint-client-wasm"
|
|
26
|
+
],
|
|
19
27
|
"devDependencies": {
|
|
20
28
|
"@rollup/plugin-terser": "^0.4.4",
|
|
21
29
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
22
|
-
"@rollup/plugin-wasm": "^6.2.2",
|
|
23
30
|
"@types/node": "^20.14.8",
|
|
24
|
-
"@web/rollup-plugin-import-meta-assets": "^2.2.1",
|
|
25
31
|
"rollup": "^4.21.2",
|
|
32
|
+
"rollup-plugin-typescript2": "^0.36.0",
|
|
26
33
|
"tslib": "^2.7.0",
|
|
27
34
|
"typescript": "^5.2.2"
|
|
28
35
|
},
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { test, expect, vi } from 'vitest'
|
|
2
|
+
import { FedimintWallet } from './FedimintWallet'
|
|
3
|
+
import { beforeAll } from 'vitest'
|
|
4
|
+
|
|
5
|
+
let randomTestingId: string
|
|
6
|
+
let wallet: FedimintWallet
|
|
7
|
+
// Testnet
|
|
8
|
+
const TESTING_FEDERATION =
|
|
9
|
+
'fed11qgqrgvnhwden5te0v9k8q6rp9ekh2arfdeukuet595cr2ttpd3jhq6rzve6zuer9wchxvetyd938gcewvdhk6tcqqysptkuvknc7erjgf4em3zfh90kffqf9srujn6q53d6r056e4apze5cw27h75'
|
|
10
|
+
|
|
11
|
+
beforeAll(() => {
|
|
12
|
+
randomTestingId = Math.random().toString(36).substring(2, 15)
|
|
13
|
+
wallet = new FedimintWallet()
|
|
14
|
+
expect(wallet).toBeDefined()
|
|
15
|
+
|
|
16
|
+
// Cleanup after all tests
|
|
17
|
+
return async () => {
|
|
18
|
+
// clear up browser resources
|
|
19
|
+
await wallet.cleanup()
|
|
20
|
+
// remove the wallet db
|
|
21
|
+
indexedDB.deleteDatabase(randomTestingId)
|
|
22
|
+
// swap out the randomTestingId for a new one, to avoid raciness
|
|
23
|
+
randomTestingId = Math.random().toString(36).substring(2, 15)
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('initial open & join', async () => {
|
|
28
|
+
expect(wallet).toBeDefined()
|
|
29
|
+
expect(wallet.isOpen()).toBe(false)
|
|
30
|
+
// On initial open, it should return false
|
|
31
|
+
// because no federations have been joined
|
|
32
|
+
await expect(wallet.open(randomTestingId)).resolves.toBe(false)
|
|
33
|
+
await expect(
|
|
34
|
+
wallet.joinFederation(TESTING_FEDERATION, randomTestingId),
|
|
35
|
+
).resolves.toBeUndefined()
|
|
36
|
+
expect(wallet.isOpen()).toBe(true)
|
|
37
|
+
await expect(wallet.waitForOpen()).resolves.toBeUndefined()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('Error on open & join if wallet is already open', async () => {
|
|
41
|
+
expect(wallet).toBeDefined()
|
|
42
|
+
expect(wallet.isOpen()).toBe(true)
|
|
43
|
+
|
|
44
|
+
// Test opening an already open wallet
|
|
45
|
+
try {
|
|
46
|
+
await wallet.open(randomTestingId)
|
|
47
|
+
} catch (error) {
|
|
48
|
+
expect(error).toBeInstanceOf(Error)
|
|
49
|
+
expect((error as Error).message).toBe('The FedimintWallet is already open.')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Test joining federation on an already open wallet
|
|
53
|
+
try {
|
|
54
|
+
await wallet.joinFederation(TESTING_FEDERATION, randomTestingId)
|
|
55
|
+
} catch (error) {
|
|
56
|
+
expect(error).toBeInstanceOf(Error)
|
|
57
|
+
expect((error as Error).message).toBe(
|
|
58
|
+
'The FedimintWallet is already open. You can only call `joinFederation` on closed clients.',
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
test('getConfig', async () => {
|
|
63
|
+
expect(wallet).toBeDefined()
|
|
64
|
+
expect(wallet.isOpen()).toBe(true)
|
|
65
|
+
const config = await wallet.federation.getConfig()
|
|
66
|
+
expect(config).toBeDefined()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('empty getBalance', async () => {
|
|
70
|
+
expect(wallet).toBeDefined()
|
|
71
|
+
expect(wallet.isOpen()).toBe(true)
|
|
72
|
+
await expect(wallet.waitForOpen()).resolves.toBeUndefined()
|
|
73
|
+
await expect(wallet.balance.getBalance()).resolves.toEqual(0)
|
|
74
|
+
})
|
package/src/FedimintWallet.ts
CHANGED
|
@@ -1,381 +1,127 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { WorkerClient } from './worker/WorkerClient'
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
StreamResult,
|
|
10
|
-
StreamError,
|
|
11
|
-
CreateBolt11Response,
|
|
12
|
-
ModuleKind,
|
|
13
|
-
} from './types/wallet.js'
|
|
3
|
+
BalanceService,
|
|
4
|
+
MintService,
|
|
5
|
+
LightningService,
|
|
6
|
+
FederationService,
|
|
7
|
+
RecoveryService,
|
|
8
|
+
} from './services'
|
|
14
9
|
|
|
15
10
|
const DEFAULT_CLIENT_NAME = 'fm-default' as const
|
|
16
11
|
|
|
17
12
|
export class FedimintWallet {
|
|
18
|
-
private
|
|
19
|
-
|
|
13
|
+
private client: WorkerClient
|
|
14
|
+
|
|
15
|
+
public balance: BalanceService
|
|
16
|
+
public mint: MintService
|
|
17
|
+
public lightning: LightningService
|
|
18
|
+
public federation: FederationService
|
|
19
|
+
public recovery: RecoveryService
|
|
20
|
+
|
|
20
21
|
private openPromise: Promise<void> | null = null
|
|
21
22
|
private resolveOpen: () => void = () => {}
|
|
23
|
+
private _isOpen: boolean = false
|
|
22
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Creates a new instance of FedimintWallet.
|
|
27
|
+
*
|
|
28
|
+
* @description
|
|
29
|
+
* This constructor initializes a FedimintWallet instance, which manages communication
|
|
30
|
+
* with a Web Worker. The Web Worker is responsible for running WebAssembly code that
|
|
31
|
+
* handles the core Fedimint Client operations.
|
|
32
|
+
*
|
|
33
|
+
* (default) When not in lazy mode, the constructor immediately initializes the
|
|
34
|
+
* Web Worker and begins loading the WebAssembly module in the background. This
|
|
35
|
+
* allows for faster subsequent operations but may increase initial load time.
|
|
36
|
+
*
|
|
37
|
+
* In lazy mode, the Web Worker and WebAssembly initialization are deferred until
|
|
38
|
+
* the first operation that requires them, reducing initial overhead at the cost
|
|
39
|
+
* of a slight delay on the first operation.
|
|
40
|
+
*
|
|
41
|
+
* @param {boolean} lazy - If true, delays Web Worker and WebAssembly initialization
|
|
42
|
+
* until needed. Default is false.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // Create a wallet with immediate initialization
|
|
46
|
+
* const wallet = new FedimintWallet();
|
|
47
|
+
* wallet.open();
|
|
48
|
+
*
|
|
49
|
+
* // Create a wallet with lazy initialization
|
|
50
|
+
* const lazyWallet = new FedimintWallet(true);
|
|
51
|
+
* // Some time later...
|
|
52
|
+
* lazyWallet.initialize();
|
|
53
|
+
* lazyWallet.open();
|
|
54
|
+
*/
|
|
23
55
|
constructor(lazy: boolean = false) {
|
|
24
|
-
if (lazy) return
|
|
25
|
-
this.initialize()
|
|
26
56
|
this.openPromise = new Promise((resolve) => {
|
|
27
57
|
this.resolveOpen = resolve
|
|
28
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)
|
|
65
|
+
|
|
66
|
+
if (!lazy) {
|
|
67
|
+
this.initialize()
|
|
68
|
+
}
|
|
29
69
|
}
|
|
30
70
|
|
|
31
|
-
// Setup
|
|
32
71
|
async initialize() {
|
|
33
|
-
|
|
34
|
-
// this.worker = new Worker(new URL('./wasm.worker.ts', import.meta.url))
|
|
35
|
-
this.initPromise = init().then(() => {
|
|
36
|
-
console.trace('Fedimint Client Wasm Initialization complete')
|
|
37
|
-
})
|
|
38
|
-
return this.initPromise
|
|
72
|
+
await this.client.initialize()
|
|
39
73
|
}
|
|
40
74
|
|
|
41
|
-
async
|
|
42
|
-
|
|
43
|
-
|
|
75
|
+
async waitForOpen() {
|
|
76
|
+
if (this._isOpen) return Promise.resolve()
|
|
77
|
+
return this.openPromise
|
|
78
|
+
}
|
|
44
79
|
|
|
45
|
-
|
|
46
|
-
this.
|
|
47
|
-
this
|
|
48
|
-
|
|
80
|
+
async open(clientName: string = DEFAULT_CLIENT_NAME) {
|
|
81
|
+
await this.client.initialize()
|
|
82
|
+
// TODO: Determine if this should be safe or throw
|
|
83
|
+
if (this._isOpen) throw new Error('The FedimintWallet is already open.')
|
|
84
|
+
const { success } = await this.client.sendSingleMessage('open', {
|
|
85
|
+
clientName,
|
|
86
|
+
})
|
|
87
|
+
if (success) {
|
|
88
|
+
this._isOpen = !!success
|
|
89
|
+
this.resolveOpen()
|
|
90
|
+
}
|
|
91
|
+
return success
|
|
49
92
|
}
|
|
50
93
|
|
|
51
94
|
async joinFederation(
|
|
52
95
|
inviteCode: string,
|
|
53
96
|
clientName: string = DEFAULT_CLIENT_NAME,
|
|
54
97
|
) {
|
|
55
|
-
await this.initialize()
|
|
56
|
-
this
|
|
57
|
-
this.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
>(
|
|
65
|
-
module: ModuleKind,
|
|
66
|
-
method: string,
|
|
67
|
-
body: Body,
|
|
68
|
-
onSuccess: (res: Response) => void,
|
|
69
|
-
onError: (res: StreamError['error']) => void,
|
|
70
|
-
): Promise<RpcHandle> {
|
|
71
|
-
await this.openPromise
|
|
72
|
-
if (!this._fed) throw new Error('FedimintWallet is not open')
|
|
73
|
-
const unsubscribe = await this._fed.rpc(
|
|
74
|
-
module,
|
|
75
|
-
method,
|
|
76
|
-
JSON.stringify(body),
|
|
77
|
-
(res: string) => {
|
|
78
|
-
// TODO: Validate the response?
|
|
79
|
-
const parsed = JSON.parse(res) as StreamResult<Response>
|
|
80
|
-
if (parsed.error) {
|
|
81
|
-
onError(parsed.error)
|
|
82
|
-
} else {
|
|
83
|
-
onSuccess(parsed.data)
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
)
|
|
87
|
-
return unsubscribe
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private async _rpcSingle<Response extends JSONValue = JSONValue>(
|
|
91
|
-
module: ModuleKind,
|
|
92
|
-
method: string,
|
|
93
|
-
body: JSONValue,
|
|
94
|
-
): Promise<Response> {
|
|
95
|
-
return new Promise((resolve, reject) => {
|
|
96
|
-
if (!this._fed) return reject('FedimintWallet is not open')
|
|
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
|
-
})
|
|
106
|
-
})
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async getBalance(): Promise<number> {
|
|
110
|
-
return await this._rpcSingle('', 'get_balance', {})
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Mint module methods
|
|
114
|
-
|
|
115
|
-
async redeemEcash(notes: string): Promise<void> {
|
|
116
|
-
await this._rpcSingle('mint', 'reissue_external_notes', {
|
|
117
|
-
oob_notes: notes, // "out of band notes"
|
|
118
|
-
extra_meta: null,
|
|
119
|
-
})
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async reissueExternalNotes(
|
|
123
|
-
oobNotes: string,
|
|
124
|
-
extraMeta: JSONObject,
|
|
125
|
-
): Promise<string> {
|
|
126
|
-
return await this._rpcSingle('mint', 'reissue_external_notes', {
|
|
127
|
-
oob_notes: oobNotes,
|
|
128
|
-
extra_meta: extraMeta,
|
|
98
|
+
await this.client.initialize()
|
|
99
|
+
// TODO: Determine if this should be safe or throw
|
|
100
|
+
if (this._isOpen)
|
|
101
|
+
throw new Error(
|
|
102
|
+
'The FedimintWallet is already open. You can only call `joinFederation` on closed clients.',
|
|
103
|
+
)
|
|
104
|
+
const response = await this.client.sendSingleMessage('join', {
|
|
105
|
+
inviteCode,
|
|
106
|
+
clientName,
|
|
129
107
|
})
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
operationId: string,
|
|
134
|
-
onSuccess: (state: JSONValue) => void = () => {},
|
|
135
|
-
onError: (error: string) => void = () => {},
|
|
136
|
-
) {
|
|
137
|
-
type ReissueExternalNotesState =
|
|
138
|
-
| 'Created'
|
|
139
|
-
| 'Issuing'
|
|
140
|
-
| 'Done'
|
|
141
|
-
| { Failed: { error: string } }
|
|
142
|
-
|
|
143
|
-
const unsubscribe = this._rpcStream<ReissueExternalNotesState>(
|
|
144
|
-
'mint',
|
|
145
|
-
'subscribe_reissue_external_notes',
|
|
146
|
-
{ operation_id: operationId },
|
|
147
|
-
(res) => onSuccess(res),
|
|
148
|
-
onError,
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
return () => {
|
|
152
|
-
unsubscribe.then((unsub) => {
|
|
153
|
-
unsub.cancel()
|
|
154
|
-
unsub.free()
|
|
155
|
-
})
|
|
108
|
+
if (response.success) {
|
|
109
|
+
this._isOpen = true
|
|
110
|
+
this.resolveOpen()
|
|
156
111
|
}
|
|
157
112
|
}
|
|
158
113
|
|
|
159
|
-
async spendNotes(
|
|
160
|
-
minAmount: number,
|
|
161
|
-
tryCancelAfter: number,
|
|
162
|
-
includeInvite: boolean,
|
|
163
|
-
extraMeta: JSONValue,
|
|
164
|
-
): Promise<JSONValue> {
|
|
165
|
-
return await this._rpcSingle('mint', 'spend_notes', {
|
|
166
|
-
min_amount: minAmount,
|
|
167
|
-
try_cancel_after: tryCancelAfter,
|
|
168
|
-
include_invite: includeInvite,
|
|
169
|
-
extra_meta: extraMeta,
|
|
170
|
-
})
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
async validateNotes(oobNotes: string): Promise<number> {
|
|
174
|
-
return await this._rpcSingle('mint', 'validate_notes', {
|
|
175
|
-
oob_notes: oobNotes,
|
|
176
|
-
})
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async tryCancelSpendNotes(operationId: string): Promise<void> {
|
|
180
|
-
await this._rpcSingle('mint', 'try_cancel_spend_notes', {
|
|
181
|
-
operation_id: operationId,
|
|
182
|
-
})
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
subscribeSpendNotes(
|
|
186
|
-
operationId: string,
|
|
187
|
-
onSuccess: (state: JSONValue) => void = () => {},
|
|
188
|
-
onError: (error: string) => void = () => {},
|
|
189
|
-
) {
|
|
190
|
-
const unsubscribe = this._rpcStream(
|
|
191
|
-
'mint',
|
|
192
|
-
'subscribe_spend_notes',
|
|
193
|
-
{ operation_id: operationId },
|
|
194
|
-
(res) => onSuccess(res),
|
|
195
|
-
onError,
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
return () => {
|
|
199
|
-
unsubscribe.then((unsub) => {
|
|
200
|
-
unsub.cancel()
|
|
201
|
-
unsub.free()
|
|
202
|
-
})
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async awaitSpendOobRefund(operationId: string): Promise<JSONValue> {
|
|
207
|
-
return await this._rpcSingle('mint', 'await_spend_oob_refund', {
|
|
208
|
-
operation_id: operationId,
|
|
209
|
-
})
|
|
210
|
-
}
|
|
211
|
-
|
|
212
114
|
/**
|
|
213
115
|
* This should ONLY be called when UNLOADING the wallet client.
|
|
214
116
|
* After this call, the FedimintWallet instance should be discarded.
|
|
215
117
|
*/
|
|
216
118
|
async cleanup() {
|
|
217
|
-
await this._fed?.free()
|
|
218
|
-
this._fed = null
|
|
219
119
|
this.openPromise = null
|
|
120
|
+
this._isOpen = false
|
|
121
|
+
this.client.cleanup()
|
|
220
122
|
}
|
|
221
123
|
|
|
222
124
|
isOpen() {
|
|
223
|
-
return this.
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
async getConfig(): Promise<JSONValue> {
|
|
227
|
-
return await this._rpcSingle('', 'get_config', {})
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
async getFederationId(): Promise<string> {
|
|
231
|
-
return await this._rpcSingle('', 'get_federation_id', {})
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async getInviteCode(peer: number): Promise<string | null> {
|
|
235
|
-
return await this._rpcSingle('', 'get_invite_code', { peer })
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
async listOperations(): Promise<JSONValue[]> {
|
|
239
|
-
return await this._rpcSingle('', 'list_operations', {})
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
async hasPendingRecoveries(): Promise<boolean> {
|
|
243
|
-
return await this._rpcSingle('', 'has_pending_recoveries', {})
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async waitForAllRecoveries(): Promise<void> {
|
|
247
|
-
await this._rpcSingle('', 'wait_for_all_recoveries', {})
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/// STREAMING RPCs --------------------
|
|
251
|
-
|
|
252
|
-
subscribeBalance(
|
|
253
|
-
onSuccess: (balance: number) => void = () => {},
|
|
254
|
-
onError: (error: string) => void = () => {},
|
|
255
|
-
) {
|
|
256
|
-
const unsubscribe = this._rpcStream<string>(
|
|
257
|
-
'',
|
|
258
|
-
'subscribe_balance_changes',
|
|
259
|
-
{},
|
|
260
|
-
(res) => onSuccess(parseInt(res)),
|
|
261
|
-
onError,
|
|
262
|
-
)
|
|
263
|
-
|
|
264
|
-
return () => {
|
|
265
|
-
unsubscribe.then((unsub) => {
|
|
266
|
-
unsub.cancel()
|
|
267
|
-
unsub.free()
|
|
268
|
-
})
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
subscribeToRecoveryProgress(
|
|
273
|
-
onSuccess: (progress: {
|
|
274
|
-
module_id: number
|
|
275
|
-
progress: JSONValue
|
|
276
|
-
}) => void = () => {},
|
|
277
|
-
onError: (error: string) => void = () => {},
|
|
278
|
-
) {
|
|
279
|
-
const unsubscribe = this._rpcStream<{
|
|
280
|
-
module_id: number
|
|
281
|
-
progress: JSONValue
|
|
282
|
-
}>('', 'subscribe_to_recovery_progress', {}, onSuccess, onError)
|
|
283
|
-
|
|
284
|
-
return () => {
|
|
285
|
-
unsubscribe.then((unsub) => {
|
|
286
|
-
unsub.cancel()
|
|
287
|
-
unsub.free()
|
|
288
|
-
})
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Lightning Network module methods
|
|
293
|
-
|
|
294
|
-
async createBolt11Invoice(
|
|
295
|
-
amount: number,
|
|
296
|
-
description: string,
|
|
297
|
-
expiryTime: number | null = null,
|
|
298
|
-
extraMeta: JSONObject = {},
|
|
299
|
-
gateway: LightningGateway | null = null,
|
|
300
|
-
): Promise<CreateBolt11Response> {
|
|
301
|
-
return await this._rpcSingle('ln', 'create_bolt11_invoice', {
|
|
302
|
-
amount,
|
|
303
|
-
description,
|
|
304
|
-
expiry_time: expiryTime,
|
|
305
|
-
extra_meta: extraMeta,
|
|
306
|
-
gateway,
|
|
307
|
-
})
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
async payBolt11Invoice(
|
|
311
|
-
invoice: string,
|
|
312
|
-
maybeGateway: LightningGateway | null = null,
|
|
313
|
-
extraMeta: JSONObject = {},
|
|
314
|
-
): Promise<OutgoingLightningPayment> {
|
|
315
|
-
return await this._rpcSingle('ln', 'pay_bolt11_invoice', {
|
|
316
|
-
maybe_gateway: maybeGateway,
|
|
317
|
-
invoice,
|
|
318
|
-
extra_meta: extraMeta,
|
|
319
|
-
})
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
subscribeLnPay(
|
|
323
|
-
operationId: string,
|
|
324
|
-
onSuccess: (state: LnPayState) => void = () => {},
|
|
325
|
-
onError: (error: string) => void = () => {},
|
|
326
|
-
) {
|
|
327
|
-
const unsubscribe = this._rpcStream(
|
|
328
|
-
'ln',
|
|
329
|
-
'subscribe_ln_pay',
|
|
330
|
-
{ operation_id: operationId },
|
|
331
|
-
onSuccess,
|
|
332
|
-
onError,
|
|
333
|
-
)
|
|
334
|
-
|
|
335
|
-
return () => {
|
|
336
|
-
unsubscribe.then((unsub) => {
|
|
337
|
-
unsub.cancel()
|
|
338
|
-
unsub.free()
|
|
339
|
-
})
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
subscribeLnReceive(
|
|
344
|
-
operationId: string,
|
|
345
|
-
onSuccess: (state: LnReceiveState) => void = () => {},
|
|
346
|
-
onError: (error: string) => void = () => {},
|
|
347
|
-
) {
|
|
348
|
-
const unsubscribe = this._rpcStream(
|
|
349
|
-
'ln',
|
|
350
|
-
'subscribe_ln_receive',
|
|
351
|
-
{ operation_id: operationId },
|
|
352
|
-
onSuccess,
|
|
353
|
-
onError,
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
return () => {
|
|
357
|
-
unsubscribe.then((unsub) => {
|
|
358
|
-
unsub.cancel()
|
|
359
|
-
unsub.free()
|
|
360
|
-
})
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
async getGateway(
|
|
365
|
-
gatewayId: string | null = null,
|
|
366
|
-
forceInternal: boolean = false,
|
|
367
|
-
): Promise<LightningGateway | null> {
|
|
368
|
-
return await this._rpcSingle('ln', 'get_gateway', {
|
|
369
|
-
gateway_id: gatewayId,
|
|
370
|
-
force_internal: forceInternal,
|
|
371
|
-
})
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
async listGateways(): Promise<LightningGateway[]> {
|
|
375
|
-
return await this._rpcSingle('ln', 'list_gateways', {})
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
async updateGatewayCache(): Promise<void> {
|
|
379
|
-
await this._rpcSingle('ln', 'update_gateway_cache', {})
|
|
125
|
+
return this._isOpen
|
|
380
126
|
}
|
|
381
127
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { WorkerClient } from '../worker'
|
|
2
|
+
|
|
3
|
+
export class BalanceService {
|
|
4
|
+
constructor(private client: WorkerClient) {}
|
|
5
|
+
|
|
6
|
+
async getBalance(): Promise<number> {
|
|
7
|
+
return await this.client.rpcSingle('', 'get_balance', {})
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
subscribeBalance(
|
|
11
|
+
onSuccess: (balance: number) => void = () => {},
|
|
12
|
+
onError: (error: string) => void = () => {},
|
|
13
|
+
) {
|
|
14
|
+
const unsubscribe = this.client.rpcStream<string>(
|
|
15
|
+
'',
|
|
16
|
+
'subscribe_balance_changes',
|
|
17
|
+
{},
|
|
18
|
+
(res) => onSuccess(parseInt(res)),
|
|
19
|
+
onError,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
return unsubscribe
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
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 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
|
+
async listOperations(): Promise<JSONValue[]> {
|
|
30
|
+
return await this.client.rpcSingle('', 'list_operations', {})
|
|
31
|
+
}
|
|
32
|
+
}
|