@kaleidorg/wallet-engine 1.0.0-beta.4 → 1.0.0-beta.42
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 +29 -10
- package/dist/adapters/ArkadeAdapter.d.ts +78 -14
- package/dist/adapters/ArkadeAdapter.d.ts.map +1 -1
- package/dist/adapters/ArkadeAdapter.js +653 -161
- package/dist/adapters/ArkadeAdapter.js.map +1 -1
- package/dist/adapters/IProtocolAdapter.d.ts +195 -18
- package/dist/adapters/IProtocolAdapter.d.ts.map +1 -1
- package/dist/adapters/IProtocolAdapter.js +6 -2
- package/dist/adapters/IProtocolAdapter.js.map +1 -1
- package/dist/adapters/RgbAdapter.d.ts +70 -27
- package/dist/adapters/RgbAdapter.d.ts.map +1 -1
- package/dist/adapters/RgbAdapter.js +464 -370
- package/dist/adapters/RgbAdapter.js.map +1 -1
- package/dist/adapters/SparkAdapter.d.ts +93 -15
- package/dist/adapters/SparkAdapter.d.ts.map +1 -1
- package/dist/adapters/SparkAdapter.js +833 -168
- package/dist/adapters/SparkAdapter.js.map +1 -1
- package/dist/adapters/arkade.d.ts +15 -0
- package/dist/adapters/arkade.d.ts.map +1 -0
- package/dist/adapters/arkade.js +15 -0
- package/dist/adapters/arkade.js.map +1 -0
- package/dist/adapters/flashnet.d.ts +15 -0
- package/dist/adapters/flashnet.d.ts.map +1 -0
- package/dist/adapters/flashnet.js +17 -0
- package/dist/adapters/flashnet.js.map +1 -0
- package/dist/adapters/native.d.ts +17 -0
- package/dist/adapters/native.d.ts.map +1 -0
- package/dist/adapters/native.js +17 -0
- package/dist/adapters/native.js.map +1 -0
- package/dist/adapters/rgb.d.ts +11 -0
- package/dist/adapters/rgb.d.ts.map +1 -0
- package/dist/adapters/rgb.js +11 -0
- package/dist/adapters/rgb.js.map +1 -0
- package/dist/adapters/spark.d.ts +12 -0
- package/dist/adapters/spark.d.ts.map +1 -0
- package/dist/adapters/spark.js +14 -0
- package/dist/adapters/spark.js.map +1 -0
- package/dist/adapters/wdk/ArkadeWdkAdapter.d.ts +53 -19
- package/dist/adapters/wdk/ArkadeWdkAdapter.d.ts.map +1 -1
- package/dist/adapters/wdk/ArkadeWdkAdapter.js +366 -90
- package/dist/adapters/wdk/ArkadeWdkAdapter.js.map +1 -1
- package/dist/adapters/wdk/BaseWdkAdapter.d.ts +40 -0
- package/dist/adapters/wdk/BaseWdkAdapter.d.ts.map +1 -0
- package/dist/adapters/wdk/BaseWdkAdapter.js +71 -0
- package/dist/adapters/wdk/BaseWdkAdapter.js.map +1 -0
- package/dist/adapters/wdk/LiquidWdkAdapter.d.ts +6 -13
- package/dist/adapters/wdk/LiquidWdkAdapter.d.ts.map +1 -1
- package/dist/adapters/wdk/LiquidWdkAdapter.js +14 -32
- package/dist/adapters/wdk/LiquidWdkAdapter.js.map +1 -1
- package/dist/adapters/wdk/RgbCore.d.ts +64 -0
- package/dist/adapters/wdk/RgbCore.d.ts.map +1 -0
- package/dist/adapters/wdk/RgbCore.js +111 -0
- package/dist/adapters/wdk/RgbCore.js.map +1 -0
- package/dist/adapters/wdk/RgbLibWasmAdapter.d.ts +277 -0
- package/dist/adapters/wdk/RgbLibWasmAdapter.d.ts.map +1 -0
- package/dist/adapters/wdk/RgbLibWasmAdapter.js +731 -0
- package/dist/adapters/wdk/RgbLibWasmAdapter.js.map +1 -0
- package/dist/adapters/wdk/RgbLibWdkAdapter.d.ts +104 -0
- package/dist/adapters/wdk/RgbLibWdkAdapter.d.ts.map +1 -0
- package/dist/adapters/wdk/RgbLibWdkAdapter.js +249 -0
- package/dist/adapters/wdk/RgbLibWdkAdapter.js.map +1 -0
- package/dist/adapters/wdk/RlnWdkAdapter.d.ts +27 -14
- package/dist/adapters/wdk/RlnWdkAdapter.d.ts.map +1 -1
- package/dist/adapters/wdk/RlnWdkAdapter.js +124 -89
- package/dist/adapters/wdk/RlnWdkAdapter.js.map +1 -1
- package/dist/adapters/wdk/SparkWdkAdapter.d.ts +74 -41
- package/dist/adapters/wdk/SparkWdkAdapter.d.ts.map +1 -1
- package/dist/adapters/wdk/SparkWdkAdapter.js +706 -249
- package/dist/adapters/wdk/SparkWdkAdapter.js.map +1 -1
- package/dist/adapters/wdk/index.d.ts +17 -0
- package/dist/adapters/wdk/index.d.ts.map +1 -0
- package/dist/adapters/wdk/index.js +17 -0
- package/dist/adapters/wdk/index.js.map +1 -0
- package/dist/adapters/wdk/wasm-rgb.d.ts +15 -0
- package/dist/adapters/wdk/wasm-rgb.d.ts.map +1 -0
- package/dist/adapters/wdk/wasm-rgb.js +15 -0
- package/dist/adapters/wdk/wasm-rgb.js.map +1 -0
- package/dist/capabilities/index.d.ts +1 -1
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +17 -2
- package/dist/capabilities/index.js.map +1 -1
- package/dist/capabilities/operations.d.ts +22 -0
- package/dist/capabilities/operations.d.ts.map +1 -0
- package/dist/capabilities/operations.js +62 -0
- package/dist/capabilities/operations.js.map +1 -0
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +8 -0
- package/dist/constants.js.map +1 -0
- package/dist/disclosure/index.d.ts +1 -1
- package/dist/disclosure/index.js +1 -1
- package/dist/disclosure/index.js.map +1 -1
- package/dist/format.d.ts +11 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +10 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +21 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -32
- package/dist/index.js.map +1 -1
- package/dist/lib/arkade-client-manager.d.ts +64 -24
- package/dist/lib/arkade-client-manager.d.ts.map +1 -1
- package/dist/lib/arkade-client-manager.js +240 -65
- package/dist/lib/arkade-client-manager.js.map +1 -1
- package/dist/lib/arkade-converters.d.ts +39 -0
- package/dist/lib/arkade-converters.d.ts.map +1 -0
- package/dist/lib/arkade-converters.js +148 -0
- package/dist/lib/arkade-converters.js.map +1 -0
- package/dist/lib/arkade-helpers.d.ts +110 -0
- package/dist/lib/arkade-helpers.d.ts.map +1 -0
- package/dist/lib/arkade-helpers.js +227 -0
- package/dist/lib/arkade-helpers.js.map +1 -0
- package/dist/lib/arkade-swaps-client-manager.d.ts +55 -0
- package/dist/lib/arkade-swaps-client-manager.d.ts.map +1 -0
- package/dist/lib/arkade-swaps-client-manager.js +127 -0
- package/dist/lib/arkade-swaps-client-manager.js.map +1 -0
- package/dist/lib/arkade-vtxo-lifecycle.d.ts +116 -0
- package/dist/lib/arkade-vtxo-lifecycle.d.ts.map +1 -0
- package/dist/lib/arkade-vtxo-lifecycle.js +184 -0
- package/dist/lib/arkade-vtxo-lifecycle.js.map +1 -0
- package/dist/lib/flashnet-client-manager.d.ts +26 -9
- package/dist/lib/flashnet-client-manager.d.ts.map +1 -1
- package/dist/lib/flashnet-client-manager.js +97 -13
- package/dist/lib/flashnet-client-manager.js.map +1 -1
- package/dist/lib/kaleido-client-manager.d.ts +38 -3
- package/dist/lib/kaleido-client-manager.d.ts.map +1 -1
- package/dist/lib/kaleido-client-manager.js +79 -10
- package/dist/lib/kaleido-client-manager.js.map +1 -1
- package/dist/lib/ln-message-sign.d.ts +20 -0
- package/dist/lib/ln-message-sign.d.ts.map +1 -0
- package/dist/lib/ln-message-sign.js +90 -0
- package/dist/lib/ln-message-sign.js.map +1 -0
- package/dist/lib/log.d.ts +15 -0
- package/dist/lib/log.d.ts.map +1 -0
- package/dist/lib/log.js +16 -0
- package/dist/lib/log.js.map +1 -0
- package/dist/lib/orchestra-client.d.ts +149 -0
- package/dist/lib/orchestra-client.d.ts.map +1 -0
- package/dist/lib/orchestra-client.js +178 -0
- package/dist/lib/orchestra-client.js.map +1 -0
- package/dist/lib/psbt-signer.d.ts +60 -0
- package/dist/lib/psbt-signer.d.ts.map +1 -0
- package/dist/lib/psbt-signer.js +161 -0
- package/dist/lib/psbt-signer.js.map +1 -0
- package/dist/lib/rgb-converters.d.ts +62 -0
- package/dist/lib/rgb-converters.d.ts.map +1 -0
- package/dist/lib/rgb-converters.js +179 -0
- package/dist/lib/rgb-converters.js.map +1 -0
- package/dist/lib/rgb-fee-policy.d.ts +41 -0
- package/dist/lib/rgb-fee-policy.d.ts.map +1 -0
- package/dist/lib/rgb-fee-policy.js +52 -0
- package/dist/lib/rgb-fee-policy.js.map +1 -0
- package/dist/lib/rgb-helpers.d.ts +54 -0
- package/dist/lib/rgb-helpers.d.ts.map +1 -0
- package/dist/lib/rgb-helpers.js +89 -0
- package/dist/lib/rgb-helpers.js.map +1 -0
- package/dist/lib/spark-activity.d.ts +5 -0
- package/dist/lib/spark-activity.d.ts.map +1 -0
- package/dist/lib/spark-activity.js +11 -0
- package/dist/lib/spark-activity.js.map +1 -0
- package/dist/lib/spark-balance-cache.d.ts +58 -0
- package/dist/lib/spark-balance-cache.d.ts.map +1 -0
- package/dist/lib/spark-balance-cache.js +86 -0
- package/dist/lib/spark-balance-cache.js.map +1 -0
- package/dist/lib/spark-client-manager.d.ts +64 -10
- package/dist/lib/spark-client-manager.d.ts.map +1 -1
- package/dist/lib/spark-client-manager.js +191 -35
- package/dist/lib/spark-client-manager.js.map +1 -1
- package/dist/lib/spark-converters.d.ts +64 -0
- package/dist/lib/spark-converters.d.ts.map +1 -0
- package/dist/lib/spark-converters.js +242 -0
- package/dist/lib/spark-converters.js.map +1 -0
- package/dist/lib/spark-helpers.d.ts +72 -0
- package/dist/lib/spark-helpers.d.ts.map +1 -0
- package/dist/lib/spark-helpers.js +151 -0
- package/dist/lib/spark-helpers.js.map +1 -0
- package/dist/lib/spark-sent-token-records.d.ts +43 -0
- package/dist/lib/spark-sent-token-records.d.ts.map +1 -0
- package/dist/lib/spark-sent-token-records.js +105 -0
- package/dist/lib/spark-sent-token-records.js.map +1 -0
- package/dist/lib/wallet-seed.d.ts +31 -0
- package/dist/lib/wallet-seed.d.ts.map +1 -0
- package/dist/lib/wallet-seed.js +58 -0
- package/dist/lib/wallet-seed.js.map +1 -0
- package/dist/lib/zbase32.d.ts +3 -0
- package/dist/lib/zbase32.d.ts.map +1 -0
- package/dist/lib/zbase32.js +64 -0
- package/dist/lib/zbase32.js.map +1 -0
- package/dist/manager/ProtocolManager.d.ts +54 -3
- package/dist/manager/ProtocolManager.d.ts.map +1 -1
- package/dist/manager/ProtocolManager.js +118 -41
- package/dist/manager/ProtocolManager.js.map +1 -1
- package/dist/ports/index.d.ts +20 -0
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +23 -1
- package/dist/ports/index.js.map +1 -1
- package/dist/receive/unifiedReceive.d.ts +12 -0
- package/dist/receive/unifiedReceive.d.ts.map +1 -1
- package/dist/receive/unifiedReceive.js +35 -4
- package/dist/receive/unifiedReceive.js.map +1 -1
- package/dist/registry/createWdkRegistry.d.ts +10 -2
- package/dist/registry/createWdkRegistry.d.ts.map +1 -1
- package/dist/registry/createWdkRegistry.js +14 -7
- package/dist/registry/createWdkRegistry.js.map +1 -1
- package/dist/router/destination.d.ts +2 -2
- package/dist/router/destination.d.ts.map +1 -1
- package/dist/router/destination.js +34 -11
- package/dist/router/destination.js.map +1 -1
- package/dist/router/index.d.ts +39 -3
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +113 -4
- package/dist/router/index.js.map +1 -1
- package/dist/router/preference.d.ts +53 -0
- package/dist/router/preference.d.ts.map +1 -0
- package/dist/router/preference.js +81 -0
- package/dist/router/preference.js.map +1 -0
- package/dist/swap/KaleidoswapSwap.d.ts +1 -1
- package/dist/swap/KaleidoswapSwap.d.ts.map +1 -1
- package/dist/swap/KaleidoswapSwap.js +37 -20
- package/dist/swap/KaleidoswapSwap.js.map +1 -1
- package/dist/swap/index.d.ts +8 -0
- package/dist/swap/index.d.ts.map +1 -0
- package/dist/swap/index.js +8 -0
- package/dist/swap/index.js.map +1 -0
- package/dist/types/arkade.d.ts +1 -1
- package/dist/types/base.d.ts +35 -25
- package/dist/types/base.d.ts.map +1 -1
- package/dist/types/base.js +28 -2
- package/dist/types/base.js.map +1 -1
- package/dist/types/cross-l2.d.ts +1 -1
- package/dist/types/flashnet.d.ts +20 -0
- package/dist/types/flashnet.d.ts.map +1 -1
- package/dist/types/flashnet.js +34 -6
- package/dist/types/flashnet.js.map +1 -1
- package/dist/types/rgb.d.ts +18 -4
- package/dist/types/rgb.d.ts.map +1 -1
- package/dist/types/spark.d.ts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +2 -2
- package/dist/utils.js.map +1 -1
- package/package.json +68 -14
|
@@ -0,0 +1,731 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RgbLibWasmAdapter
|
|
3
|
+
* -----------------
|
|
4
|
+
* RGB-L1 (on-chain) backed by the BROWSER/WASM rgb-lib build
|
|
5
|
+
* (`@utexo/rgb-lib-wasm`) instead of the native addon used by
|
|
6
|
+
* `RgbLibWdkAdapter`. Same protocol surface (BTC on-chain + RGB assets on-chain,
|
|
7
|
+
* NO Lightning/channels/swaps), same `RgbCore` translation — only the backing
|
|
8
|
+
* differs, so the two cannot drift on asset/balance shape.
|
|
9
|
+
*
|
|
10
|
+
* Why a separate adapter: the native `@utexo/wdk-wallet-rgb` needs a filesystem
|
|
11
|
+
* `dataDir` + a Node/Bare runtime and cannot load in a browser / MV3 service
|
|
12
|
+
* worker. The wasm build is a wasm-bindgen `--target web` module that persists to
|
|
13
|
+
* IndexedDB and uses only fetch / crypto / WebAssembly — so it runs node-less in
|
|
14
|
+
* the extension (and on mobile). It is the path that makes self-custodial RGB-L1
|
|
15
|
+
* possible without an rgb-lightning-node.
|
|
16
|
+
*
|
|
17
|
+
* Runtime-agnostic: the host injects an ALREADY-wasm-initialized module via
|
|
18
|
+
* `registerWdkModule('@utexo/rgb-lib-wasm', () => initializedModule)`. The host
|
|
19
|
+
* owns where the 13 MB `_bg.wasm` comes from (`chrome.runtime.getURL(...)` in the
|
|
20
|
+
* extension; a bundled asset on mobile) and must have awaited the default
|
|
21
|
+
* `init(...)` export before injecting. This adapter never touches `fetch`/URLs.
|
|
22
|
+
*
|
|
23
|
+
* Discipline: no rgb-lib/wasm types cross the contract — the module + wallet are
|
|
24
|
+
* read as `any` and translated. Field names are read defensively and should be
|
|
25
|
+
* smoke-tested on-device (validated offline: keys, wallet, address, listAssets).
|
|
26
|
+
*
|
|
27
|
+
* WasmWallet API used (from @utexo/rgb-lib-wasm@1.0.0-beta.2):
|
|
28
|
+
* static create(walletDataJson) → WasmWallet (IndexedDB-restoring)
|
|
29
|
+
* goOnline(skipConsistencyCheck, indexerUrl) → online
|
|
30
|
+
* getAddress() · getBtcBalance() · getAssetBalance(id) · listAssets(schemas[])
|
|
31
|
+
* blindReceive(assetId|null, assignment, duration|null, transportEndpoints, minConf)
|
|
32
|
+
* sendBegin(online, recipientMap, donation, feeRate, minConf) · signPsbt(psbt)
|
|
33
|
+
* · sendEnd(online, signedPsbt, skipSync)
|
|
34
|
+
* sendBtcBegin/sendBtcEnd · createUtxosBegin/createUtxosEnd · refresh · sync
|
|
35
|
+
* listTransactions() · listTransfers(assetId?)
|
|
36
|
+
* Top-level: init() (panic/log hook) · restoreKeys(network, mnemonic) → keys.
|
|
37
|
+
*/
|
|
38
|
+
import { ProtocolError, } from '../../types/base.js';
|
|
39
|
+
import { getCapabilities } from '../../capabilities/index.js';
|
|
40
|
+
import { PROTOCOL_OPERATIONS } from '../../capabilities/operations.js';
|
|
41
|
+
import { loadWdkModule } from './moduleLoader.js';
|
|
42
|
+
import { rgbBtcAsset, rgbNiaAsset, rgbAssetBalance, RGB_L1_PROFILE } from './RgbCore.js';
|
|
43
|
+
import { BaseWdkAdapter } from './BaseWdkAdapter.js';
|
|
44
|
+
/** Map the engine network string → rgb-lib's network enum casing. */
|
|
45
|
+
function toRgbNetwork(network) {
|
|
46
|
+
switch (network.toLowerCase()) {
|
|
47
|
+
case 'mainnet':
|
|
48
|
+
case 'bitcoin':
|
|
49
|
+
return 'Mainnet';
|
|
50
|
+
case 'testnet':
|
|
51
|
+
return 'Testnet';
|
|
52
|
+
// KaleidoSwap's signet IS the custom signet (Mutinynet); its recipient IDs
|
|
53
|
+
// are network-tagged `SignetCustom` and won't validate against a standard
|
|
54
|
+
// `Signet` wallet (and vice-versa). Map both the explicit custom aliases and
|
|
55
|
+
// the plain `signet` we surface in the UI to rgb-lib's `SignetCustom`.
|
|
56
|
+
case 'signet':
|
|
57
|
+
case 'signetcustom':
|
|
58
|
+
case 'customsignet':
|
|
59
|
+
case 'mutinynet':
|
|
60
|
+
return 'SignetCustom';
|
|
61
|
+
case 'regtest':
|
|
62
|
+
return 'Regtest';
|
|
63
|
+
default:
|
|
64
|
+
return 'Mainnet';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Wrap a WasmWallet so every method call is queued and runs to completion before
|
|
69
|
+
* the next starts — rgb-lib-wasm is single-threaded and corrupts/panics on
|
|
70
|
+
* concurrent (interleaved-async) access. All methods become async; call sites
|
|
71
|
+
* await them.
|
|
72
|
+
*/
|
|
73
|
+
function serializeWasmAccount(account) {
|
|
74
|
+
let chain = Promise.resolve();
|
|
75
|
+
return new Proxy(account, {
|
|
76
|
+
get(target, prop, receiver) {
|
|
77
|
+
const value = Reflect.get(target, prop, receiver);
|
|
78
|
+
if (typeof value !== 'function')
|
|
79
|
+
return value;
|
|
80
|
+
return (...args) => {
|
|
81
|
+
const run = chain.then(() => value.apply(target, args));
|
|
82
|
+
chain = run.then(() => undefined, () => undefined);
|
|
83
|
+
return run;
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
export class RgbLibWasmAdapter extends BaseWdkAdapter {
|
|
89
|
+
constructor() {
|
|
90
|
+
super(...arguments);
|
|
91
|
+
this.protocolName = 'RGB_L1';
|
|
92
|
+
this.capabilities = PROTOCOL_OPERATIONS.RGB_L1;
|
|
93
|
+
this.supportedLayers = getCapabilities('RGB_L1').layers;
|
|
94
|
+
this.version = '0.1.0-wasm';
|
|
95
|
+
/** The rgb-lib `online` handle returned by goOnline(); required by network ops. */
|
|
96
|
+
this.online = null;
|
|
97
|
+
this.transportEndpoints = [];
|
|
98
|
+
}
|
|
99
|
+
// --- Connection ---------------------------------------------------------
|
|
100
|
+
async connect(config) {
|
|
101
|
+
const cfg = config;
|
|
102
|
+
if (!cfg.mnemonic)
|
|
103
|
+
throw new ProtocolError('RgbLibWasmAdapter requires a mnemonic', 'RGB_L1', 'CONFIG');
|
|
104
|
+
if (!cfg.indexerUrl)
|
|
105
|
+
throw new ProtocolError('RgbLibWasmAdapter requires an indexerUrl', 'RGB_L1', 'CONFIG');
|
|
106
|
+
this.network = cfg.network ?? 'mainnet';
|
|
107
|
+
this.transportEndpoints = cfg.transportEndpoints ?? [];
|
|
108
|
+
const rgbNetwork = toRgbNetwork(this.network);
|
|
109
|
+
// The host injects an already-wasm-initialized module; the inline import is
|
|
110
|
+
// the Node/Vite fallback. `init()` is rgb-lib's panic/log hook (idempotent).
|
|
111
|
+
// @ts-ignore — declared as an optional dep; resolved at runtime.
|
|
112
|
+
const mod = await loadWdkModule('@utexo/rgb-lib-wasm', () => import('@utexo/rgb-lib-wasm'));
|
|
113
|
+
try {
|
|
114
|
+
mod.init?.();
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
/* already initialized */
|
|
118
|
+
}
|
|
119
|
+
const keys = mod.restoreKeys(rgbNetwork, cfg.mnemonic);
|
|
120
|
+
const walletData = {
|
|
121
|
+
// Scope the IndexedDB store by the rgb-lib network, NOT the host network
|
|
122
|
+
// label: rgb-lib panics ("unreachable") if a store created under one
|
|
123
|
+
// BitcoinNetwork is reopened under another (e.g. Signet → SignetCustom).
|
|
124
|
+
// Distinct networks ⇒ distinct stores; same network ⇒ persistent.
|
|
125
|
+
dataDir: cfg.dataDir ?? `rgb-l1-${rgbNetwork.toLowerCase()}`,
|
|
126
|
+
bitcoinNetwork: rgbNetwork,
|
|
127
|
+
databaseType: 'Sqlite', // the enum value the wasm build accepts; IndexedDB is the actual backing
|
|
128
|
+
maxAllocationsPerUtxo: cfg.maxAllocationsPerUtxo ?? 5,
|
|
129
|
+
mnemonic: keys.mnemonic ?? cfg.mnemonic,
|
|
130
|
+
masterFingerprint: keys.masterFingerprint ?? keys.master_fingerprint,
|
|
131
|
+
accountXpubVanilla: keys.accountXpubVanilla ?? keys.account_xpub_vanilla,
|
|
132
|
+
accountXpubColored: keys.accountXpubColored ?? keys.account_xpub_colored,
|
|
133
|
+
vanillaKeychain: null,
|
|
134
|
+
supportedSchemas: ['Nia', 'Cfa', 'Ifa'],
|
|
135
|
+
};
|
|
136
|
+
const WasmWallet = mod.WasmWallet;
|
|
137
|
+
const rawWallet = WasmWallet.create
|
|
138
|
+
? await WasmWallet.create(JSON.stringify(walletData))
|
|
139
|
+
: new WasmWallet(JSON.stringify(walletData));
|
|
140
|
+
// rgb-lib-wasm is single-threaded and NOT reentrant: if a second op starts
|
|
141
|
+
// while an async one (refresh/sync/send/…) is mid-flight, its thread-locals
|
|
142
|
+
// corrupt and it panics ("Lazy instance poisoned" → RuntimeError:
|
|
143
|
+
// unreachable). Serialize every wallet call through a queue so they never
|
|
144
|
+
// overlap. (Method results are awaited at each call site.)
|
|
145
|
+
this.account = serializeWasmAccount(rawWallet);
|
|
146
|
+
this.online = await this.account.goOnline(false, cfg.indexerUrl);
|
|
147
|
+
this.connected = true;
|
|
148
|
+
await this.recoverBtcStateIfThin();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* One-time recovery for a wallet restored from a *thin* BDK snapshot (no
|
|
152
|
+
* revealed SPKs) — the state left behind when an MV3 service-worker teardown
|
|
153
|
+
* interrupts rgb-lib-wasm's async IndexedDB save. In that state an incremental
|
|
154
|
+
* `sync` can only re-query already-revealed SPKs, so it can't rediscover the
|
|
155
|
+
* on-chain BTC and the balance reads 0 even though funds exist.
|
|
156
|
+
*
|
|
157
|
+
* Strategy: after an incremental sync, if BTC still reads 0, run a `fullScan`
|
|
158
|
+
* (BIP44 stop-gap) to rebuild the UTXO set from the indexer, then `flush` so
|
|
159
|
+
* the recovered state durably persists (and normal incremental sync suffices
|
|
160
|
+
* from then on). Version-guarded — `fullScan` is absent on rgb-lib-wasm
|
|
161
|
+
* ≤ beta.2 — and best-effort so a scan failure never blocks connect.
|
|
162
|
+
*/
|
|
163
|
+
async recoverBtcStateIfThin() {
|
|
164
|
+
const fullScan = this.account?.fullScan;
|
|
165
|
+
if (typeof fullScan !== 'function')
|
|
166
|
+
return;
|
|
167
|
+
try {
|
|
168
|
+
await this.account.sync(this.online);
|
|
169
|
+
const { total } = await this.getBtcBalance();
|
|
170
|
+
if (total > 0)
|
|
171
|
+
return; // state already healthy — skip the costlier full scan
|
|
172
|
+
await this.account.fullScan(this.online);
|
|
173
|
+
await this.flushState();
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
console.error('[RGB-L1] BTC state recovery scan failed:', e);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async getConnectionInfo() {
|
|
180
|
+
this.assertConnected();
|
|
181
|
+
return { protocol: 'RGB_L1', connected: this.connected, network: this.network };
|
|
182
|
+
}
|
|
183
|
+
// --- Address / receive --------------------------------------------------
|
|
184
|
+
async getReceiveAddress(assetId) {
|
|
185
|
+
this.assertConnected();
|
|
186
|
+
// Only a real RGB asset id (rgb:…) yields a blinded invoice; BTC / "BTC" /
|
|
187
|
+
// empty must return the on-chain BTC address (otherwise the BTC tab shows an
|
|
188
|
+
// empty "bitcoin:" QR).
|
|
189
|
+
if (assetId && assetId.startsWith('rgb:')) {
|
|
190
|
+
const inv = await this.receiveRgb({ assetId });
|
|
191
|
+
return { address: inv?.invoice ?? inv?.recipient_id ?? '', format: 'RGB_INVOICE', asset: assetId };
|
|
192
|
+
}
|
|
193
|
+
const address = await this.account.getAddress();
|
|
194
|
+
return { address, format: 'BTC_ADDRESS' };
|
|
195
|
+
}
|
|
196
|
+
// --- Balance ------------------------------------------------------------
|
|
197
|
+
/** Raw vanilla / colored BTC split as rgb-lib reports it (both in sats). */
|
|
198
|
+
async detailedBtcBalance() {
|
|
199
|
+
this.assertConnected();
|
|
200
|
+
const v = (await this.account.getBtcBalance()) ?? {};
|
|
201
|
+
return {
|
|
202
|
+
vanilla: readRgbLibBtcBalanceBucket(v.vanilla ?? v),
|
|
203
|
+
colored: v.colored ? readRgbLibBtcBalanceBucket(v.colored) : { settled: 0, spendable: 0, future: 0 },
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
async getBtcBalance() {
|
|
207
|
+
const { vanilla, colored } = await this.detailedBtcBalance();
|
|
208
|
+
const settled = vanilla.settled + colored.settled;
|
|
209
|
+
const spendable = vanilla.spendable + colored.spendable;
|
|
210
|
+
const future = vanilla.future + colored.future;
|
|
211
|
+
return { confirmed: settled, unconfirmed: Math.max(0, future - settled), total: spendable };
|
|
212
|
+
}
|
|
213
|
+
/** Detailed BTC balance with the vanilla / colored split (IProtocolAdapter hook). */
|
|
214
|
+
async getRgbDetailedBalance() {
|
|
215
|
+
return this.detailedBtcBalance();
|
|
216
|
+
}
|
|
217
|
+
async refreshBalances() {
|
|
218
|
+
this.assertConnected();
|
|
219
|
+
try {
|
|
220
|
+
// Sync the wallet ONCE, then refresh transfer statuses reusing that sync
|
|
221
|
+
// (skip_sync=true). Previously refresh(skip_sync=false) synced and then we
|
|
222
|
+
// synced again — two full indexer round-trips, ~2× the cold-sync wait.
|
|
223
|
+
await this.account.sync(this.online);
|
|
224
|
+
await this.account.refresh(this.online, null, [], true);
|
|
225
|
+
// Durably commit the refreshed state. In MV3 the service worker is killed
|
|
226
|
+
// aggressively; without a flush the settled-transfer promotion lives only
|
|
227
|
+
// in memory and is lost on the next cold start, which re-surfaces as stale
|
|
228
|
+
// balances / "insufficient assignments" on the following send.
|
|
229
|
+
await this.flushState();
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
// best-effort, but surface the cause — a silent failure leaves the wallet
|
|
233
|
+
// showing 0 balance / no history.
|
|
234
|
+
console.error('[RGB-L1] refresh/sync failed:', e);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async listAssets() {
|
|
238
|
+
this.assertConnected();
|
|
239
|
+
const { total } = await this.getBtcBalance();
|
|
240
|
+
const out = [rgbBtcAsset(total, RGB_L1_PROFILE)];
|
|
241
|
+
const res = await this.account.listAssets([]);
|
|
242
|
+
// All fungible schemas: NIA + CFA + IFA (rgbNiaAsset maps any fungible).
|
|
243
|
+
const assets = Array.isArray(res)
|
|
244
|
+
? res
|
|
245
|
+
: [...(res?.nia ?? []), ...(res?.cfa ?? []), ...(res?.ifa ?? [])];
|
|
246
|
+
for (const a of assets)
|
|
247
|
+
out.push(rgbNiaAsset(normalizeAsset(a), RGB_L1_PROFILE));
|
|
248
|
+
return out;
|
|
249
|
+
}
|
|
250
|
+
async getAssetBalance(assetId) {
|
|
251
|
+
this.assertConnected();
|
|
252
|
+
try {
|
|
253
|
+
const raw = await this.account.getAssetBalance(assetId);
|
|
254
|
+
return rgbAssetBalance(raw);
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
const a = (await this.listAssets()).find((x) => x.id === assetId);
|
|
258
|
+
return a?.balance ?? rgbAssetBalance({});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async getAsset(assetId) {
|
|
262
|
+
const found = (await this.listAssets()).find((a) => a.id === assetId);
|
|
263
|
+
if (!found)
|
|
264
|
+
throw new ProtocolError(`Unknown asset ${assetId}`, 'RGB_L1', 'NO_ASSET');
|
|
265
|
+
return found;
|
|
266
|
+
}
|
|
267
|
+
// --- Invoices -----------------------------------------------------------
|
|
268
|
+
async createInvoice(request) {
|
|
269
|
+
this.assertConnected();
|
|
270
|
+
if (!request.asset || request.asset === 'BTC') {
|
|
271
|
+
throw new ProtocolError('RGB-L1 has no Lightning invoices; use getReceiveAddress for BTC', 'RGB_L1', 'NOT_SUPPORTED');
|
|
272
|
+
}
|
|
273
|
+
const inv = await this.receiveRgb({
|
|
274
|
+
assetId: request.asset,
|
|
275
|
+
amount: request.assetAmount,
|
|
276
|
+
durationSeconds: request.expirySeconds,
|
|
277
|
+
});
|
|
278
|
+
return {
|
|
279
|
+
invoice: inv?.invoice ?? '',
|
|
280
|
+
paymentHash: inv?.recipientId ?? inv?.recipient_id ?? '',
|
|
281
|
+
amount: request.assetAmount,
|
|
282
|
+
expiresAt: inv?.expirationTimestamp ? inv.expirationTimestamp * 1000 : Date.now() + (request.expirySeconds ?? 3600) * 1000,
|
|
283
|
+
description: request.description,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
async decodeInvoice(_invoice) {
|
|
287
|
+
throw new ProtocolError('RGB-L1 adapter does not decode invoices', 'RGB_L1', 'NOT_SUPPORTED');
|
|
288
|
+
}
|
|
289
|
+
// --- Send (Lightning not supported) -------------------------------------
|
|
290
|
+
async sendPayment(_request) {
|
|
291
|
+
throw new ProtocolError('RGB-L1 has no Lightning send; use sendAsset or sendBtcOnchain', 'RGB_L1', 'NOT_SUPPORTED');
|
|
292
|
+
}
|
|
293
|
+
async getPaymentStatus(_paymentHash) {
|
|
294
|
+
throw new ProtocolError('RGB-L1 has no Lightning payment status', 'RGB_L1', 'NOT_SUPPORTED');
|
|
295
|
+
}
|
|
296
|
+
// --- Transactions -------------------------------------------------------
|
|
297
|
+
async listTransactions(_filter) {
|
|
298
|
+
this.assertConnected();
|
|
299
|
+
const raw = await this.account.listTransactions();
|
|
300
|
+
const txs = Array.isArray(raw) ? raw : raw?.transactions ?? [];
|
|
301
|
+
return txs.map((t) => {
|
|
302
|
+
const { received, sent, type } = normalizeRgbLibTransactionAmounts(t);
|
|
303
|
+
const confTime = t.confirmationTime ?? t.confirmation_time;
|
|
304
|
+
const timestampSeconds = normalizeRgbLibTimestamp(confTime);
|
|
305
|
+
return {
|
|
306
|
+
id: t.txid ?? t.transactionId ?? t.transaction_id ?? '',
|
|
307
|
+
type,
|
|
308
|
+
status: (timestampSeconds ? 'confirmed' : 'pending'),
|
|
309
|
+
timestamp: timestampSeconds * 1000,
|
|
310
|
+
amount: Math.abs(received - sent) || received || sent,
|
|
311
|
+
amountDisplay: '',
|
|
312
|
+
asset: undefined,
|
|
313
|
+
protocolData: {
|
|
314
|
+
...t,
|
|
315
|
+
transactionType: normalizeRgbLibTxType(t.transactionType ?? t.transaction_type),
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
async getTransaction(txId) {
|
|
321
|
+
const found = (await this.listTransactions()).find((t) => t.id === txId);
|
|
322
|
+
if (!found)
|
|
323
|
+
throw new ProtocolError(`Unknown tx ${txId}`, 'RGB_L1', 'NO_TX');
|
|
324
|
+
return found;
|
|
325
|
+
}
|
|
326
|
+
async getNodeInfo() {
|
|
327
|
+
return {};
|
|
328
|
+
}
|
|
329
|
+
async listChannels() {
|
|
330
|
+
return [];
|
|
331
|
+
}
|
|
332
|
+
async listPayments() {
|
|
333
|
+
return [];
|
|
334
|
+
}
|
|
335
|
+
async listTransfers(options) {
|
|
336
|
+
this.assertConnected();
|
|
337
|
+
return this.account.listTransfers(options?.asset_id ?? null);
|
|
338
|
+
}
|
|
339
|
+
// --- RGB-specific hooks (used by the RGB host surface) ------------------
|
|
340
|
+
async createRgbInvoice(params) {
|
|
341
|
+
this.assertConnected();
|
|
342
|
+
return this.receiveRgb(params);
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Generate an RGB receive invoice. Defaults to a blinded receive (the
|
|
346
|
+
* recipient UTXO is hidden); `witness: true` uses a witness receive (the
|
|
347
|
+
* sender creates the UTXO). rgb-lib's `Assignment` enum is `{ Fungible: <num> }`
|
|
348
|
+
* for a specific amount or the unit string `"Any"` — NOT null, and NOT bigint.
|
|
349
|
+
*/
|
|
350
|
+
async receiveRgb(opts) {
|
|
351
|
+
const fungibleValue = opts.amount != null
|
|
352
|
+
? opts.amount
|
|
353
|
+
: opts.assignment?.type === 'Fungible' && opts.assignment.value != null
|
|
354
|
+
? opts.assignment.value
|
|
355
|
+
: undefined;
|
|
356
|
+
const assignment = fungibleValue != null ? { Fungible: Number(fungibleValue) } : 'Any';
|
|
357
|
+
const args = [
|
|
358
|
+
opts.assetId ?? null,
|
|
359
|
+
assignment,
|
|
360
|
+
opts.durationSeconds ?? null,
|
|
361
|
+
this.transportEndpoints,
|
|
362
|
+
opts.minConfirmations ?? 1,
|
|
363
|
+
];
|
|
364
|
+
const res = await (opts.witness
|
|
365
|
+
? this.account.witnessReceive(...args)
|
|
366
|
+
: this.account.blindReceive(...args));
|
|
367
|
+
// Generating an invoice records a pending transfer in the wallet DB; flush so
|
|
368
|
+
// it survives a service-worker restart before the payer pays it.
|
|
369
|
+
await this.flushState();
|
|
370
|
+
// Normalize to a plain, structured-clone-safe object: the wasm result can
|
|
371
|
+
// carry BigInt / wasm-bound values that break chrome message passing
|
|
372
|
+
// ("could not serialize message"). Coerce the fields the host reads.
|
|
373
|
+
return {
|
|
374
|
+
invoice: res?.invoice ?? '',
|
|
375
|
+
recipientId: res?.recipientId ?? res?.recipient_id ?? '',
|
|
376
|
+
recipient_id: res?.recipientId ?? res?.recipient_id ?? '',
|
|
377
|
+
expirationTimestamp: res?.expirationTimestamp != null ? Number(res.expirationTimestamp) : undefined,
|
|
378
|
+
batchTransferIdx: res?.batchTransferIdx != null ? Number(res.batchTransferIdx) : undefined,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
async signPsbt(psbtHex) {
|
|
382
|
+
this.assertConnected();
|
|
383
|
+
const signed = await this.account.signPsbt(psbtHex);
|
|
384
|
+
return { psbt: signed ?? psbtHex, unchanged: !signed || signed === psbtHex };
|
|
385
|
+
}
|
|
386
|
+
async createRgbUtxos(params) {
|
|
387
|
+
this.assertConnected();
|
|
388
|
+
// Same rationale as sendAsset: createUtxosBegin selects from vanilla UTXOs
|
|
389
|
+
// tracked in the local DB; sync first so the indexer's current view is used.
|
|
390
|
+
await this.refreshBalances();
|
|
391
|
+
const feeRate = BigInt(Math.round(params.feeRate ?? 1));
|
|
392
|
+
const unsigned = await this.account.createUtxosBegin(this.online, params.upTo ?? false, params.num ?? null, params.size ?? null, feeRate, false);
|
|
393
|
+
const signed = await this.account.signPsbt(unsigned);
|
|
394
|
+
await this.account.createUtxosEnd(this.online, signed, false);
|
|
395
|
+
// Commit the new UTXO set before the caller relies on it (e.g. immediately
|
|
396
|
+
// issuing/receiving against the freshly-created colorable UTXOs).
|
|
397
|
+
await this.flushState();
|
|
398
|
+
return { success: true };
|
|
399
|
+
}
|
|
400
|
+
async sendAsset(params) {
|
|
401
|
+
this.assertConnected();
|
|
402
|
+
const token = params.token ?? params.assetId;
|
|
403
|
+
const recipientId = params.recipient ?? params.recipientId;
|
|
404
|
+
if (!token)
|
|
405
|
+
throw new ProtocolError('RGB-L1 asset send requires an asset id', 'RGB_L1', 'INVALID_REQUEST');
|
|
406
|
+
if (!recipientId)
|
|
407
|
+
throw new ProtocolError('RGB-L1 asset send requires a recipient id', 'RGB_L1', 'INVALID_REQUEST');
|
|
408
|
+
const amount = Number(params.amount ?? params.assignment?.value ?? 0);
|
|
409
|
+
if (!Number.isFinite(amount) || amount <= 0) {
|
|
410
|
+
throw new ProtocolError('RGB-L1 asset send requires a positive amount', 'RGB_L1', 'INVALID_REQUEST');
|
|
411
|
+
}
|
|
412
|
+
const transportEndpoints = Array.isArray(params.transportEndpoints) && params.transportEndpoints.length > 0
|
|
413
|
+
? params.transportEndpoints
|
|
414
|
+
: this.transportEndpoints;
|
|
415
|
+
const assignment = toRgbLibAssignment(params.assignment, amount);
|
|
416
|
+
const recipient = {
|
|
417
|
+
// rgb-lib-wasm examples use camelCase, while the desktop rgb-lib client
|
|
418
|
+
// path sends snake_case. Keep both so this adapter survives either wasm
|
|
419
|
+
// serde casing without changing the host API.
|
|
420
|
+
recipientId,
|
|
421
|
+
recipient_id: recipientId,
|
|
422
|
+
assignment,
|
|
423
|
+
transportEndpoints,
|
|
424
|
+
transport_endpoints: transportEndpoints,
|
|
425
|
+
};
|
|
426
|
+
const wd = params.witnessData ?? params.witness_data;
|
|
427
|
+
if (wd) {
|
|
428
|
+
const amountSat = wd.amountSat ?? wd.amount_sat;
|
|
429
|
+
const witnessData = {
|
|
430
|
+
amountSat: Math.round(Number(amountSat ?? 0)),
|
|
431
|
+
amount_sat: Math.round(Number(amountSat ?? 0)),
|
|
432
|
+
...(wd.blinding != null ? { blinding: Math.round(Number(wd.blinding)) } : {}),
|
|
433
|
+
};
|
|
434
|
+
recipient.witnessData = witnessData;
|
|
435
|
+
recipient.witness_data = witnessData;
|
|
436
|
+
}
|
|
437
|
+
const recipientMap = {
|
|
438
|
+
[token]: [recipient],
|
|
439
|
+
};
|
|
440
|
+
// rgb-lib's `send` only spends *settled* allocations it knows about locally.
|
|
441
|
+
// Without a fresh sync+refresh right before sendBegin, a received transfer
|
|
442
|
+
// that hasn't been promoted to Settled in the local DB (e.g. after a SW
|
|
443
|
+
// restart or IndexedDB restore) is invisible to the spend, and sendBegin
|
|
444
|
+
// fails with "Insufficient total assignments" despite a non-zero UI balance.
|
|
445
|
+
await this.refreshBalances();
|
|
446
|
+
const feeRate = BigInt(Math.round(params.feeRate ?? 1));
|
|
447
|
+
const unsigned = await this.account.sendBegin(this.online, recipientMap, params.donation ?? false, feeRate, params.minConfirmations ?? 1);
|
|
448
|
+
const signed = await this.account.signPsbt(unsigned);
|
|
449
|
+
const result = await this.account.sendEnd(this.online, signed, false);
|
|
450
|
+
// The spend is broadcast; persist the consumed-allocation state so a SW kill
|
|
451
|
+
// can't leave the wallet thinking the inputs are still spendable (which would
|
|
452
|
+
// later fail as "insufficient assignments" or attempt a double-spend).
|
|
453
|
+
await this.flushState();
|
|
454
|
+
return result;
|
|
455
|
+
}
|
|
456
|
+
async sendBtcOnchain(params) {
|
|
457
|
+
this.assertConnected();
|
|
458
|
+
const feeRate = BigInt(Math.round(params.feeRate ?? 1));
|
|
459
|
+
const unsigned = await this.account.sendBtcBegin(this.online, params.address, BigInt(params.amount), feeRate, false);
|
|
460
|
+
const signed = await this.account.signPsbt(unsigned);
|
|
461
|
+
const txid = await this.account.sendBtcEnd(this.online, signed, false);
|
|
462
|
+
await this.flushState();
|
|
463
|
+
return { ok: true, txid };
|
|
464
|
+
}
|
|
465
|
+
// --- UTXOs / fees / metadata / transfer maintenance ---------------------
|
|
466
|
+
/**
|
|
467
|
+
* List the wallet's unspent outputs and their RGB allocations
|
|
468
|
+
* (IProtocolAdapter hook). Normalizes rgb-lib's camel/snake casing and the
|
|
469
|
+
* `Outpoint` (object `{txid,vout}` or `"txid:vout"` string) into the flat shape
|
|
470
|
+
* the host consumes.
|
|
471
|
+
*/
|
|
472
|
+
async listRgbUnspents() {
|
|
473
|
+
this.assertConnected();
|
|
474
|
+
const raw = await this.account.listUnspents(false);
|
|
475
|
+
const list = Array.isArray(raw) ? raw : raw?.unspents ?? [];
|
|
476
|
+
return {
|
|
477
|
+
unspents: list.map((u) => {
|
|
478
|
+
const utxo = u?.utxo ?? u ?? {};
|
|
479
|
+
const allocations = u?.rgbAllocations ?? u?.rgb_allocations ?? [];
|
|
480
|
+
return {
|
|
481
|
+
utxo: {
|
|
482
|
+
outpoint: formatOutpoint(utxo.outpoint),
|
|
483
|
+
btc_amount: toFiniteNumber(utxo.btcAmount ?? utxo.btc_amount ?? 0),
|
|
484
|
+
colorable: Boolean(utxo.colorable),
|
|
485
|
+
},
|
|
486
|
+
rgb_allocations: allocations.map((a) => ({
|
|
487
|
+
asset_id: a?.assetId ?? a?.asset_id ?? null,
|
|
488
|
+
assignment: a?.assignment ?? null,
|
|
489
|
+
settled: Boolean(a?.settled),
|
|
490
|
+
})),
|
|
491
|
+
};
|
|
492
|
+
}),
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
/** Estimate the on-chain fee rate (sat/vB) for a confirmation target (IProtocolAdapter hook). */
|
|
496
|
+
async estimateRgbFee(blocks) {
|
|
497
|
+
this.assertConnected();
|
|
498
|
+
const target = Number.isFinite(blocks) && blocks > 0 ? Math.round(blocks) : 6;
|
|
499
|
+
const rate = await this.account.getFeeEstimation(this.online, target);
|
|
500
|
+
return { fee_rate: toFiniteNumber(rate) };
|
|
501
|
+
}
|
|
502
|
+
/** Asset metadata (name, ticker, precision, supply). */
|
|
503
|
+
async getAssetMetadata(assetId) {
|
|
504
|
+
this.assertConnected();
|
|
505
|
+
const meta = await this.account.getAssetMetadata(assetId);
|
|
506
|
+
return {
|
|
507
|
+
asset_id: assetId,
|
|
508
|
+
asset_schema: meta?.assetSchema ?? meta?.asset_schema,
|
|
509
|
+
name: meta?.name,
|
|
510
|
+
ticker: meta?.ticker,
|
|
511
|
+
precision: meta?.precision,
|
|
512
|
+
initial_supply: toFiniteNumber(meta?.initialSupply ?? meta?.initial_supply ?? 0),
|
|
513
|
+
max_supply: meta?.maxSupply ?? meta?.max_supply,
|
|
514
|
+
known_circulating_supply: meta?.knownCirculatingSupply ?? meta?.known_circulating_supply,
|
|
515
|
+
timestamp: meta?.timestamp,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Status of a received invoice: matches the pending transfer by recipient id /
|
|
520
|
+
* invoice string and returns its rgb-lib status (WaitingCounterparty,
|
|
521
|
+
* WaitingConfirmations, Settled, Failed, …).
|
|
522
|
+
*/
|
|
523
|
+
async getInvoiceStatus(params) {
|
|
524
|
+
this.assertConnected();
|
|
525
|
+
const needle = String(params.invoice ?? '');
|
|
526
|
+
const raw = await this.account.listTransfers(null);
|
|
527
|
+
const transfers = Array.isArray(raw) ? raw : raw?.transfers ?? [];
|
|
528
|
+
const match = transfers.find((t) => {
|
|
529
|
+
const fields = [t?.recipientId, t?.recipient_id, t?.invoiceString, t?.invoice_string, t?.invoice];
|
|
530
|
+
return fields.some((f) => f && String(f) === needle);
|
|
531
|
+
});
|
|
532
|
+
return { status: match?.status ?? null, transfer: match ?? null };
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Fail expired/stuck pending transfers (default: all). Stuck WaitingCounterparty
|
|
536
|
+
* transfers hold allocations and can block a later spend with "insufficient
|
|
537
|
+
* assignments"; failing then deleting them frees those allocations.
|
|
538
|
+
*/
|
|
539
|
+
async failRgbTransfers(params = {}) {
|
|
540
|
+
this.assertConnected();
|
|
541
|
+
const changed = await this.account.failTransfers(this.online, params.batchTransferIdx ?? null, params.noAssetOnly ?? false, false);
|
|
542
|
+
await this.flushState();
|
|
543
|
+
return { changed: Boolean(changed) };
|
|
544
|
+
}
|
|
545
|
+
/** Delete already-failed transfers from the wallet DB. */
|
|
546
|
+
async deleteRgbTransfers(params = {}) {
|
|
547
|
+
this.assertConnected();
|
|
548
|
+
const changed = await this.account.deleteTransfers(params.batchTransferIdx ?? null, params.noAssetOnly ?? false);
|
|
549
|
+
await this.flushState();
|
|
550
|
+
return { changed: Boolean(changed) };
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Durably commit wallet state to IndexedDB. Best-effort and version-guarded:
|
|
554
|
+
* `flush()` was added after `@utexo/rgb-lib-wasm@1.0.0-beta.2`, so on older
|
|
555
|
+
* builds this is a no-op (the wasm persists opportunistically). A failed flush
|
|
556
|
+
* leaves in-memory state intact and is safe to retry, so we log and continue.
|
|
557
|
+
*/
|
|
558
|
+
async flushState() {
|
|
559
|
+
const fn = this.account?.flush;
|
|
560
|
+
if (typeof fn !== 'function')
|
|
561
|
+
return;
|
|
562
|
+
try {
|
|
563
|
+
await this.account.flush();
|
|
564
|
+
}
|
|
565
|
+
catch (e) {
|
|
566
|
+
console.error('[RGB-L1] flush failed:', e);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
// ==========================================================================
|
|
570
|
+
// Backup / VSS
|
|
571
|
+
//
|
|
572
|
+
// RGB state (allocations/consignments) can't be rebuilt from the seed, so it
|
|
573
|
+
// must be backed up after every settled transfer. rgb-lib encrypts the blob
|
|
574
|
+
// client-side before it ever leaves the wallet, so the VSS server only stores
|
|
575
|
+
// ciphertext. All calls route through the serialized account queue, so a
|
|
576
|
+
// backup can't interleave with a concurrent wallet mutation.
|
|
577
|
+
// ==========================================================================
|
|
578
|
+
/** Encrypted wallet backup bytes (rgb-lib's own format). */
|
|
579
|
+
async backup(password) {
|
|
580
|
+
this.assertConnected();
|
|
581
|
+
return this.account.backup(password);
|
|
582
|
+
}
|
|
583
|
+
/** Restore wallet state from encrypted backup bytes produced by {@link backup}. */
|
|
584
|
+
async restoreBackup(params) {
|
|
585
|
+
this.assertConnected();
|
|
586
|
+
await this.account.restoreBackup(params.backupBytes, params.password);
|
|
587
|
+
await this.flushState();
|
|
588
|
+
}
|
|
589
|
+
/** Whether local wallet state has changed since the last backup. */
|
|
590
|
+
async backupInfo() {
|
|
591
|
+
this.assertConnected();
|
|
592
|
+
return { required: Boolean(await this.account.backupInfo()) };
|
|
593
|
+
}
|
|
594
|
+
/** Configure VSS (cloud) backup: server URL, per-wallet store id, signing key (hex). */
|
|
595
|
+
async configureVssBackup(params) {
|
|
596
|
+
this.assertConnected();
|
|
597
|
+
await this.account.configureVssBackup(params.serverUrl, params.storeId, params.signingKeyHex);
|
|
598
|
+
}
|
|
599
|
+
/** Disable VSS (cloud) backup for this wallet. */
|
|
600
|
+
async disableVssBackup() {
|
|
601
|
+
this.assertConnected();
|
|
602
|
+
await this.account.disableVssBackup();
|
|
603
|
+
}
|
|
604
|
+
/** Upload an encrypted backup to the configured VSS server. Returns the new server version. */
|
|
605
|
+
async vssBackup() {
|
|
606
|
+
this.assertConnected();
|
|
607
|
+
// rgb-lib returns the raw server version (may be a BigInt) — normalize so it
|
|
608
|
+
// survives structured-clone across the extension's SW message boundary.
|
|
609
|
+
const raw = await this.account.vssBackup();
|
|
610
|
+
return { serverVersion: raw != null ? toFiniteNumber(raw) : null };
|
|
611
|
+
}
|
|
612
|
+
/** VSS backup status: { backup_exists, server_version, backup_required } → camelCase, no BigInt. */
|
|
613
|
+
async vssBackupInfo() {
|
|
614
|
+
this.assertConnected();
|
|
615
|
+
const raw = (await this.account.vssBackupInfo());
|
|
616
|
+
return {
|
|
617
|
+
backupExists: Boolean(raw?.backup_exists),
|
|
618
|
+
serverVersion: raw?.server_version != null ? toFiniteNumber(raw.server_version) : null,
|
|
619
|
+
backupRequired: Boolean(raw?.backup_required),
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
/** Download and restore wallet state from the configured VSS server. */
|
|
623
|
+
async vssRestoreBackup() {
|
|
624
|
+
this.assertConnected();
|
|
625
|
+
await this.account.vssRestoreBackup();
|
|
626
|
+
await this.flushState();
|
|
627
|
+
}
|
|
628
|
+
async disconnect() {
|
|
629
|
+
this.online = null;
|
|
630
|
+
await super.disconnect();
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
function normalizeRgbLibTimestamp(confTime) {
|
|
634
|
+
if (typeof confTime === 'number' || typeof confTime === 'string' || typeof confTime === 'bigint') {
|
|
635
|
+
return toFiniteNumber(confTime);
|
|
636
|
+
}
|
|
637
|
+
if (confTime && typeof confTime === 'object') {
|
|
638
|
+
const obj = confTime;
|
|
639
|
+
return firstFiniteNumber(obj.timestamp, obj.blockTime, obj.block_time, obj.time) ?? 0;
|
|
640
|
+
}
|
|
641
|
+
return 0;
|
|
642
|
+
}
|
|
643
|
+
/** rgb-lib serializes an Outpoint as `{txid,vout}` or the `"txid:vout"` string. */
|
|
644
|
+
function formatOutpoint(outpoint) {
|
|
645
|
+
if (typeof outpoint === 'string')
|
|
646
|
+
return outpoint;
|
|
647
|
+
if (outpoint && typeof outpoint === 'object') {
|
|
648
|
+
const o = outpoint;
|
|
649
|
+
const txid = o.txid ?? o.txId;
|
|
650
|
+
const vout = o.vout ?? o.index;
|
|
651
|
+
if (txid != null && vout != null)
|
|
652
|
+
return `${txid}:${vout}`;
|
|
653
|
+
}
|
|
654
|
+
return '';
|
|
655
|
+
}
|
|
656
|
+
function toRgbLibAssignment(assignment, amount) {
|
|
657
|
+
if (assignment?.type && assignment.type !== 'Fungible') {
|
|
658
|
+
throw new ProtocolError(`Unsupported RGB-L1 assignment type: ${assignment.type}`, 'RGB_L1', 'INVALID_REQUEST');
|
|
659
|
+
}
|
|
660
|
+
return { Fungible: Math.round(amount) };
|
|
661
|
+
}
|
|
662
|
+
function readRgbLibBtcBalanceBucket(bucket) {
|
|
663
|
+
const settled = toFiniteNumber(bucket?.settled ?? bucket?.confirmed ?? bucket?.total ?? 0);
|
|
664
|
+
const spendable = toFiniteNumber(bucket?.spendable ?? bucket?.available ?? settled);
|
|
665
|
+
const future = toFiniteNumber(bucket?.future ?? bucket?.unconfirmed ?? spendable);
|
|
666
|
+
return { settled, spendable, future };
|
|
667
|
+
}
|
|
668
|
+
/** Map rgb-lib's `TransactionType` to a stable string; unknowns ⇒ "User". */
|
|
669
|
+
function normalizeRgbLibTxType(raw) {
|
|
670
|
+
const v = String(raw ?? '');
|
|
671
|
+
if (v === 'RgbSend' || v === 'CreateUtxos')
|
|
672
|
+
return v;
|
|
673
|
+
return 'User';
|
|
674
|
+
}
|
|
675
|
+
function normalizeRgbLibTransactionAmounts(t) {
|
|
676
|
+
const explicitReceived = firstFiniteNumber(t.received, t.receivedSat, t.received_sat, t.incoming, t.incomingSat, t.incoming_sat);
|
|
677
|
+
const explicitSent = firstFiniteNumber(t.sent, t.sentSat, t.sent_sat, t.outgoing, t.outgoingSat, t.outgoing_sat);
|
|
678
|
+
if (explicitReceived !== null || explicitSent !== null) {
|
|
679
|
+
const received = explicitReceived ?? 0;
|
|
680
|
+
const sent = explicitSent ?? 0;
|
|
681
|
+
return { received, sent, type: received >= sent ? 'receive' : 'send' };
|
|
682
|
+
}
|
|
683
|
+
const rawDirection = String(t.type ?? t.direction ?? t.transactionDirection ?? '').toLowerCase();
|
|
684
|
+
const signedAmount = firstFiniteNumber(t.amount, t.amountSat, t.amount_sat, t.value, t.valueSat);
|
|
685
|
+
const amount = Math.abs(signedAmount ?? 0);
|
|
686
|
+
if (rawDirection.includes('send') || rawDirection.includes('out') || (signedAmount ?? 0) < 0) {
|
|
687
|
+
return { received: 0, sent: amount, type: 'send' };
|
|
688
|
+
}
|
|
689
|
+
return { received: amount, sent: 0, type: 'receive' };
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Normalize an rgb-lib-wasm asset record into the shape `RgbCore.rgbNiaAsset`
|
|
693
|
+
* expects (it may use camelCase `assetId` or snake_case `asset_id`).
|
|
694
|
+
*/
|
|
695
|
+
function normalizeAsset(a) {
|
|
696
|
+
return {
|
|
697
|
+
asset_id: a?.assetId ?? a?.asset_id ?? a?.id ?? '',
|
|
698
|
+
name: a?.name,
|
|
699
|
+
ticker: a?.ticker,
|
|
700
|
+
precision: a?.precision,
|
|
701
|
+
balance: normalizeAssetBalance(a?.balance ?? a),
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
function normalizeAssetBalance(a) {
|
|
705
|
+
if (!a)
|
|
706
|
+
return undefined;
|
|
707
|
+
return {
|
|
708
|
+
settled: a.settled ?? a.total,
|
|
709
|
+
future: a.future ?? a.pending,
|
|
710
|
+
spendable: a.spendable ?? a.available,
|
|
711
|
+
offchain_outbound: a.offchain_outbound ?? a.offchainOutbound ?? a.locked,
|
|
712
|
+
offchain_inbound: a.offchain_inbound ?? a.offchainInbound,
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function toFiniteNumber(value) {
|
|
716
|
+
if (typeof value === 'bigint')
|
|
717
|
+
return Number(value);
|
|
718
|
+
const n = Number(value ?? 0);
|
|
719
|
+
return Number.isFinite(n) ? n : 0;
|
|
720
|
+
}
|
|
721
|
+
function firstFiniteNumber(...values) {
|
|
722
|
+
for (const value of values) {
|
|
723
|
+
if (value === null || value === undefined || value === '')
|
|
724
|
+
continue;
|
|
725
|
+
const n = typeof value === 'bigint' ? Number(value) : Number(value);
|
|
726
|
+
if (Number.isFinite(n))
|
|
727
|
+
return n;
|
|
728
|
+
}
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
//# sourceMappingURL=RgbLibWasmAdapter.js.map
|