@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.
Files changed (242) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -10
  3. package/dist/adapters/ArkadeAdapter.d.ts +78 -14
  4. package/dist/adapters/ArkadeAdapter.d.ts.map +1 -1
  5. package/dist/adapters/ArkadeAdapter.js +653 -161
  6. package/dist/adapters/ArkadeAdapter.js.map +1 -1
  7. package/dist/adapters/IProtocolAdapter.d.ts +195 -18
  8. package/dist/adapters/IProtocolAdapter.d.ts.map +1 -1
  9. package/dist/adapters/IProtocolAdapter.js +6 -2
  10. package/dist/adapters/IProtocolAdapter.js.map +1 -1
  11. package/dist/adapters/RgbAdapter.d.ts +70 -27
  12. package/dist/adapters/RgbAdapter.d.ts.map +1 -1
  13. package/dist/adapters/RgbAdapter.js +464 -370
  14. package/dist/adapters/RgbAdapter.js.map +1 -1
  15. package/dist/adapters/SparkAdapter.d.ts +93 -15
  16. package/dist/adapters/SparkAdapter.d.ts.map +1 -1
  17. package/dist/adapters/SparkAdapter.js +833 -168
  18. package/dist/adapters/SparkAdapter.js.map +1 -1
  19. package/dist/adapters/arkade.d.ts +15 -0
  20. package/dist/adapters/arkade.d.ts.map +1 -0
  21. package/dist/adapters/arkade.js +15 -0
  22. package/dist/adapters/arkade.js.map +1 -0
  23. package/dist/adapters/flashnet.d.ts +15 -0
  24. package/dist/adapters/flashnet.d.ts.map +1 -0
  25. package/dist/adapters/flashnet.js +17 -0
  26. package/dist/adapters/flashnet.js.map +1 -0
  27. package/dist/adapters/native.d.ts +17 -0
  28. package/dist/adapters/native.d.ts.map +1 -0
  29. package/dist/adapters/native.js +17 -0
  30. package/dist/adapters/native.js.map +1 -0
  31. package/dist/adapters/rgb.d.ts +11 -0
  32. package/dist/adapters/rgb.d.ts.map +1 -0
  33. package/dist/adapters/rgb.js +11 -0
  34. package/dist/adapters/rgb.js.map +1 -0
  35. package/dist/adapters/spark.d.ts +12 -0
  36. package/dist/adapters/spark.d.ts.map +1 -0
  37. package/dist/adapters/spark.js +14 -0
  38. package/dist/adapters/spark.js.map +1 -0
  39. package/dist/adapters/wdk/ArkadeWdkAdapter.d.ts +53 -19
  40. package/dist/adapters/wdk/ArkadeWdkAdapter.d.ts.map +1 -1
  41. package/dist/adapters/wdk/ArkadeWdkAdapter.js +366 -90
  42. package/dist/adapters/wdk/ArkadeWdkAdapter.js.map +1 -1
  43. package/dist/adapters/wdk/BaseWdkAdapter.d.ts +40 -0
  44. package/dist/adapters/wdk/BaseWdkAdapter.d.ts.map +1 -0
  45. package/dist/adapters/wdk/BaseWdkAdapter.js +71 -0
  46. package/dist/adapters/wdk/BaseWdkAdapter.js.map +1 -0
  47. package/dist/adapters/wdk/LiquidWdkAdapter.d.ts +6 -13
  48. package/dist/adapters/wdk/LiquidWdkAdapter.d.ts.map +1 -1
  49. package/dist/adapters/wdk/LiquidWdkAdapter.js +14 -32
  50. package/dist/adapters/wdk/LiquidWdkAdapter.js.map +1 -1
  51. package/dist/adapters/wdk/RgbCore.d.ts +64 -0
  52. package/dist/adapters/wdk/RgbCore.d.ts.map +1 -0
  53. package/dist/adapters/wdk/RgbCore.js +111 -0
  54. package/dist/adapters/wdk/RgbCore.js.map +1 -0
  55. package/dist/adapters/wdk/RgbLibWasmAdapter.d.ts +277 -0
  56. package/dist/adapters/wdk/RgbLibWasmAdapter.d.ts.map +1 -0
  57. package/dist/adapters/wdk/RgbLibWasmAdapter.js +731 -0
  58. package/dist/adapters/wdk/RgbLibWasmAdapter.js.map +1 -0
  59. package/dist/adapters/wdk/RgbLibWdkAdapter.d.ts +104 -0
  60. package/dist/adapters/wdk/RgbLibWdkAdapter.d.ts.map +1 -0
  61. package/dist/adapters/wdk/RgbLibWdkAdapter.js +249 -0
  62. package/dist/adapters/wdk/RgbLibWdkAdapter.js.map +1 -0
  63. package/dist/adapters/wdk/RlnWdkAdapter.d.ts +27 -14
  64. package/dist/adapters/wdk/RlnWdkAdapter.d.ts.map +1 -1
  65. package/dist/adapters/wdk/RlnWdkAdapter.js +124 -89
  66. package/dist/adapters/wdk/RlnWdkAdapter.js.map +1 -1
  67. package/dist/adapters/wdk/SparkWdkAdapter.d.ts +74 -41
  68. package/dist/adapters/wdk/SparkWdkAdapter.d.ts.map +1 -1
  69. package/dist/adapters/wdk/SparkWdkAdapter.js +706 -249
  70. package/dist/adapters/wdk/SparkWdkAdapter.js.map +1 -1
  71. package/dist/adapters/wdk/index.d.ts +17 -0
  72. package/dist/adapters/wdk/index.d.ts.map +1 -0
  73. package/dist/adapters/wdk/index.js +17 -0
  74. package/dist/adapters/wdk/index.js.map +1 -0
  75. package/dist/adapters/wdk/wasm-rgb.d.ts +15 -0
  76. package/dist/adapters/wdk/wasm-rgb.d.ts.map +1 -0
  77. package/dist/adapters/wdk/wasm-rgb.js +15 -0
  78. package/dist/adapters/wdk/wasm-rgb.js.map +1 -0
  79. package/dist/capabilities/index.d.ts +1 -1
  80. package/dist/capabilities/index.d.ts.map +1 -1
  81. package/dist/capabilities/index.js +17 -2
  82. package/dist/capabilities/index.js.map +1 -1
  83. package/dist/capabilities/operations.d.ts +22 -0
  84. package/dist/capabilities/operations.d.ts.map +1 -0
  85. package/dist/capabilities/operations.js +62 -0
  86. package/dist/capabilities/operations.js.map +1 -0
  87. package/dist/constants.d.ts +8 -0
  88. package/dist/constants.d.ts.map +1 -0
  89. package/dist/constants.js +8 -0
  90. package/dist/constants.js.map +1 -0
  91. package/dist/disclosure/index.d.ts +1 -1
  92. package/dist/disclosure/index.js +1 -1
  93. package/dist/disclosure/index.js.map +1 -1
  94. package/dist/format.d.ts +11 -0
  95. package/dist/format.d.ts.map +1 -0
  96. package/dist/format.js +10 -0
  97. package/dist/format.js.map +1 -0
  98. package/dist/index.d.ts +21 -31
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +32 -32
  101. package/dist/index.js.map +1 -1
  102. package/dist/lib/arkade-client-manager.d.ts +64 -24
  103. package/dist/lib/arkade-client-manager.d.ts.map +1 -1
  104. package/dist/lib/arkade-client-manager.js +240 -65
  105. package/dist/lib/arkade-client-manager.js.map +1 -1
  106. package/dist/lib/arkade-converters.d.ts +39 -0
  107. package/dist/lib/arkade-converters.d.ts.map +1 -0
  108. package/dist/lib/arkade-converters.js +148 -0
  109. package/dist/lib/arkade-converters.js.map +1 -0
  110. package/dist/lib/arkade-helpers.d.ts +110 -0
  111. package/dist/lib/arkade-helpers.d.ts.map +1 -0
  112. package/dist/lib/arkade-helpers.js +227 -0
  113. package/dist/lib/arkade-helpers.js.map +1 -0
  114. package/dist/lib/arkade-swaps-client-manager.d.ts +55 -0
  115. package/dist/lib/arkade-swaps-client-manager.d.ts.map +1 -0
  116. package/dist/lib/arkade-swaps-client-manager.js +127 -0
  117. package/dist/lib/arkade-swaps-client-manager.js.map +1 -0
  118. package/dist/lib/arkade-vtxo-lifecycle.d.ts +116 -0
  119. package/dist/lib/arkade-vtxo-lifecycle.d.ts.map +1 -0
  120. package/dist/lib/arkade-vtxo-lifecycle.js +184 -0
  121. package/dist/lib/arkade-vtxo-lifecycle.js.map +1 -0
  122. package/dist/lib/flashnet-client-manager.d.ts +26 -9
  123. package/dist/lib/flashnet-client-manager.d.ts.map +1 -1
  124. package/dist/lib/flashnet-client-manager.js +97 -13
  125. package/dist/lib/flashnet-client-manager.js.map +1 -1
  126. package/dist/lib/kaleido-client-manager.d.ts +38 -3
  127. package/dist/lib/kaleido-client-manager.d.ts.map +1 -1
  128. package/dist/lib/kaleido-client-manager.js +79 -10
  129. package/dist/lib/kaleido-client-manager.js.map +1 -1
  130. package/dist/lib/ln-message-sign.d.ts +20 -0
  131. package/dist/lib/ln-message-sign.d.ts.map +1 -0
  132. package/dist/lib/ln-message-sign.js +90 -0
  133. package/dist/lib/ln-message-sign.js.map +1 -0
  134. package/dist/lib/log.d.ts +15 -0
  135. package/dist/lib/log.d.ts.map +1 -0
  136. package/dist/lib/log.js +16 -0
  137. package/dist/lib/log.js.map +1 -0
  138. package/dist/lib/orchestra-client.d.ts +149 -0
  139. package/dist/lib/orchestra-client.d.ts.map +1 -0
  140. package/dist/lib/orchestra-client.js +178 -0
  141. package/dist/lib/orchestra-client.js.map +1 -0
  142. package/dist/lib/psbt-signer.d.ts +60 -0
  143. package/dist/lib/psbt-signer.d.ts.map +1 -0
  144. package/dist/lib/psbt-signer.js +161 -0
  145. package/dist/lib/psbt-signer.js.map +1 -0
  146. package/dist/lib/rgb-converters.d.ts +62 -0
  147. package/dist/lib/rgb-converters.d.ts.map +1 -0
  148. package/dist/lib/rgb-converters.js +179 -0
  149. package/dist/lib/rgb-converters.js.map +1 -0
  150. package/dist/lib/rgb-fee-policy.d.ts +41 -0
  151. package/dist/lib/rgb-fee-policy.d.ts.map +1 -0
  152. package/dist/lib/rgb-fee-policy.js +52 -0
  153. package/dist/lib/rgb-fee-policy.js.map +1 -0
  154. package/dist/lib/rgb-helpers.d.ts +54 -0
  155. package/dist/lib/rgb-helpers.d.ts.map +1 -0
  156. package/dist/lib/rgb-helpers.js +89 -0
  157. package/dist/lib/rgb-helpers.js.map +1 -0
  158. package/dist/lib/spark-activity.d.ts +5 -0
  159. package/dist/lib/spark-activity.d.ts.map +1 -0
  160. package/dist/lib/spark-activity.js +11 -0
  161. package/dist/lib/spark-activity.js.map +1 -0
  162. package/dist/lib/spark-balance-cache.d.ts +58 -0
  163. package/dist/lib/spark-balance-cache.d.ts.map +1 -0
  164. package/dist/lib/spark-balance-cache.js +86 -0
  165. package/dist/lib/spark-balance-cache.js.map +1 -0
  166. package/dist/lib/spark-client-manager.d.ts +64 -10
  167. package/dist/lib/spark-client-manager.d.ts.map +1 -1
  168. package/dist/lib/spark-client-manager.js +191 -35
  169. package/dist/lib/spark-client-manager.js.map +1 -1
  170. package/dist/lib/spark-converters.d.ts +64 -0
  171. package/dist/lib/spark-converters.d.ts.map +1 -0
  172. package/dist/lib/spark-converters.js +242 -0
  173. package/dist/lib/spark-converters.js.map +1 -0
  174. package/dist/lib/spark-helpers.d.ts +72 -0
  175. package/dist/lib/spark-helpers.d.ts.map +1 -0
  176. package/dist/lib/spark-helpers.js +151 -0
  177. package/dist/lib/spark-helpers.js.map +1 -0
  178. package/dist/lib/spark-sent-token-records.d.ts +43 -0
  179. package/dist/lib/spark-sent-token-records.d.ts.map +1 -0
  180. package/dist/lib/spark-sent-token-records.js +105 -0
  181. package/dist/lib/spark-sent-token-records.js.map +1 -0
  182. package/dist/lib/wallet-seed.d.ts +31 -0
  183. package/dist/lib/wallet-seed.d.ts.map +1 -0
  184. package/dist/lib/wallet-seed.js +58 -0
  185. package/dist/lib/wallet-seed.js.map +1 -0
  186. package/dist/lib/zbase32.d.ts +3 -0
  187. package/dist/lib/zbase32.d.ts.map +1 -0
  188. package/dist/lib/zbase32.js +64 -0
  189. package/dist/lib/zbase32.js.map +1 -0
  190. package/dist/manager/ProtocolManager.d.ts +54 -3
  191. package/dist/manager/ProtocolManager.d.ts.map +1 -1
  192. package/dist/manager/ProtocolManager.js +118 -41
  193. package/dist/manager/ProtocolManager.js.map +1 -1
  194. package/dist/ports/index.d.ts +20 -0
  195. package/dist/ports/index.d.ts.map +1 -1
  196. package/dist/ports/index.js +23 -1
  197. package/dist/ports/index.js.map +1 -1
  198. package/dist/receive/unifiedReceive.d.ts +12 -0
  199. package/dist/receive/unifiedReceive.d.ts.map +1 -1
  200. package/dist/receive/unifiedReceive.js +35 -4
  201. package/dist/receive/unifiedReceive.js.map +1 -1
  202. package/dist/registry/createWdkRegistry.d.ts +10 -2
  203. package/dist/registry/createWdkRegistry.d.ts.map +1 -1
  204. package/dist/registry/createWdkRegistry.js +14 -7
  205. package/dist/registry/createWdkRegistry.js.map +1 -1
  206. package/dist/router/destination.d.ts +2 -2
  207. package/dist/router/destination.d.ts.map +1 -1
  208. package/dist/router/destination.js +34 -11
  209. package/dist/router/destination.js.map +1 -1
  210. package/dist/router/index.d.ts +39 -3
  211. package/dist/router/index.d.ts.map +1 -1
  212. package/dist/router/index.js +113 -4
  213. package/dist/router/index.js.map +1 -1
  214. package/dist/router/preference.d.ts +53 -0
  215. package/dist/router/preference.d.ts.map +1 -0
  216. package/dist/router/preference.js +81 -0
  217. package/dist/router/preference.js.map +1 -0
  218. package/dist/swap/KaleidoswapSwap.d.ts +1 -1
  219. package/dist/swap/KaleidoswapSwap.d.ts.map +1 -1
  220. package/dist/swap/KaleidoswapSwap.js +37 -20
  221. package/dist/swap/KaleidoswapSwap.js.map +1 -1
  222. package/dist/swap/index.d.ts +8 -0
  223. package/dist/swap/index.d.ts.map +1 -0
  224. package/dist/swap/index.js +8 -0
  225. package/dist/swap/index.js.map +1 -0
  226. package/dist/types/arkade.d.ts +1 -1
  227. package/dist/types/base.d.ts +35 -25
  228. package/dist/types/base.d.ts.map +1 -1
  229. package/dist/types/base.js +28 -2
  230. package/dist/types/base.js.map +1 -1
  231. package/dist/types/cross-l2.d.ts +1 -1
  232. package/dist/types/flashnet.d.ts +20 -0
  233. package/dist/types/flashnet.d.ts.map +1 -1
  234. package/dist/types/flashnet.js +34 -6
  235. package/dist/types/flashnet.js.map +1 -1
  236. package/dist/types/rgb.d.ts +18 -4
  237. package/dist/types/rgb.d.ts.map +1 -1
  238. package/dist/types/spark.d.ts +1 -1
  239. package/dist/utils.d.ts +1 -1
  240. package/dist/utils.js +2 -2
  241. package/dist/utils.js.map +1 -1
  242. 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