@cogcoin/client 0.5.0

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 (289) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +136 -0
  3. package/dist/app-paths.d.ts +38 -0
  4. package/dist/app-paths.js +121 -0
  5. package/dist/art/banner.txt +13 -0
  6. package/dist/art/scroll.txt +13 -0
  7. package/dist/art/train-car.txt +6 -0
  8. package/dist/art/train-smoke.txt +6 -0
  9. package/dist/art/train.txt +6 -0
  10. package/dist/bitcoind/bootstrap/chainstate.d.ts +4 -0
  11. package/dist/bitcoind/bootstrap/chainstate.js +13 -0
  12. package/dist/bitcoind/bootstrap/constants.d.ts +7 -0
  13. package/dist/bitcoind/bootstrap/constants.js +12 -0
  14. package/dist/bitcoind/bootstrap/controller.d.ts +29 -0
  15. package/dist/bitcoind/bootstrap/controller.js +101 -0
  16. package/dist/bitcoind/bootstrap/download.d.ts +2 -0
  17. package/dist/bitcoind/bootstrap/download.js +196 -0
  18. package/dist/bitcoind/bootstrap/headers.d.ts +13 -0
  19. package/dist/bitcoind/bootstrap/headers.js +61 -0
  20. package/dist/bitcoind/bootstrap/paths.d.ts +4 -0
  21. package/dist/bitcoind/bootstrap/paths.js +15 -0
  22. package/dist/bitcoind/bootstrap/snapshot-file.d.ts +7 -0
  23. package/dist/bitcoind/bootstrap/snapshot-file.js +42 -0
  24. package/dist/bitcoind/bootstrap/state.d.ts +40 -0
  25. package/dist/bitcoind/bootstrap/state.js +70 -0
  26. package/dist/bitcoind/bootstrap/types.d.ts +28 -0
  27. package/dist/bitcoind/bootstrap/types.js +1 -0
  28. package/dist/bitcoind/bootstrap.d.ts +8 -0
  29. package/dist/bitcoind/bootstrap.js +7 -0
  30. package/dist/bitcoind/client/factory.d.ts +3 -0
  31. package/dist/bitcoind/client/factory.js +57 -0
  32. package/dist/bitcoind/client/follow-block-times.d.ts +8 -0
  33. package/dist/bitcoind/client/follow-block-times.js +25 -0
  34. package/dist/bitcoind/client/follow-loop.d.ts +10 -0
  35. package/dist/bitcoind/client/follow-loop.js +57 -0
  36. package/dist/bitcoind/client/internal-types.d.ts +63 -0
  37. package/dist/bitcoind/client/internal-types.js +18 -0
  38. package/dist/bitcoind/client/managed-client.d.ts +20 -0
  39. package/dist/bitcoind/client/managed-client.js +197 -0
  40. package/dist/bitcoind/client/rate-tracker.d.ts +2 -0
  41. package/dist/bitcoind/client/rate-tracker.js +24 -0
  42. package/dist/bitcoind/client/sync-engine.d.ts +3 -0
  43. package/dist/bitcoind/client/sync-engine.js +143 -0
  44. package/dist/bitcoind/client.d.ts +1 -0
  45. package/dist/bitcoind/client.js +1 -0
  46. package/dist/bitcoind/errors.d.ts +1 -0
  47. package/dist/bitcoind/errors.js +49 -0
  48. package/dist/bitcoind/index.d.ts +2 -0
  49. package/dist/bitcoind/index.js +1 -0
  50. package/dist/bitcoind/indexer-daemon-main.d.ts +1 -0
  51. package/dist/bitcoind/indexer-daemon-main.js +472 -0
  52. package/dist/bitcoind/indexer-daemon.d.ts +107 -0
  53. package/dist/bitcoind/indexer-daemon.js +391 -0
  54. package/dist/bitcoind/node.d.ts +8 -0
  55. package/dist/bitcoind/node.js +219 -0
  56. package/dist/bitcoind/normalize.d.ts +3 -0
  57. package/dist/bitcoind/normalize.js +47 -0
  58. package/dist/bitcoind/progress/assets.d.ts +10 -0
  59. package/dist/bitcoind/progress/assets.js +90 -0
  60. package/dist/bitcoind/progress/constants.d.ts +48 -0
  61. package/dist/bitcoind/progress/constants.js +53 -0
  62. package/dist/bitcoind/progress/controller.d.ts +28 -0
  63. package/dist/bitcoind/progress/controller.js +188 -0
  64. package/dist/bitcoind/progress/follow-scene.d.ts +40 -0
  65. package/dist/bitcoind/progress/follow-scene.js +367 -0
  66. package/dist/bitcoind/progress/formatting.d.ts +23 -0
  67. package/dist/bitcoind/progress/formatting.js +227 -0
  68. package/dist/bitcoind/progress/quote-scene.d.ts +4 -0
  69. package/dist/bitcoind/progress/quote-scene.js +137 -0
  70. package/dist/bitcoind/progress/train-scene.d.ts +9 -0
  71. package/dist/bitcoind/progress/train-scene.js +92 -0
  72. package/dist/bitcoind/progress/tty-renderer.d.ts +18 -0
  73. package/dist/bitcoind/progress/tty-renderer.js +150 -0
  74. package/dist/bitcoind/progress.d.ts +7 -0
  75. package/dist/bitcoind/progress.js +7 -0
  76. package/dist/bitcoind/quotes.d.ts +24 -0
  77. package/dist/bitcoind/quotes.js +195 -0
  78. package/dist/bitcoind/rpc.d.ts +71 -0
  79. package/dist/bitcoind/rpc.js +322 -0
  80. package/dist/bitcoind/service-paths.d.ts +19 -0
  81. package/dist/bitcoind/service-paths.js +49 -0
  82. package/dist/bitcoind/service.d.ts +40 -0
  83. package/dist/bitcoind/service.js +735 -0
  84. package/dist/bitcoind/testing.d.ts +9 -0
  85. package/dist/bitcoind/testing.js +9 -0
  86. package/dist/bitcoind/types.d.ts +396 -0
  87. package/dist/bitcoind/types.js +3 -0
  88. package/dist/bytes.d.ts +9 -0
  89. package/dist/bytes.js +36 -0
  90. package/dist/cli/commands/follow.d.ts +2 -0
  91. package/dist/cli/commands/follow.js +43 -0
  92. package/dist/cli/commands/mining-admin.d.ts +2 -0
  93. package/dist/cli/commands/mining-admin.js +92 -0
  94. package/dist/cli/commands/mining-read.d.ts +2 -0
  95. package/dist/cli/commands/mining-read.js +173 -0
  96. package/dist/cli/commands/mining-runtime.d.ts +2 -0
  97. package/dist/cli/commands/mining-runtime.js +108 -0
  98. package/dist/cli/commands/status.d.ts +2 -0
  99. package/dist/cli/commands/status.js +31 -0
  100. package/dist/cli/commands/sync.d.ts +2 -0
  101. package/dist/cli/commands/sync.js +52 -0
  102. package/dist/cli/commands/wallet-admin.d.ts +2 -0
  103. package/dist/cli/commands/wallet-admin.js +175 -0
  104. package/dist/cli/commands/wallet-mutation.d.ts +2 -0
  105. package/dist/cli/commands/wallet-mutation.js +681 -0
  106. package/dist/cli/commands/wallet-read.d.ts +2 -0
  107. package/dist/cli/commands/wallet-read.js +265 -0
  108. package/dist/cli/context.d.ts +3 -0
  109. package/dist/cli/context.js +75 -0
  110. package/dist/cli/io.d.ts +3 -0
  111. package/dist/cli/io.js +12 -0
  112. package/dist/cli/mining-format.d.ts +5 -0
  113. package/dist/cli/mining-format.js +156 -0
  114. package/dist/cli/mining-json.d.ts +49 -0
  115. package/dist/cli/mining-json.js +89 -0
  116. package/dist/cli/mutation-command-groups.d.ts +15 -0
  117. package/dist/cli/mutation-command-groups.js +71 -0
  118. package/dist/cli/mutation-json.d.ts +430 -0
  119. package/dist/cli/mutation-json.js +311 -0
  120. package/dist/cli/mutation-resolved-json.d.ts +124 -0
  121. package/dist/cli/mutation-resolved-json.js +129 -0
  122. package/dist/cli/mutation-success.d.ts +20 -0
  123. package/dist/cli/mutation-success.js +47 -0
  124. package/dist/cli/mutation-text-format.d.ts +22 -0
  125. package/dist/cli/mutation-text-format.js +171 -0
  126. package/dist/cli/mutation-text-write.d.ts +13 -0
  127. package/dist/cli/mutation-text-write.js +16 -0
  128. package/dist/cli/output.d.ts +185 -0
  129. package/dist/cli/output.js +1085 -0
  130. package/dist/cli/parse.d.ts +3 -0
  131. package/dist/cli/parse.js +971 -0
  132. package/dist/cli/preview-json.d.ts +416 -0
  133. package/dist/cli/preview-json.js +293 -0
  134. package/dist/cli/prompt.d.ts +3 -0
  135. package/dist/cli/prompt.js +33 -0
  136. package/dist/cli/read-json.d.ts +187 -0
  137. package/dist/cli/read-json.js +675 -0
  138. package/dist/cli/runner.d.ts +2 -0
  139. package/dist/cli/runner.js +129 -0
  140. package/dist/cli/signals.d.ts +3 -0
  141. package/dist/cli/signals.js +63 -0
  142. package/dist/cli/status-format.d.ts +2 -0
  143. package/dist/cli/status-format.js +48 -0
  144. package/dist/cli/types.d.ts +148 -0
  145. package/dist/cli/types.js +2 -0
  146. package/dist/cli/wallet-format.d.ts +29 -0
  147. package/dist/cli/wallet-format.js +637 -0
  148. package/dist/cli/workflow-hints.d.ts +13 -0
  149. package/dist/cli/workflow-hints.js +94 -0
  150. package/dist/cli-runner.d.ts +3 -0
  151. package/dist/cli-runner.js +3 -0
  152. package/dist/cli.d.ts +2 -0
  153. package/dist/cli.js +6 -0
  154. package/dist/client/default-client.d.ts +11 -0
  155. package/dist/client/default-client.js +118 -0
  156. package/dist/client/factory.d.ts +2 -0
  157. package/dist/client/factory.js +15 -0
  158. package/dist/client/initialization.d.ts +6 -0
  159. package/dist/client/initialization.js +30 -0
  160. package/dist/client/persistence.d.ts +5 -0
  161. package/dist/client/persistence.js +28 -0
  162. package/dist/client/store-adapter.d.ts +3 -0
  163. package/dist/client/store-adapter.js +20 -0
  164. package/dist/client.d.ts +2 -0
  165. package/dist/client.js +2 -0
  166. package/dist/index.d.ts +2 -0
  167. package/dist/index.js +1 -0
  168. package/dist/passive-status.d.ts +36 -0
  169. package/dist/passive-status.js +100 -0
  170. package/dist/sqlite/better-sqlite3.d.ts +26 -0
  171. package/dist/sqlite/better-sqlite3.js +4 -0
  172. package/dist/sqlite/checkpoints.d.ts +11 -0
  173. package/dist/sqlite/checkpoints.js +27 -0
  174. package/dist/sqlite/driver.d.ts +17 -0
  175. package/dist/sqlite/driver.js +98 -0
  176. package/dist/sqlite/index.d.ts +4 -0
  177. package/dist/sqlite/index.js +9 -0
  178. package/dist/sqlite/migrate.d.ts +2 -0
  179. package/dist/sqlite/migrate.js +37 -0
  180. package/dist/sqlite/store.d.ts +3 -0
  181. package/dist/sqlite/store.js +122 -0
  182. package/dist/sqlite/tip-meta.d.ts +26 -0
  183. package/dist/sqlite/tip-meta.js +97 -0
  184. package/dist/sqlite/types.d.ts +10 -0
  185. package/dist/sqlite/types.js +1 -0
  186. package/dist/types.d.ts +55 -0
  187. package/dist/types.js +1 -0
  188. package/dist/wallet/archive.d.ts +4 -0
  189. package/dist/wallet/archive.js +39 -0
  190. package/dist/wallet/cogop/constants.d.ts +32 -0
  191. package/dist/wallet/cogop/constants.js +32 -0
  192. package/dist/wallet/cogop/index.d.ts +32 -0
  193. package/dist/wallet/cogop/index.js +213 -0
  194. package/dist/wallet/cogop/numeric.d.ts +3 -0
  195. package/dist/wallet/cogop/numeric.js +24 -0
  196. package/dist/wallet/cogop/scriptpubkey.d.ts +2 -0
  197. package/dist/wallet/cogop/scriptpubkey.js +13 -0
  198. package/dist/wallet/cogop/validate-name.d.ts +2 -0
  199. package/dist/wallet/cogop/validate-name.js +18 -0
  200. package/dist/wallet/fs/atomic.d.ts +6 -0
  201. package/dist/wallet/fs/atomic.js +46 -0
  202. package/dist/wallet/fs/lock.d.ts +19 -0
  203. package/dist/wallet/fs/lock.js +61 -0
  204. package/dist/wallet/fs/status-file.d.ts +1 -0
  205. package/dist/wallet/fs/status-file.js +4 -0
  206. package/dist/wallet/lifecycle.d.ts +193 -0
  207. package/dist/wallet/lifecycle.js +1475 -0
  208. package/dist/wallet/material.d.ts +45 -0
  209. package/dist/wallet/material.js +118 -0
  210. package/dist/wallet/mining/config.d.ts +18 -0
  211. package/dist/wallet/mining/config.js +44 -0
  212. package/dist/wallet/mining/constants.d.ts +24 -0
  213. package/dist/wallet/mining/constants.js +24 -0
  214. package/dist/wallet/mining/control.d.ts +53 -0
  215. package/dist/wallet/mining/control.js +758 -0
  216. package/dist/wallet/mining/coordination.d.ts +40 -0
  217. package/dist/wallet/mining/coordination.js +121 -0
  218. package/dist/wallet/mining/hook-protocol.d.ts +47 -0
  219. package/dist/wallet/mining/hook-protocol.js +161 -0
  220. package/dist/wallet/mining/hook-runner.d.ts +1 -0
  221. package/dist/wallet/mining/hook-runner.js +52 -0
  222. package/dist/wallet/mining/hooks.d.ts +38 -0
  223. package/dist/wallet/mining/hooks.js +520 -0
  224. package/dist/wallet/mining/index.d.ts +8 -0
  225. package/dist/wallet/mining/index.js +6 -0
  226. package/dist/wallet/mining/runner.d.ts +155 -0
  227. package/dist/wallet/mining/runner.js +2574 -0
  228. package/dist/wallet/mining/runtime-artifacts.d.ts +17 -0
  229. package/dist/wallet/mining/runtime-artifacts.js +166 -0
  230. package/dist/wallet/mining/sentences.d.ts +23 -0
  231. package/dist/wallet/mining/sentences.js +281 -0
  232. package/dist/wallet/mining/state.d.ts +9 -0
  233. package/dist/wallet/mining/state.js +75 -0
  234. package/dist/wallet/mining/types.d.ts +141 -0
  235. package/dist/wallet/mining/types.js +1 -0
  236. package/dist/wallet/mining/visualizer.d.ts +19 -0
  237. package/dist/wallet/mining/visualizer.js +134 -0
  238. package/dist/wallet/mining/worker-main.d.ts +1 -0
  239. package/dist/wallet/mining/worker-main.js +17 -0
  240. package/dist/wallet/read/context.d.ts +20 -0
  241. package/dist/wallet/read/context.js +532 -0
  242. package/dist/wallet/read/filter.d.ts +9 -0
  243. package/dist/wallet/read/filter.js +42 -0
  244. package/dist/wallet/read/index.d.ts +4 -0
  245. package/dist/wallet/read/index.js +3 -0
  246. package/dist/wallet/read/project.d.ts +11 -0
  247. package/dist/wallet/read/project.js +300 -0
  248. package/dist/wallet/read/types.d.ts +144 -0
  249. package/dist/wallet/read/types.js +1 -0
  250. package/dist/wallet/runtime.d.ts +26 -0
  251. package/dist/wallet/runtime.js +28 -0
  252. package/dist/wallet/state/crypto.d.ts +31 -0
  253. package/dist/wallet/state/crypto.js +127 -0
  254. package/dist/wallet/state/provider.d.ts +37 -0
  255. package/dist/wallet/state/provider.js +312 -0
  256. package/dist/wallet/state/session.d.ts +12 -0
  257. package/dist/wallet/state/session.js +23 -0
  258. package/dist/wallet/state/storage.d.ts +19 -0
  259. package/dist/wallet/state/storage.js +55 -0
  260. package/dist/wallet/tx/anchor.d.ts +40 -0
  261. package/dist/wallet/tx/anchor.js +1210 -0
  262. package/dist/wallet/tx/cog.d.ts +92 -0
  263. package/dist/wallet/tx/cog.js +1055 -0
  264. package/dist/wallet/tx/common.d.ts +89 -0
  265. package/dist/wallet/tx/common.js +156 -0
  266. package/dist/wallet/tx/confirm.d.ts +15 -0
  267. package/dist/wallet/tx/confirm.js +24 -0
  268. package/dist/wallet/tx/domain-admin.d.ts +105 -0
  269. package/dist/wallet/tx/domain-admin.js +869 -0
  270. package/dist/wallet/tx/domain-market.d.ts +112 -0
  271. package/dist/wallet/tx/domain-market.js +1365 -0
  272. package/dist/wallet/tx/field.d.ts +101 -0
  273. package/dist/wallet/tx/field.js +1853 -0
  274. package/dist/wallet/tx/identity-selector.d.ts +12 -0
  275. package/dist/wallet/tx/identity-selector.js +52 -0
  276. package/dist/wallet/tx/index.d.ts +7 -0
  277. package/dist/wallet/tx/index.js +7 -0
  278. package/dist/wallet/tx/journal.d.ts +5 -0
  279. package/dist/wallet/tx/journal.js +31 -0
  280. package/dist/wallet/tx/register.d.ts +68 -0
  281. package/dist/wallet/tx/register.js +952 -0
  282. package/dist/wallet/tx/reputation.d.ts +72 -0
  283. package/dist/wallet/tx/reputation.js +693 -0
  284. package/dist/wallet/tx/targets.d.ts +7 -0
  285. package/dist/wallet/tx/targets.js +122 -0
  286. package/dist/wallet/types.d.ts +249 -0
  287. package/dist/wallet/types.js +1 -0
  288. package/dist/writing_quotes.json +1654 -0
  289. package/package.json +78 -0
