@fedimint/core-web 0.0.0-canary-20240910231647
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 +38 -0
- package/package.json +29 -0
- package/src/FedimintWallet.ts +163 -0
- package/src/index.ts +3 -0
- package/src/vite-env.d.ts +1 -0
- package/src/wasm.worker.ts +41 -0
- package/wasm/fedimint_client_wasm.d.ts +104 -0
- package/wasm/fedimint_client_wasm.js +1120 -0
- package/wasm/fedimint_client_wasm_bg.js +873 -0
- package/wasm/fedimint_client_wasm_bg.wasm +0 -0
- package/wasm/fedimint_client_wasm_bg.wasm.d.ts +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @fedimint/core-web
|
|
2
|
+
|
|
3
|
+
### THIS IS A WORK IN PROGRESS AND NOT READY FOR USE
|
|
4
|
+
|
|
5
|
+
This package provides a typescript interface for the Fedimint client in the browser
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @fedimint/core-web
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { FedimintWallet } from '@fedimint/core-web'
|
|
17
|
+
|
|
18
|
+
// federation invite code
|
|
19
|
+
const inviteCode = 'fed11qgqpw9thwvaz7t...'
|
|
20
|
+
|
|
21
|
+
// This should be called only once
|
|
22
|
+
await FedimintWallet.initFedimint()
|
|
23
|
+
|
|
24
|
+
const wallet = await FedimintWallet.joinFederation(inviteCode)
|
|
25
|
+
|
|
26
|
+
// Get Wallet Balance
|
|
27
|
+
const balance = await wallet.getBalance()
|
|
28
|
+
|
|
29
|
+
// Receive Ecash Payments
|
|
30
|
+
await wallet.reissueNotes('A11qgqpw9thwvaz7t...')
|
|
31
|
+
|
|
32
|
+
// Pay Lightning Invoice
|
|
33
|
+
await wallet.payInvoice('lnbc...')
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Check out the example
|
|
37
|
+
|
|
38
|
+
[`examples/vite-core`](../examples/vite-core/README.md)
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fedimint/core-web",
|
|
3
|
+
"description": "Library for building web apps with a fedimint client",
|
|
4
|
+
"version": "0.0.0-canary-20240910231647",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/fedimint/fedimint-web-sdk.git",
|
|
8
|
+
"directory": "packages/core-web"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"wasm",
|
|
13
|
+
"src"
|
|
14
|
+
],
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^20.14.8",
|
|
21
|
+
"typescript": "^5.2.2"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "pnpm run clean && tsc --project tsconfig.json",
|
|
25
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
26
|
+
"clean:deep": "pnpm run clean && rm -rf node_modules",
|
|
27
|
+
"typecheck": "tsc --noEmit"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import init, { RpcHandle, WasmClient } from '../wasm/fedimint_client_wasm.js'
|
|
2
|
+
|
|
3
|
+
type StreamError = {
|
|
4
|
+
error: string
|
|
5
|
+
data: never
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type StreamSuccess = {
|
|
9
|
+
data: {} | [] | null | undefined | number | string | boolean
|
|
10
|
+
error: never
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type StreamResult = StreamSuccess | StreamError
|
|
14
|
+
|
|
15
|
+
type Body = string | null | Record<string, string | null>
|
|
16
|
+
|
|
17
|
+
const DEFAULT_CLIENT_NAME = 'fm-default' as const
|
|
18
|
+
|
|
19
|
+
export class FedimintWallet {
|
|
20
|
+
private _fed: WasmClient | null = null
|
|
21
|
+
private initPromise: Promise<void> | null = null
|
|
22
|
+
private openPromise: Promise<void> | null = null
|
|
23
|
+
private resolveOpen: () => void = () => {}
|
|
24
|
+
|
|
25
|
+
constructor(lazy: boolean = false) {
|
|
26
|
+
if (lazy) return
|
|
27
|
+
this.initialize()
|
|
28
|
+
this.openPromise = new Promise((resolve) => {
|
|
29
|
+
this.resolveOpen = resolve
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Setup
|
|
34
|
+
async initialize() {
|
|
35
|
+
if (this.initPromise) return this.initPromise
|
|
36
|
+
// this.worker = new Worker(new URL('./wasm.worker.ts', import.meta.url))
|
|
37
|
+
this.initPromise = init().then(() => {
|
|
38
|
+
console.trace('Fedimint Client Wasm Initialization complete')
|
|
39
|
+
})
|
|
40
|
+
return this.initPromise
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async open(clientName: string = DEFAULT_CLIENT_NAME) {
|
|
44
|
+
await this.initialize()
|
|
45
|
+
const wasm = await WasmClient.open(clientName)
|
|
46
|
+
|
|
47
|
+
if (wasm === undefined) return false
|
|
48
|
+
this._fed = wasm
|
|
49
|
+
this.resolveOpen()
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async joinFederation(
|
|
54
|
+
inviteCode: string,
|
|
55
|
+
clientName: string = DEFAULT_CLIENT_NAME,
|
|
56
|
+
) {
|
|
57
|
+
await this.initialize()
|
|
58
|
+
this._fed = await WasmClient.join_federation(clientName, inviteCode)
|
|
59
|
+
this.resolveOpen()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// RPC
|
|
63
|
+
private async _rpcStream(
|
|
64
|
+
module: string,
|
|
65
|
+
method: string,
|
|
66
|
+
body: Body = {},
|
|
67
|
+
onSuccess: (res: StreamSuccess['data']) => void,
|
|
68
|
+
onError: (res: StreamError['error']) => void,
|
|
69
|
+
): Promise<RpcHandle> {
|
|
70
|
+
await this.openPromise
|
|
71
|
+
if (!this._fed) throw new Error('FedimintWallet is not open')
|
|
72
|
+
const unsubscribe = await this._fed.rpc(
|
|
73
|
+
module,
|
|
74
|
+
method,
|
|
75
|
+
JSON.stringify(body),
|
|
76
|
+
(res: string) => {
|
|
77
|
+
const parsed = JSON.parse(res) as StreamResult
|
|
78
|
+
if (parsed.error) {
|
|
79
|
+
onError(parsed.error)
|
|
80
|
+
} else {
|
|
81
|
+
onSuccess(parsed.data)
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
)
|
|
85
|
+
return unsubscribe
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private async _rpcSingle(module: string, method: string, body: Body = {}) {
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
if (!this._fed) return reject('FedimintWallet is not open')
|
|
91
|
+
this._fed.rpc(module, method, JSON.stringify(body), (res: string) => {
|
|
92
|
+
const parsed = JSON.parse(res) as StreamResult
|
|
93
|
+
if (parsed.error) {
|
|
94
|
+
reject(parsed.error)
|
|
95
|
+
} else {
|
|
96
|
+
resolve(parsed.data)
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Client
|
|
103
|
+
|
|
104
|
+
async getBalance(): Promise<number> {
|
|
105
|
+
return (await this._rpcSingle('', 'get_balance')) as number
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// LN
|
|
109
|
+
|
|
110
|
+
async payInvoice(invoice: string): Promise<void> {
|
|
111
|
+
await this._rpcSingle('ln', 'pay_bolt11_invoice', {
|
|
112
|
+
invoice,
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// async listGateways() {
|
|
117
|
+
// return await this._rpcSingle("ln", "list_gateways");
|
|
118
|
+
// }
|
|
119
|
+
//
|
|
120
|
+
// async verifyGateways() {
|
|
121
|
+
// return await this._rpcSingle("ln", "verify_gateway_availability");
|
|
122
|
+
// }
|
|
123
|
+
|
|
124
|
+
// Mint
|
|
125
|
+
|
|
126
|
+
async redeemEcash(notes: string): Promise<void> {
|
|
127
|
+
await this._rpcSingle('mint', 'reissue_external_notes', {
|
|
128
|
+
oob_notes: notes, // "out of band notes"
|
|
129
|
+
extra_meta: null,
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Teardown
|
|
134
|
+
async cleanup() {
|
|
135
|
+
await this._fed?.free()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
isOpen() {
|
|
139
|
+
return this._fed !== null
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Streaming
|
|
143
|
+
|
|
144
|
+
subscribeBalance(
|
|
145
|
+
onSuccess: (balance: number) => void = () => {},
|
|
146
|
+
onError: (error: string) => void = () => {},
|
|
147
|
+
) {
|
|
148
|
+
const unsubscribe = this._rpcStream(
|
|
149
|
+
'',
|
|
150
|
+
'subscribe_balance_changes',
|
|
151
|
+
{},
|
|
152
|
+
(res) => onSuccess(parseInt(res as string)),
|
|
153
|
+
onError,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return () => {
|
|
157
|
+
unsubscribe.then((unsub) => {
|
|
158
|
+
unsub.cancel()
|
|
159
|
+
unsub.free()
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// import init, { InitOutput, WasmClient } from '../wasm/fedimint_client_wasm.js'
|
|
2
|
+
|
|
3
|
+
// let client: WasmClient | undefined
|
|
4
|
+
|
|
5
|
+
// async function workerInit() {
|
|
6
|
+
// await init(new URL('@fedi/common/wasm/fedi_wasm_bg.wasm', import.meta.url))
|
|
7
|
+
// }
|
|
8
|
+
|
|
9
|
+
// const initPromise = workerInit().catch((error) =>
|
|
10
|
+
// postMessage({ error: String(error) }),
|
|
11
|
+
// )
|
|
12
|
+
|
|
13
|
+
// async function rpcRequest(method: string, data: string): Promise<string> {
|
|
14
|
+
// await initPromise
|
|
15
|
+
// return await fedimint_rpc(method, data)
|
|
16
|
+
// }
|
|
17
|
+
|
|
18
|
+
// const handleMessage = async (token: string, method: string, data: string) => {
|
|
19
|
+
// if (method === 'open') {
|
|
20
|
+
// await initPromise
|
|
21
|
+
// client = await WasmClient.open(data)
|
|
22
|
+
// if (client !== undefined) {
|
|
23
|
+
// postMessage({ token, result: true })
|
|
24
|
+
// } else {
|
|
25
|
+
// postMessage({ token, result: false })
|
|
26
|
+
// }
|
|
27
|
+
// } else if (method === 'join_federation') {
|
|
28
|
+
// await initPromise
|
|
29
|
+
// const result = await WasmClient.join_federation(data)
|
|
30
|
+
// postMessage({ token, result })
|
|
31
|
+
// }
|
|
32
|
+
// }
|
|
33
|
+
|
|
34
|
+
// // Handles worker.postMessage calls
|
|
35
|
+
// addEventListener('message', (e) => {
|
|
36
|
+
// const { token, method, data } = e.data
|
|
37
|
+
// handleMessage(token, method, data)
|
|
38
|
+
// // rpcRequest(method, data)
|
|
39
|
+
// // .then((result) => postMessage({ token, result }))
|
|
40
|
+
// // .catch((error) => postMessage({ error: String(error) }))
|
|
41
|
+
// })
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/**
|
|
4
|
+
*/
|
|
5
|
+
export class RpcHandle {
|
|
6
|
+
free(): void;
|
|
7
|
+
/**
|
|
8
|
+
*/
|
|
9
|
+
cancel(): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
*/
|
|
13
|
+
export class WasmClient {
|
|
14
|
+
free(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Open fedimint client with already joined federation.
|
|
17
|
+
*
|
|
18
|
+
* After you have joined a federation, you can reopen the fedimint client
|
|
19
|
+
* with same client_name. Opening client with same name at same time is
|
|
20
|
+
* not supported. You can close the current client by calling
|
|
21
|
+
* `client.free()`. NOTE: The client will remain active until all the
|
|
22
|
+
* running rpc calls have finished.
|
|
23
|
+
* @param {string} client_name
|
|
24
|
+
* @returns {Promise<WasmClient | undefined>}
|
|
25
|
+
*/
|
|
26
|
+
static open(client_name: string): Promise<WasmClient | undefined>;
|
|
27
|
+
/**
|
|
28
|
+
* Open a fedimint client by join a federation.
|
|
29
|
+
* @param {string} client_name
|
|
30
|
+
* @param {string} invite_code
|
|
31
|
+
* @returns {Promise<WasmClient>}
|
|
32
|
+
*/
|
|
33
|
+
static join_federation(client_name: string, invite_code: string): Promise<WasmClient>;
|
|
34
|
+
/**
|
|
35
|
+
* Call a fedimint client rpc the responses are returned using `cb`
|
|
36
|
+
* callback. Each rpc call *can* return multiple responses by calling
|
|
37
|
+
* `cb` multiple times. The returned RpcHandle can be used to cancel the
|
|
38
|
+
* operation.
|
|
39
|
+
* @param {string} module
|
|
40
|
+
* @param {string} method
|
|
41
|
+
* @param {string} payload
|
|
42
|
+
* @param {Function} cb
|
|
43
|
+
* @returns {RpcHandle}
|
|
44
|
+
*/
|
|
45
|
+
rpc(module: string, method: string, payload: string, cb: Function): RpcHandle;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
49
|
+
|
|
50
|
+
export interface InitOutput {
|
|
51
|
+
readonly memory: WebAssembly.Memory;
|
|
52
|
+
readonly __wbg_wasmclient_free: (a: number) => void;
|
|
53
|
+
readonly __wbg_rpchandle_free: (a: number) => void;
|
|
54
|
+
readonly rpchandle_cancel: (a: number) => void;
|
|
55
|
+
readonly wasmclient_open: (a: number, b: number) => number;
|
|
56
|
+
readonly wasmclient_join_federation: (a: number, b: number, c: number, d: number) => number;
|
|
57
|
+
readonly wasmclient_rpc: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => number;
|
|
58
|
+
readonly ring_core_0_17_8_bn_mul_mont: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
59
|
+
readonly rustsecp256k1zkp_v0_8_0_default_illegal_callback_fn: (a: number, b: number) => void;
|
|
60
|
+
readonly rustsecp256k1zkp_v0_8_0_default_error_callback_fn: (a: number, b: number) => void;
|
|
61
|
+
readonly rustsecp256k1_v0_6_1_context_create: (a: number) => number;
|
|
62
|
+
readonly rustsecp256k1_v0_6_1_context_destroy: (a: number) => void;
|
|
63
|
+
readonly rustsecp256k1_v0_6_1_default_illegal_callback_fn: (a: number, b: number) => void;
|
|
64
|
+
readonly rustsecp256k1_v0_6_1_default_error_callback_fn: (a: number, b: number) => void;
|
|
65
|
+
readonly rustsecp256k1_v0_8_1_context_create: (a: number) => number;
|
|
66
|
+
readonly rustsecp256k1_v0_8_1_context_destroy: (a: number) => void;
|
|
67
|
+
readonly rustsecp256k1_v0_8_1_default_illegal_callback_fn: (a: number, b: number) => void;
|
|
68
|
+
readonly rustsecp256k1_v0_8_1_default_error_callback_fn: (a: number, b: number) => void;
|
|
69
|
+
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
|
70
|
+
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
71
|
+
readonly __wbindgen_export_2: WebAssembly.Table;
|
|
72
|
+
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
73
|
+
readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h8697e16cd1c64495: (a: number, b: number, c: number, d: number) => void;
|
|
74
|
+
readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h31a94cc9a05d5ca0: (a: number, b: number, c: number) => void;
|
|
75
|
+
readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h4d11ec113460b95d: (a: number, b: number) => void;
|
|
76
|
+
readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__he7056307c6986185: (a: number, b: number, c: number, d: number) => void;
|
|
77
|
+
readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5b16159cdfa166b0: (a: number, b: number) => void;
|
|
78
|
+
readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hebf1bd391d12b3cb: (a: number, b: number, c: number) => void;
|
|
79
|
+
readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h09ee3e3abd173580: (a: number, b: number) => void;
|
|
80
|
+
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
81
|
+
readonly __wbindgen_exn_store: (a: number) => void;
|
|
82
|
+
readonly wasm_bindgen__convert__closures__invoke2_mut__h8bdaa9faeb7d5075: (a: number, b: number, c: number, d: number) => void;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
|
86
|
+
/**
|
|
87
|
+
* Instantiates the given `module`, which can either be bytes or
|
|
88
|
+
* a precompiled `WebAssembly.Module`.
|
|
89
|
+
*
|
|
90
|
+
* @param {SyncInitInput} module
|
|
91
|
+
*
|
|
92
|
+
* @returns {InitOutput}
|
|
93
|
+
*/
|
|
94
|
+
export function initSync(module: SyncInitInput): InitOutput;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
|
98
|
+
* for everything else, calls `WebAssembly.instantiate` directly.
|
|
99
|
+
*
|
|
100
|
+
* @param {InitInput | Promise<InitInput>} module_or_path
|
|
101
|
+
*
|
|
102
|
+
* @returns {Promise<InitOutput>}
|
|
103
|
+
*/
|
|
104
|
+
export default function __wbg_init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;
|