@@ -0,0 +1,300 @@
1
+ import { getLock, getBalance, getListing, getReputation, listActiveLocksByDomain, listDomainsByOwner, listFields, lookupDomain, resolveCanonical, } from "@cogcoin/indexer/queries";
2
+ function bytesToHex(value) {
3
+ if (value === null || value === undefined) {
4
+ return null;
5
+ }
6
+ return Buffer.from(value).toString("hex");
7
+ }
8
+ function scriptHexToBytes(scriptPubKeyHex) {
9
+ return new Uint8Array(Buffer.from(scriptPubKeyHex, "hex"));
10
+ }
11
+ function tryDecodeUtf8(value) {
12
+ if (value === null || value === undefined) {
13
+ return null;
14
+ }
15
+ try {
16
+ return new TextDecoder("utf8", { fatal: true }).decode(value);
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ export function createWalletReadModel(walletState, snapshot) {
23
+ const snapshotState = snapshot?.state ?? null;
24
+ const localIdentityByScript = new Map();
25
+ const identities = walletState.identities
26
+ .slice()
27
+ .sort((left, right) => left.index - right.index)
28
+ .map((identity) => {
29
+ const scriptBytes = scriptHexToBytes(identity.scriptPubKeyHex);
30
+ const ownedDomains = snapshotState === null
31
+ ? []
32
+ : listDomainsByOwner(snapshotState, scriptBytes).sort((left, right) => left.name.localeCompare(right.name));
33
+ const anchoredOwnedDomains = ownedDomains.filter((domain) => domain.anchored);
34
+ const canonicalDomainId = snapshotState === null ? null : resolveCanonical(snapshotState, scriptBytes);
35
+ const canonicalDomainName = canonicalDomainId === null || snapshotState === null
36
+ ? null
37
+ : (snapshotState ? lookupDomainById(snapshotState, canonicalDomainId)?.name ?? null : null);
38
+ const readOnly = identity.status === "read-only" || anchoredOwnedDomains.length > 1;
39
+ const observedCogBalance = snapshotState === null ? null : getBalance(snapshotState, scriptBytes);
40
+ const view = {
41
+ index: identity.index,
42
+ scriptPubKeyHex: identity.scriptPubKeyHex,
43
+ address: identity.address,
44
+ selectors: [
45
+ `id:${identity.index}`,
46
+ ...ownedDomains.map((domain) => `domain:${domain.name}`),
47
+ ...(identity.address === null ? [] : [identity.address]),
48
+ `spk:${identity.scriptPubKeyHex}`,
49
+ ],
50
+ assignedDomainNames: identity.assignedDomainNames.slice().sort((left, right) => left.localeCompare(right)),
51
+ localStatus: identity.status,
52
+ effectiveStatus: readOnly ? "read-only" : identity.status,
53
+ canonicalDomainId,
54
+ canonicalDomainName,
55
+ ownedDomainNames: ownedDomains.map((domain) => domain.name),
56
+ anchoredOwnedDomainNames: anchoredOwnedDomains.map((domain) => domain.name),
57
+ observedCogBalance,
58
+ readOnly,
59
+ };
60
+ localIdentityByScript.set(identity.scriptPubKeyHex, view);
61
+ return view;
62
+ });
63
+ const domainNames = new Set();
64
+ for (const domain of walletState.domains) {
65
+ domainNames.add(domain.name);
66
+ }
67
+ if (snapshotState !== null) {
68
+ for (const identity of identities) {
69
+ for (const name of identity.ownedDomainNames) {
70
+ domainNames.add(name);
71
+ }
72
+ }
73
+ }
74
+ const domains = [...domainNames]
75
+ .sort((left, right) => left.localeCompare(right))
76
+ .map((name) => {
77
+ const localRecord = walletState.domains.find((domain) => domain.name === name) ?? null;
78
+ const chainRecord = snapshotState === null ? null : lookupDomain(snapshotState, name);
79
+ const ownerScriptPubKeyHex = chainRecord ? bytesToHex(chainRecord.ownerScriptPubKey) : localRecord?.currentOwnerScriptPubKeyHex ?? null;
80
+ const ownerIdentity = ownerScriptPubKeyHex === null ? null : localIdentityByScript.get(ownerScriptPubKeyHex) ?? null;
81
+ const fields = chainRecord && snapshotState ? listFields(snapshotState, chainRecord.domainId) : null;
82
+ const listing = chainRecord && snapshotState ? getListing(snapshotState, chainRecord.domainId) : null;
83
+ const activeLocks = chainRecord && snapshotState ? listActiveLocksByDomain(snapshotState, chainRecord.domainId) : null;
84
+ const reputation = chainRecord && snapshotState ? getReputation(snapshotState, chainRecord.domainId) : null;
85
+ const readOnly = ownerIdentity?.readOnly ?? (localRecord?.currentOwnerLocalIndex !== null && localRecord?.currentOwnerLocalIndex !== undefined
86
+ ? identities.find((identity) => identity.index === localRecord.currentOwnerLocalIndex)?.readOnly ?? false
87
+ : false);
88
+ let localRelationship = "external";
89
+ if (ownerIdentity !== null) {
90
+ localRelationship = readOnly ? "read-only" : "owned";
91
+ }
92
+ else if (localRecord !== null) {
93
+ localRelationship = "tracked";
94
+ }
95
+ else if (ownerScriptPubKeyHex === null) {
96
+ localRelationship = "unknown";
97
+ }
98
+ return {
99
+ name,
100
+ domainId: chainRecord?.domainId ?? localRecord?.domainId ?? null,
101
+ anchored: chainRecord?.anchored ?? (localRecord?.canonicalChainStatus === "anchored" ? true : localRecord?.canonicalChainStatus === "registered-unanchored" ? false : null),
102
+ ownerScriptPubKeyHex,
103
+ ownerLocalIndex: ownerIdentity?.index ?? localRecord?.currentOwnerLocalIndex ?? null,
104
+ ownerAddress: ownerIdentity?.address ?? null,
105
+ localTracked: localRecord !== null,
106
+ localRecord,
107
+ chainFound: chainRecord !== null,
108
+ chainStatus: chainRecord === null
109
+ ? localRecord?.canonicalChainStatus ?? "unknown"
110
+ : chainRecord.anchored ? "anchored" : "registered-unanchored",
111
+ localAnchorIntent: localRecord?.localAnchorIntent ?? null,
112
+ foundingMessageText: chainRecord?.foundingMessage ?? localRecord?.foundingMessageText ?? null,
113
+ endpointText: tryDecodeUtf8(chainRecord?.endpoint),
114
+ delegateScriptPubKeyHex: bytesToHex(chainRecord?.delegate),
115
+ minerScriptPubKeyHex: bytesToHex(chainRecord?.miner),
116
+ fieldCount: fields?.length ?? null,
117
+ listingPriceCogtoshi: listing?.priceCogtoshi ?? null,
118
+ activeLockCount: activeLocks?.length ?? null,
119
+ selfStakeCogtoshi: reputation?.selfStake ?? null,
120
+ supportedStakeCogtoshi: reputation?.supportedStake ?? null,
121
+ totalSupportedCogtoshi: reputation?.totalSupported ?? null,
122
+ totalRevokedCogtoshi: reputation?.totalRevoked ?? null,
123
+ readOnly,
124
+ localRelationship,
125
+ };
126
+ });
127
+ return {
128
+ walletRootId: walletState.walletRootId,
129
+ fundingIdentity: identities.find((identity) => identity.index === walletState.fundingIndex) ?? null,
130
+ identities,
131
+ domains,
132
+ readOnlyIdentityCount: identities.filter((identity) => identity.readOnly).length,
133
+ };
134
+ }
135
+ function lookupDomainById(state, domainId) {
136
+ for (const record of state.consensus.domainsById.values()) {
137
+ if (record.domainId === domainId) {
138
+ return { name: record.name };
139
+ }
140
+ }
141
+ return null;
142
+ }
143
+ export function listWalletLocks(context) {
144
+ if (context.snapshot === null || context.model === null) {
145
+ return null;
146
+ }
147
+ const localScriptToIndex = new Map(context.model.identities.map((identity) => [identity.scriptPubKeyHex, identity.index]));
148
+ const localDomainIds = new Set(context.model.domains
149
+ .map((domain) => domain.domainId)
150
+ .filter((domainId) => domainId !== null));
151
+ const currentHeight = context.snapshot.state.history.currentHeight;
152
+ const domainsById = new Map(context.model.domains
153
+ .map((domain) => domain.domainId === null ? null : [domain.domainId, domain.name])
154
+ .filter((entry) => entry !== null));
155
+ const locks = [...context.snapshot.state.consensus.locks.values()]
156
+ .filter((lock) => {
157
+ const lockerHex = bytesToHex(lock.lockerScriptPubKey);
158
+ return (lockerHex !== null && localScriptToIndex.has(lockerHex)) || localDomainIds.has(lock.recipientDomainId);
159
+ })
160
+ .sort((left, right) => left.timeoutHeight - right.timeoutHeight || left.lockId - right.lockId);
161
+ return locks.map((lock) => {
162
+ const lockerScriptPubKeyHex = bytesToHex(lock.lockerScriptPubKey);
163
+ const lockerLocalIndex = lockerScriptPubKeyHex === null ? null : localScriptToIndex.get(lockerScriptPubKeyHex) ?? null;
164
+ const recipientDomain = context.snapshot.state.consensus.domainsById.get(lock.recipientDomainId) ?? null;
165
+ const recipientOwnerHex = recipientDomain === null ? null : bytesToHex(recipientDomain.ownerScriptPubKey);
166
+ const claimableNow = currentHeight !== null
167
+ && currentHeight < lock.timeoutHeight
168
+ && recipientOwnerHex !== null
169
+ && localScriptToIndex.has(recipientOwnerHex);
170
+ return {
171
+ lockId: lock.lockId,
172
+ status: "active",
173
+ amountCogtoshi: lock.amount,
174
+ timeoutHeight: lock.timeoutHeight,
175
+ lockerScriptPubKeyHex: lockerScriptPubKeyHex ?? "",
176
+ lockerLocalIndex,
177
+ recipientDomainId: lock.recipientDomainId,
178
+ recipientDomainName: domainsById.get(lock.recipientDomainId) ?? null,
179
+ recipientLocal: localDomainIds.has(lock.recipientDomainId),
180
+ claimableNow,
181
+ reclaimableNow: currentHeight !== null && currentHeight >= lock.timeoutHeight && lockerLocalIndex !== null,
182
+ };
183
+ });
184
+ }
185
+ export function findWalletLock(context, lockId) {
186
+ if (context.snapshot === null) {
187
+ return null;
188
+ }
189
+ return getLock(context.snapshot.state, lockId);
190
+ }
191
+ export function findWalletDomain(context, name) {
192
+ const domain = context.model?.domains.find((entry) => entry.name === name)
193
+ ?? (context.snapshot
194
+ ? (() => {
195
+ const chainDomain = lookupDomain(context.snapshot.state, name);
196
+ if (chainDomain === null) {
197
+ return null;
198
+ }
199
+ return {
200
+ name: chainDomain.name,
201
+ domainId: chainDomain.domainId,
202
+ anchored: chainDomain.anchored,
203
+ ownerScriptPubKeyHex: bytesToHex(chainDomain.ownerScriptPubKey),
204
+ ownerLocalIndex: null,
205
+ ownerAddress: null,
206
+ localTracked: false,
207
+ localRecord: null,
208
+ chainFound: true,
209
+ chainStatus: chainDomain.anchored ? "anchored" : "registered-unanchored",
210
+ localAnchorIntent: null,
211
+ foundingMessageText: chainDomain.foundingMessage,
212
+ endpointText: tryDecodeUtf8(chainDomain.endpoint),
213
+ delegateScriptPubKeyHex: bytesToHex(chainDomain.delegate),
214
+ minerScriptPubKeyHex: bytesToHex(chainDomain.miner),
215
+ fieldCount: listFields(context.snapshot.state, chainDomain.domainId).length,
216
+ listingPriceCogtoshi: getListing(context.snapshot.state, chainDomain.domainId)?.priceCogtoshi ?? null,
217
+ activeLockCount: listActiveLocksByDomain(context.snapshot.state, chainDomain.domainId).length,
218
+ selfStakeCogtoshi: getReputation(context.snapshot.state, chainDomain.domainId)?.selfStake ?? null,
219
+ supportedStakeCogtoshi: getReputation(context.snapshot.state, chainDomain.domainId)?.supportedStake ?? null,
220
+ totalSupportedCogtoshi: getReputation(context.snapshot.state, chainDomain.domainId)?.totalSupported ?? null,
221
+ totalRevokedCogtoshi: getReputation(context.snapshot.state, chainDomain.domainId)?.totalRevoked ?? null,
222
+ readOnly: false,
223
+ localRelationship: "external",
224
+ };
225
+ })()
226
+ : null);
227
+ if (domain === null) {
228
+ return null;
229
+ }
230
+ return {
231
+ domain,
232
+ localRelationship: domain.localRelationship,
233
+ };
234
+ }
235
+ export function listDomainFields(context, name) {
236
+ if (context.snapshot === null) {
237
+ return null;
238
+ }
239
+ const domain = lookupDomain(context.snapshot.state, name);
240
+ if (domain === null) {
241
+ return null;
242
+ }
243
+ return listFields(context.snapshot.state, domain.domainId)
244
+ .slice()
245
+ .sort((left, right) => left.fieldId - right.fieldId)
246
+ .map((field) => {
247
+ const value = readDomainDataByName(context.snapshot.state, domain.domainId, field.name);
248
+ return {
249
+ domainName: name,
250
+ domainId: domain.domainId,
251
+ fieldId: field.fieldId,
252
+ name: field.name,
253
+ permanent: field.permanent,
254
+ hasValue: value !== null,
255
+ format: value?.format ?? null,
256
+ preview: value === null ? null : createFieldPreview(value.value, value.format),
257
+ rawValueHex: value === null ? null : Buffer.from(value.value).toString("hex"),
258
+ };
259
+ });
260
+ }
261
+ export function findDomainField(context, domainName, fieldName) {
262
+ return listDomainFields(context, domainName)?.find((field) => field.name === fieldName) ?? null;
263
+ }
264
+ export function createFieldPreview(value, format) {
265
+ if (value.length === 0) {
266
+ return "(empty)";
267
+ }
268
+ const decoded = tryDecodeUtf8(value);
269
+ if ((format === 0x02 || format === 0x09) && decoded !== null) {
270
+ return decoded.length <= 80 ? decoded : `${decoded.slice(0, 77)}...`;
271
+ }
272
+ const hex = Buffer.from(value).toString("hex");
273
+ return hex.length <= 64 ? `hex:${hex}` : `hex:${hex.slice(0, 61)}...`;
274
+ }
275
+ export function formatFieldFormat(format) {
276
+ if (format === null) {
277
+ return "none";
278
+ }
279
+ if (format === 0x00) {
280
+ return "clear (0x00)";
281
+ }
282
+ if (format === 0x01) {
283
+ return "bytes (0x01)";
284
+ }
285
+ if (format === 0x02) {
286
+ return "text (0x02)";
287
+ }
288
+ if (format === 0x09) {
289
+ return "json (0x09)";
290
+ }
291
+ return `raw (0x${format.toString(16).padStart(2, "0")})`;
292
+ }
293
+ function readDomainDataByName(state, domainId, fieldName) {
294
+ const key = `${domainId}:${fieldName}`;
295
+ const fieldId = state.consensus.fieldIdsByName.get(key);
296
+ if (fieldId === undefined) {
297
+ return null;
298
+ }
299
+ return state.consensus.domainData.get(`${domainId}:${fieldId}`) ?? null;
300
+ }
@@ -0,0 +1,144 @@
1
+ import type { IndexerState } from "@cogcoin/indexer/types";
2
+ import type { ManagedBitcoindHealth, ManagedBitcoindObservedStatus, ManagedCoreWalletReplicaStatus, ManagedIndexerDaemonObservedStatus, ManagedIndexerTruthSource } from "../../bitcoind/types.js";
3
+ import type { ClientTip } from "../../types.js";
4
+ import type { MiningControlPlaneView } from "../mining/index.js";
5
+ import type { DomainRecord as LocalDomainRecord, LocalIdentityRecord, WalletStateV1 } from "../types.js";
6
+ export type WalletStateAvailability = "uninitialized" | "locked" | "ready" | "local-state-corrupt";
7
+ export type WalletServiceHealth = "synced" | "catching-up" | "reorging" | "starting" | "stale-heartbeat" | "failed" | "schema-mismatch" | "service-version-mismatch" | "wallet-root-mismatch" | "unavailable";
8
+ export interface WalletLocalStateStatus {
9
+ availability: WalletStateAvailability;
10
+ walletRootId: string | null;
11
+ state: WalletStateV1 | null;
12
+ source: "primary" | "backup" | null;
13
+ unlockUntilUnixMs: number | null;
14
+ hasPrimaryStateFile: boolean;
15
+ hasBackupStateFile: boolean;
16
+ hasUnlockSessionFile: boolean;
17
+ message: string | null;
18
+ }
19
+ export interface WalletNodeStatus {
20
+ ready: boolean;
21
+ chain: string;
22
+ pid: number | null;
23
+ walletRootId: string | null;
24
+ nodeBestHeight: number | null;
25
+ nodeBestHashHex: string | null;
26
+ nodeHeaderHeight: number | null;
27
+ serviceUpdatedAtUnixMs: number | null;
28
+ serviceStatus: ManagedBitcoindObservedStatus | null;
29
+ walletReplica: ManagedCoreWalletReplicaStatus | null;
30
+ walletReplicaMessage?: string | null;
31
+ }
32
+ export interface WalletBitcoindStatus {
33
+ health: ManagedBitcoindHealth;
34
+ status: ManagedBitcoindObservedStatus | null;
35
+ message: string | null;
36
+ }
37
+ export interface WalletIndexerStatus {
38
+ health: WalletServiceHealth;
39
+ status: ManagedIndexerDaemonObservedStatus | null;
40
+ message: string | null;
41
+ snapshotTip: ClientTip | null;
42
+ source?: ManagedIndexerTruthSource;
43
+ daemonInstanceId?: string | null;
44
+ snapshotSeq?: string | null;
45
+ openedAtUnixMs?: number | null;
46
+ }
47
+ export interface WalletSnapshotView {
48
+ state: IndexerState;
49
+ tip: ClientTip | null;
50
+ source?: "lease";
51
+ daemonInstanceId?: string | null;
52
+ snapshotSeq?: string | null;
53
+ openedAtUnixMs?: number | null;
54
+ }
55
+ export interface WalletIdentityView {
56
+ index: number;
57
+ scriptPubKeyHex: string;
58
+ address: string | null;
59
+ selectors: string[];
60
+ assignedDomainNames: string[];
61
+ localStatus: LocalIdentityRecord["status"];
62
+ effectiveStatus: LocalIdentityRecord["status"];
63
+ canonicalDomainId: number | null;
64
+ canonicalDomainName: string | null;
65
+ ownedDomainNames: string[];
66
+ anchoredOwnedDomainNames: string[];
67
+ observedCogBalance: bigint | null;
68
+ readOnly: boolean;
69
+ }
70
+ export interface WalletDomainView {
71
+ name: string;
72
+ domainId: number | null;
73
+ anchored: boolean | null;
74
+ ownerScriptPubKeyHex: string | null;
75
+ ownerLocalIndex: number | null;
76
+ ownerAddress: string | null;
77
+ localTracked: boolean;
78
+ localRecord: LocalDomainRecord | null;
79
+ chainFound: boolean;
80
+ chainStatus: LocalDomainRecord["canonicalChainStatus"];
81
+ localAnchorIntent: LocalDomainRecord["localAnchorIntent"] | null;
82
+ foundingMessageText: string | null;
83
+ endpointText: string | null;
84
+ delegateScriptPubKeyHex: string | null;
85
+ minerScriptPubKeyHex: string | null;
86
+ fieldCount: number | null;
87
+ listingPriceCogtoshi: bigint | null;
88
+ activeLockCount: number | null;
89
+ selfStakeCogtoshi: bigint | null;
90
+ supportedStakeCogtoshi: bigint | null;
91
+ totalSupportedCogtoshi: bigint | null;
92
+ totalRevokedCogtoshi: bigint | null;
93
+ readOnly: boolean;
94
+ localRelationship: "owned" | "read-only" | "tracked" | "external" | "unknown";
95
+ }
96
+ export interface WalletReadModel {
97
+ walletRootId: string;
98
+ fundingIdentity: WalletIdentityView | null;
99
+ identities: WalletIdentityView[];
100
+ domains: WalletDomainView[];
101
+ readOnlyIdentityCount: number;
102
+ }
103
+ export interface WalletReadContext {
104
+ dataDir: string;
105
+ databasePath: string;
106
+ localState: WalletLocalStateStatus;
107
+ bitcoind: WalletBitcoindStatus;
108
+ nodeStatus: WalletNodeStatus | null;
109
+ nodeHealth: WalletServiceHealth;
110
+ nodeMessage: string | null;
111
+ indexer: WalletIndexerStatus;
112
+ snapshot: WalletSnapshotView | null;
113
+ model: WalletReadModel | null;
114
+ mining?: MiningControlPlaneView;
115
+ close(): Promise<void>;
116
+ }
117
+ export interface WalletLockView {
118
+ lockId: number;
119
+ status: "active" | "claimed" | "reclaimed";
120
+ amountCogtoshi: bigint;
121
+ timeoutHeight: number;
122
+ lockerScriptPubKeyHex: string;
123
+ lockerLocalIndex: number | null;
124
+ recipientDomainId: number;
125
+ recipientDomainName: string | null;
126
+ recipientLocal: boolean;
127
+ claimableNow: boolean;
128
+ reclaimableNow: boolean;
129
+ }
130
+ export interface WalletFieldView {
131
+ domainName: string;
132
+ domainId: number;
133
+ fieldId: number;
134
+ name: string;
135
+ permanent: boolean;
136
+ hasValue: boolean;
137
+ format: number | null;
138
+ preview: string | null;
139
+ rawValueHex: string | null;
140
+ }
141
+ export interface WalletDomainDetailsView {
142
+ domain: WalletDomainView;
143
+ localRelationship: WalletDomainView["localRelationship"];
144
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import type { CogcoinPathResolution } from "../app-paths.js";
2
+ export interface WalletRuntimePaths {
3
+ dataRoot: string;
4
+ clientConfigPath: string;
5
+ runtimeRoot: string;
6
+ hooksRoot: string;
7
+ stateRoot: string;
8
+ bitcoinDataDir: string;
9
+ indexerRoot: string;
10
+ walletStatePath: string;
11
+ walletStateBackupPath: string;
12
+ walletUnlockSessionPath: string;
13
+ walletControlLockPath: string;
14
+ bitcoindLockPath: string;
15
+ bitcoindStatusPath: string;
16
+ indexerDaemonLockPath: string;
17
+ indexerStatusPath: string;
18
+ hooksMiningDir: string;
19
+ hooksMiningEntrypointPath: string;
20
+ hooksMiningPackageJsonPath: string;
21
+ miningRoot: string;
22
+ miningStatusPath: string;
23
+ miningEventsPath: string;
24
+ miningControlLockPath: string;
25
+ }
26
+ export declare function resolveWalletRuntimePathsForTesting(resolution?: CogcoinPathResolution): WalletRuntimePaths;
@@ -0,0 +1,28 @@
1
+ import { resolveCogcoinPathsForTesting } from "../app-paths.js";
2
+ export function resolveWalletRuntimePathsForTesting(resolution = {}) {
3
+ const paths = resolveCogcoinPathsForTesting(resolution);
4
+ return {
5
+ dataRoot: paths.dataRoot,
6
+ clientConfigPath: paths.clientConfigPath,
7
+ runtimeRoot: paths.runtimeRoot,
8
+ hooksRoot: paths.hooksRoot,
9
+ stateRoot: paths.stateRoot,
10
+ bitcoinDataDir: paths.bitcoinDataDir,
11
+ indexerRoot: paths.indexerRoot,
12
+ walletStatePath: paths.walletStatePath,
13
+ walletStateBackupPath: paths.walletStateBackupPath,
14
+ walletUnlockSessionPath: paths.walletUnlockSessionPath,
15
+ walletControlLockPath: paths.walletControlLockPath,
16
+ bitcoindLockPath: paths.bitcoindLockPath,
17
+ bitcoindStatusPath: paths.bitcoindStatusPath,
18
+ indexerDaemonLockPath: paths.indexerDaemonLockPath,
19
+ indexerStatusPath: paths.indexerStatusPath,
20
+ hooksMiningDir: paths.hooksMiningDir,
21
+ hooksMiningEntrypointPath: paths.hooksMiningEntrypointPath,
22
+ hooksMiningPackageJsonPath: paths.hooksMiningPackageJsonPath,
23
+ miningRoot: paths.miningRoot,
24
+ miningStatusPath: paths.miningStatusPath,
25
+ miningEventsPath: paths.miningEventsPath,
26
+ miningControlLockPath: paths.miningControlLockPath,
27
+ };
28
+ }
@@ -0,0 +1,31 @@
1
+ import type { Argon2EnvelopeParams, EncryptedEnvelopeV1 } from "../types.js";
2
+ import type { WalletSecretProvider, WalletSecretReference } from "./provider.js";
3
+ export interface DeriveKeyOptions {
4
+ memoryKib?: number;
5
+ iterations?: number;
6
+ parallelism?: number;
7
+ salt?: Uint8Array;
8
+ }
9
+ export interface DerivedKeyMaterial {
10
+ readonly key: Buffer;
11
+ readonly params: Argon2EnvelopeParams;
12
+ }
13
+ export declare function deriveKeyFromPassphrase(passphrase: Uint8Array | string, options?: DeriveKeyOptions): Promise<DerivedKeyMaterial>;
14
+ export declare function rederiveKeyFromEnvelope(passphrase: Uint8Array | string, envelope: EncryptedEnvelopeV1): Promise<Buffer>;
15
+ export declare function encryptBytesWithKey(plaintext: Uint8Array, key: Uint8Array, metadata: {
16
+ format: string;
17
+ wrappedBy: string;
18
+ argon2id?: Argon2EnvelopeParams | null;
19
+ secretProvider?: WalletSecretReference | null;
20
+ }): EncryptedEnvelopeV1;
21
+ export declare function decryptBytesWithKey(envelope: EncryptedEnvelopeV1, key: Uint8Array): Buffer;
22
+ export declare function encryptJsonWithPassphrase<T>(value: T, passphrase: Uint8Array | string, metadata: {
23
+ format: string;
24
+ wrappedBy?: string;
25
+ }): Promise<EncryptedEnvelopeV1>;
26
+ export declare function encryptJsonWithSecretProvider<T>(value: T, provider: WalletSecretProvider, secretReference: WalletSecretReference, metadata: {
27
+ format: string;
28
+ wrappedBy?: string;
29
+ }): Promise<EncryptedEnvelopeV1>;
30
+ export declare function decryptJsonWithPassphrase<T>(envelope: EncryptedEnvelopeV1, passphrase: Uint8Array | string): Promise<T>;
31
+ export declare function decryptJsonWithSecretProvider<T>(envelope: EncryptedEnvelopeV1, provider: WalletSecretProvider): Promise<T>;
@@ -0,0 +1,127 @@
1
+ import { argon2, createCipheriv, createDecipheriv, randomBytes, } from "node:crypto";
2
+ const DEFAULT_ARGON2_MEMORY_KIB = 65_536;
3
+ const DEFAULT_ARGON2_ITERATIONS = 3;
4
+ const DEFAULT_ARGON2_PARALLELISM = 1;
5
+ const DERIVED_KEY_LENGTH = 32;
6
+ const GCM_NONCE_BYTES = 12;
7
+ const ARGON2_SALT_BYTES = 16;
8
+ const BIGINT_JSON_TAG = "$cogcoinBigInt";
9
+ function jsonReplacer(_key, value) {
10
+ if (typeof value === "bigint") {
11
+ return {
12
+ [BIGINT_JSON_TAG]: value.toString(),
13
+ };
14
+ }
15
+ return value;
16
+ }
17
+ function jsonReviver(_key, value) {
18
+ if (value !== null
19
+ && typeof value === "object"
20
+ && BIGINT_JSON_TAG in value
21
+ && typeof value[BIGINT_JSON_TAG] === "string") {
22
+ return BigInt(value[BIGINT_JSON_TAG]);
23
+ }
24
+ return value;
25
+ }
26
+ function deriveArgon2Key(message, nonce, memoryKib, iterations, parallelism) {
27
+ return new Promise((resolve, reject) => {
28
+ argon2("argon2id", {
29
+ message,
30
+ nonce,
31
+ memory: memoryKib,
32
+ passes: iterations,
33
+ parallelism,
34
+ tagLength: DERIVED_KEY_LENGTH,
35
+ }, (error, derivedKey) => {
36
+ if (error) {
37
+ reject(error);
38
+ return;
39
+ }
40
+ resolve(Buffer.from(derivedKey));
41
+ });
42
+ });
43
+ }
44
+ export async function deriveKeyFromPassphrase(passphrase, options = {}) {
45
+ const salt = Buffer.from(options.salt ?? randomBytes(ARGON2_SALT_BYTES));
46
+ const passphraseBytes = typeof passphrase === "string"
47
+ ? Buffer.from(passphrase, "utf8")
48
+ : Buffer.from(passphrase);
49
+ const memoryKib = options.memoryKib ?? DEFAULT_ARGON2_MEMORY_KIB;
50
+ const iterations = options.iterations ?? DEFAULT_ARGON2_ITERATIONS;
51
+ const parallelism = options.parallelism ?? DEFAULT_ARGON2_PARALLELISM;
52
+ const key = await deriveArgon2Key(passphraseBytes, salt, memoryKib, iterations, parallelism);
53
+ return {
54
+ key,
55
+ params: {
56
+ name: "argon2id",
57
+ memoryKib,
58
+ iterations,
59
+ parallelism,
60
+ salt: salt.toString("base64"),
61
+ },
62
+ };
63
+ }
64
+ export async function rederiveKeyFromEnvelope(passphrase, envelope) {
65
+ if (envelope.argon2id == null) {
66
+ throw new Error("wallet_envelope_not_passphrase_wrapped");
67
+ }
68
+ const passphraseBytes = typeof passphrase === "string"
69
+ ? Buffer.from(passphrase, "utf8")
70
+ : Buffer.from(passphrase);
71
+ const salt = Buffer.from(envelope.argon2id.salt, "base64");
72
+ return deriveArgon2Key(passphraseBytes, salt, envelope.argon2id.memoryKib, envelope.argon2id.iterations, envelope.argon2id.parallelism);
73
+ }
74
+ export function encryptBytesWithKey(plaintext, key, metadata) {
75
+ const nonce = randomBytes(GCM_NONCE_BYTES);
76
+ const cipher = createCipheriv("aes-256-gcm", Buffer.from(key), nonce);
77
+ const ciphertext = Buffer.concat([cipher.update(Buffer.from(plaintext)), cipher.final()]);
78
+ const tag = cipher.getAuthTag();
79
+ return {
80
+ format: metadata.format,
81
+ version: 1,
82
+ cipher: "aes-256-gcm",
83
+ wrappedBy: metadata.wrappedBy,
84
+ argon2id: metadata.argon2id ?? null,
85
+ secretProvider: metadata.secretProvider ?? null,
86
+ nonce: nonce.toString("base64"),
87
+ tag: tag.toString("base64"),
88
+ ciphertext: ciphertext.toString("base64"),
89
+ };
90
+ }
91
+ export function decryptBytesWithKey(envelope, key) {
92
+ const decipher = createDecipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(envelope.nonce, "base64"));
93
+ decipher.setAuthTag(Buffer.from(envelope.tag, "base64"));
94
+ return Buffer.concat([
95
+ decipher.update(Buffer.from(envelope.ciphertext, "base64")),
96
+ decipher.final(),
97
+ ]);
98
+ }
99
+ export async function encryptJsonWithPassphrase(value, passphrase, metadata) {
100
+ const derived = await deriveKeyFromPassphrase(passphrase);
101
+ return encryptBytesWithKey(Buffer.from(JSON.stringify(value, jsonReplacer)), derived.key, {
102
+ format: metadata.format,
103
+ wrappedBy: metadata.wrappedBy ?? "passphrase",
104
+ argon2id: derived.params,
105
+ });
106
+ }
107
+ export async function encryptJsonWithSecretProvider(value, provider, secretReference, metadata) {
108
+ const key = await provider.loadSecret(secretReference.keyId);
109
+ return encryptBytesWithKey(Buffer.from(JSON.stringify(value, jsonReplacer)), key, {
110
+ format: metadata.format,
111
+ wrappedBy: metadata.wrappedBy ?? "secret-provider",
112
+ secretProvider: secretReference,
113
+ });
114
+ }
115
+ export async function decryptJsonWithPassphrase(envelope, passphrase) {
116
+ const key = await rederiveKeyFromEnvelope(passphrase, envelope);
117
+ const plaintext = decryptBytesWithKey(envelope, key);
118
+ return JSON.parse(plaintext.toString("utf8"), jsonReviver);
119
+ }
120
+ export async function decryptJsonWithSecretProvider(envelope, provider) {
121
+ if (envelope.secretProvider == null) {
122
+ throw new Error("wallet_envelope_missing_secret_provider");
123
+ }
124
+ const key = await provider.loadSecret(envelope.secretProvider.keyId);
125
+ const plaintext = decryptBytesWithKey(envelope, key);
126
+ return JSON.parse(plaintext.toString("utf8"), jsonReviver);
127
+ }