@arkade-os/sdk 0.3.12 → 0.4.0-next.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 (250) hide show
  1. package/README.md +483 -54
  2. package/dist/cjs/adapters/expo-db.js +35 -0
  3. package/dist/cjs/asset/assetGroup.js +141 -0
  4. package/dist/cjs/asset/assetId.js +88 -0
  5. package/dist/cjs/asset/assetInput.js +204 -0
  6. package/dist/cjs/asset/assetOutput.js +159 -0
  7. package/dist/cjs/asset/assetRef.js +82 -0
  8. package/dist/cjs/asset/index.js +24 -0
  9. package/dist/cjs/asset/metadata.js +172 -0
  10. package/dist/cjs/asset/packet.js +164 -0
  11. package/dist/cjs/asset/types.js +25 -0
  12. package/dist/cjs/asset/utils.js +105 -0
  13. package/dist/cjs/contracts/arkcontract.js +148 -0
  14. package/dist/cjs/contracts/contractManager.js +436 -0
  15. package/dist/cjs/contracts/contractWatcher.js +567 -0
  16. package/dist/cjs/contracts/handlers/default.js +85 -0
  17. package/dist/cjs/contracts/handlers/delegate.js +89 -0
  18. package/dist/cjs/contracts/handlers/helpers.js +105 -0
  19. package/dist/cjs/contracts/handlers/index.js +19 -0
  20. package/dist/cjs/contracts/handlers/registry.js +89 -0
  21. package/dist/cjs/contracts/handlers/vhtlc.js +193 -0
  22. package/dist/cjs/contracts/index.js +41 -0
  23. package/dist/cjs/contracts/types.js +2 -0
  24. package/dist/cjs/db/manager.js +97 -0
  25. package/dist/cjs/forfeit.js +12 -8
  26. package/dist/cjs/identity/index.js +1 -0
  27. package/dist/cjs/identity/seedIdentity.js +255 -0
  28. package/dist/cjs/index.js +70 -14
  29. package/dist/cjs/intent/index.js +28 -2
  30. package/dist/cjs/providers/ark.js +7 -0
  31. package/dist/cjs/providers/delegator.js +66 -0
  32. package/dist/cjs/providers/expoIndexer.js +5 -0
  33. package/dist/cjs/providers/indexer.js +68 -1
  34. package/dist/cjs/providers/onchain.js +2 -2
  35. package/dist/cjs/providers/utils.js +1 -0
  36. package/dist/cjs/repositories/contractRepository.js +0 -103
  37. package/dist/cjs/repositories/inMemory/contractRepository.js +55 -0
  38. package/dist/cjs/repositories/inMemory/walletRepository.js +80 -0
  39. package/dist/cjs/repositories/index.js +16 -0
  40. package/dist/cjs/repositories/indexedDB/contractRepository.js +187 -0
  41. package/dist/cjs/repositories/indexedDB/db.js +57 -0
  42. package/dist/cjs/repositories/indexedDB/schema.js +159 -0
  43. package/dist/cjs/repositories/indexedDB/walletRepository.js +338 -0
  44. package/dist/cjs/repositories/indexedDB/websqlAdapter.js +144 -0
  45. package/dist/cjs/repositories/migrations/contractRepositoryImpl.js +127 -0
  46. package/dist/cjs/repositories/migrations/fromStorageAdapter.js +66 -0
  47. package/dist/cjs/repositories/migrations/walletRepositoryImpl.js +180 -0
  48. package/dist/cjs/repositories/walletRepository.js +0 -169
  49. package/dist/cjs/script/base.js +54 -0
  50. package/dist/cjs/script/delegate.js +49 -0
  51. package/dist/cjs/storage/asyncStorage.js +4 -1
  52. package/dist/cjs/storage/fileSystem.js +3 -0
  53. package/dist/cjs/storage/inMemory.js +3 -0
  54. package/dist/cjs/storage/indexedDB.js +5 -1
  55. package/dist/cjs/storage/localStorage.js +3 -0
  56. package/dist/cjs/utils/arkTransaction.js +16 -0
  57. package/dist/cjs/utils/transactionHistory.js +50 -0
  58. package/dist/cjs/utils/txSizeEstimator.js +39 -14
  59. package/dist/cjs/wallet/asset-manager.js +338 -0
  60. package/dist/cjs/wallet/asset.js +117 -0
  61. package/dist/cjs/wallet/batch.js +1 -1
  62. package/dist/cjs/wallet/delegator.js +235 -0
  63. package/dist/cjs/wallet/expo/background.js +133 -0
  64. package/dist/cjs/wallet/expo/index.js +9 -0
  65. package/dist/cjs/wallet/expo/wallet.js +231 -0
  66. package/dist/cjs/wallet/onchain.js +57 -12
  67. package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +568 -0
  68. package/dist/cjs/wallet/serviceWorker/wallet.js +383 -102
  69. package/dist/cjs/wallet/unroll.js +7 -2
  70. package/dist/cjs/wallet/utils.js +60 -0
  71. package/dist/cjs/wallet/validation.js +151 -0
  72. package/dist/cjs/wallet/vtxo-manager.js +1 -1
  73. package/dist/cjs/wallet/wallet.js +702 -260
  74. package/dist/cjs/worker/browser/service-worker-manager.js +82 -0
  75. package/dist/cjs/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
  76. package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +78 -0
  77. package/dist/cjs/worker/expo/index.js +12 -0
  78. package/dist/cjs/worker/expo/processors/contractPollProcessor.js +61 -0
  79. package/dist/cjs/worker/expo/processors/index.js +6 -0
  80. package/dist/cjs/worker/expo/taskQueue.js +41 -0
  81. package/dist/cjs/worker/expo/taskRunner.js +57 -0
  82. package/dist/cjs/worker/messageBus.js +252 -0
  83. package/dist/esm/adapters/expo-db.js +27 -0
  84. package/dist/esm/asset/assetGroup.js +137 -0
  85. package/dist/esm/asset/assetId.js +84 -0
  86. package/dist/esm/asset/assetInput.js +199 -0
  87. package/dist/esm/asset/assetOutput.js +154 -0
  88. package/dist/esm/asset/assetRef.js +78 -0
  89. package/dist/esm/asset/index.js +8 -0
  90. package/dist/esm/asset/metadata.js +167 -0
  91. package/dist/esm/asset/packet.js +159 -0
  92. package/dist/esm/asset/types.js +22 -0
  93. package/dist/esm/asset/utils.js +99 -0
  94. package/dist/esm/contracts/arkcontract.js +141 -0
  95. package/dist/esm/contracts/contractManager.js +432 -0
  96. package/dist/esm/contracts/contractWatcher.js +563 -0
  97. package/dist/esm/contracts/handlers/default.js +82 -0
  98. package/dist/esm/contracts/handlers/delegate.js +86 -0
  99. package/dist/esm/contracts/handlers/helpers.js +66 -0
  100. package/dist/esm/contracts/handlers/index.js +12 -0
  101. package/dist/esm/contracts/handlers/registry.js +86 -0
  102. package/dist/esm/contracts/handlers/vhtlc.js +190 -0
  103. package/dist/esm/contracts/index.js +13 -0
  104. package/dist/esm/contracts/types.js +1 -0
  105. package/dist/esm/db/manager.js +92 -0
  106. package/dist/esm/forfeit.js +11 -8
  107. package/dist/esm/identity/index.js +1 -0
  108. package/dist/esm/identity/seedIdentity.js +249 -0
  109. package/dist/esm/index.js +25 -15
  110. package/dist/esm/intent/index.js +28 -2
  111. package/dist/esm/providers/ark.js +7 -0
  112. package/dist/esm/providers/delegator.js +62 -0
  113. package/dist/esm/providers/expoIndexer.js +5 -0
  114. package/dist/esm/providers/indexer.js +68 -1
  115. package/dist/esm/providers/onchain.js +2 -2
  116. package/dist/esm/providers/utils.js +1 -0
  117. package/dist/esm/repositories/contractRepository.js +1 -101
  118. package/dist/esm/repositories/inMemory/contractRepository.js +51 -0
  119. package/dist/esm/repositories/inMemory/walletRepository.js +76 -0
  120. package/dist/esm/repositories/index.js +8 -0
  121. package/dist/esm/repositories/indexedDB/contractRepository.js +183 -0
  122. package/dist/esm/repositories/indexedDB/db.js +42 -0
  123. package/dist/esm/repositories/indexedDB/schema.js +155 -0
  124. package/dist/esm/repositories/indexedDB/walletRepository.js +334 -0
  125. package/dist/esm/repositories/indexedDB/websqlAdapter.js +138 -0
  126. package/dist/esm/repositories/migrations/contractRepositoryImpl.js +121 -0
  127. package/dist/esm/repositories/migrations/fromStorageAdapter.js +58 -0
  128. package/dist/esm/repositories/migrations/walletRepositoryImpl.js +176 -0
  129. package/dist/esm/repositories/walletRepository.js +1 -167
  130. package/dist/esm/script/base.js +21 -1
  131. package/dist/esm/script/delegate.js +46 -0
  132. package/dist/esm/storage/asyncStorage.js +4 -1
  133. package/dist/esm/storage/fileSystem.js +3 -0
  134. package/dist/esm/storage/inMemory.js +3 -0
  135. package/dist/esm/storage/indexedDB.js +5 -1
  136. package/dist/esm/storage/localStorage.js +3 -0
  137. package/dist/esm/utils/arkTransaction.js +15 -0
  138. package/dist/esm/utils/transactionHistory.js +50 -0
  139. package/dist/esm/utils/txSizeEstimator.js +39 -14
  140. package/dist/esm/wallet/asset-manager.js +333 -0
  141. package/dist/esm/wallet/asset.js +111 -0
  142. package/dist/esm/wallet/batch.js +1 -1
  143. package/dist/esm/wallet/delegator.js +231 -0
  144. package/dist/esm/wallet/expo/background.js +128 -0
  145. package/dist/esm/wallet/expo/index.js +2 -0
  146. package/dist/esm/wallet/expo/wallet.js +194 -0
  147. package/dist/esm/wallet/onchain.js +57 -12
  148. package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +564 -0
  149. package/dist/esm/wallet/serviceWorker/wallet.js +382 -101
  150. package/dist/esm/wallet/unroll.js +7 -2
  151. package/dist/esm/wallet/utils.js +55 -0
  152. package/dist/esm/wallet/validation.js +139 -0
  153. package/dist/esm/wallet/vtxo-manager.js +1 -1
  154. package/dist/esm/wallet/wallet.js +704 -229
  155. package/dist/esm/worker/browser/service-worker-manager.js +76 -0
  156. package/dist/esm/{wallet/serviceWorker → worker/browser}/utils.js +2 -1
  157. package/dist/esm/worker/expo/asyncStorageTaskQueue.js +74 -0
  158. package/dist/esm/worker/expo/index.js +4 -0
  159. package/dist/esm/worker/expo/processors/contractPollProcessor.js +58 -0
  160. package/dist/esm/worker/expo/processors/index.js +1 -0
  161. package/dist/esm/worker/expo/taskQueue.js +37 -0
  162. package/dist/esm/worker/expo/taskRunner.js +54 -0
  163. package/dist/esm/worker/messageBus.js +248 -0
  164. package/dist/types/adapters/expo-db.d.ts +7 -0
  165. package/dist/types/asset/assetGroup.d.ts +28 -0
  166. package/dist/types/asset/assetId.d.ts +19 -0
  167. package/dist/types/asset/assetInput.d.ts +46 -0
  168. package/dist/types/asset/assetOutput.d.ts +39 -0
  169. package/dist/types/asset/assetRef.d.ts +25 -0
  170. package/dist/types/asset/index.d.ts +8 -0
  171. package/dist/types/asset/metadata.d.ts +37 -0
  172. package/dist/types/asset/packet.d.ts +27 -0
  173. package/dist/types/asset/types.d.ts +18 -0
  174. package/dist/types/asset/utils.d.ts +21 -0
  175. package/dist/types/contracts/arkcontract.d.ts +101 -0
  176. package/dist/types/contracts/contractManager.d.ts +331 -0
  177. package/dist/types/contracts/contractWatcher.d.ts +192 -0
  178. package/dist/types/contracts/handlers/default.d.ts +19 -0
  179. package/dist/types/contracts/handlers/delegate.d.ts +21 -0
  180. package/dist/types/contracts/handlers/helpers.d.ts +18 -0
  181. package/dist/types/contracts/handlers/index.d.ts +7 -0
  182. package/dist/types/contracts/handlers/registry.d.ts +65 -0
  183. package/dist/types/contracts/handlers/vhtlc.d.ts +32 -0
  184. package/dist/types/contracts/index.d.ts +14 -0
  185. package/dist/types/contracts/types.d.ts +222 -0
  186. package/dist/types/db/manager.d.ts +22 -0
  187. package/dist/types/forfeit.d.ts +2 -1
  188. package/dist/types/identity/index.d.ts +1 -0
  189. package/dist/types/identity/seedIdentity.d.ts +128 -0
  190. package/dist/types/index.d.ts +21 -12
  191. package/dist/types/intent/index.d.ts +2 -1
  192. package/dist/types/providers/ark.d.ts +11 -2
  193. package/dist/types/providers/delegator.d.ts +29 -0
  194. package/dist/types/providers/indexer.d.ts +11 -1
  195. package/dist/types/repositories/contractRepository.d.ts +30 -19
  196. package/dist/types/repositories/inMemory/contractRepository.d.ts +17 -0
  197. package/dist/types/repositories/inMemory/walletRepository.d.ts +26 -0
  198. package/dist/types/repositories/index.d.ts +7 -0
  199. package/dist/types/repositories/indexedDB/contractRepository.d.ts +21 -0
  200. package/dist/types/repositories/indexedDB/db.d.ts +56 -0
  201. package/dist/types/repositories/indexedDB/schema.d.ts +8 -0
  202. package/dist/types/repositories/indexedDB/walletRepository.d.ts +25 -0
  203. package/dist/types/repositories/indexedDB/websqlAdapter.d.ts +49 -0
  204. package/dist/types/repositories/migrations/contractRepositoryImpl.d.ts +24 -0
  205. package/dist/types/repositories/migrations/fromStorageAdapter.d.ts +19 -0
  206. package/dist/types/repositories/migrations/walletRepositoryImpl.d.ts +27 -0
  207. package/dist/types/repositories/walletRepository.d.ts +13 -24
  208. package/dist/types/script/base.d.ts +1 -0
  209. package/dist/types/script/delegate.d.ts +36 -0
  210. package/dist/types/storage/asyncStorage.d.ts +4 -0
  211. package/dist/types/storage/fileSystem.d.ts +3 -0
  212. package/dist/types/storage/inMemory.d.ts +3 -0
  213. package/dist/types/storage/index.d.ts +3 -0
  214. package/dist/types/storage/indexedDB.d.ts +3 -0
  215. package/dist/types/storage/localStorage.d.ts +3 -0
  216. package/dist/types/utils/arkTransaction.d.ts +6 -0
  217. package/dist/types/utils/txSizeEstimator.d.ts +12 -2
  218. package/dist/types/wallet/asset-manager.d.ts +78 -0
  219. package/dist/types/wallet/asset.d.ts +21 -0
  220. package/dist/types/wallet/batch.d.ts +1 -1
  221. package/dist/types/wallet/delegator.d.ts +24 -0
  222. package/dist/types/wallet/expo/background.d.ts +66 -0
  223. package/dist/types/wallet/expo/index.d.ts +4 -0
  224. package/dist/types/wallet/expo/wallet.d.ts +97 -0
  225. package/dist/types/wallet/index.d.ts +75 -2
  226. package/dist/types/wallet/onchain.d.ts +22 -1
  227. package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +366 -0
  228. package/dist/types/wallet/serviceWorker/wallet.d.ts +20 -11
  229. package/dist/types/wallet/utils.d.ts +13 -1
  230. package/dist/types/wallet/validation.d.ts +24 -0
  231. package/dist/types/wallet/wallet.d.ts +111 -17
  232. package/dist/types/worker/browser/service-worker-manager.d.ts +21 -0
  233. package/dist/types/{wallet/serviceWorker → worker/browser}/utils.d.ts +2 -1
  234. package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +46 -0
  235. package/dist/types/worker/expo/index.d.ts +7 -0
  236. package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +14 -0
  237. package/dist/types/worker/expo/processors/index.d.ts +1 -0
  238. package/dist/types/worker/expo/taskQueue.d.ts +50 -0
  239. package/dist/types/worker/expo/taskRunner.d.ts +42 -0
  240. package/dist/types/worker/messageBus.d.ts +109 -0
  241. package/package.json +71 -17
  242. package/dist/cjs/wallet/serviceWorker/request.js +0 -78
  243. package/dist/cjs/wallet/serviceWorker/response.js +0 -222
  244. package/dist/cjs/wallet/serviceWorker/worker.js +0 -655
  245. package/dist/esm/wallet/serviceWorker/request.js +0 -75
  246. package/dist/esm/wallet/serviceWorker/response.js +0 -219
  247. package/dist/esm/wallet/serviceWorker/worker.js +0 -651
  248. package/dist/types/wallet/serviceWorker/request.d.ts +0 -74
  249. package/dist/types/wallet/serviceWorker/response.d.ts +0 -123
  250. package/dist/types/wallet/serviceWorker/worker.d.ts +0 -53
@@ -0,0 +1,167 @@
1
+ import { schnorr } from "@noble/curves/secp256k1.js";
2
+ import { hex } from "@scure/base";
3
+ import { compareBytes } from "@scure/btc-signer/utils.js";
4
+ import { BufferReader, BufferWriter } from './utils.js';
5
+ /**
6
+ * Metadata represents a key-value pair.
7
+ * @param key - the key
8
+ * @param value - the value
9
+ */
10
+ export class Metadata {
11
+ constructor(key, value) {
12
+ this.key = key;
13
+ this.value = value;
14
+ }
15
+ static create(key, value) {
16
+ const md = new Metadata(key, value);
17
+ md.validate();
18
+ return md;
19
+ }
20
+ static fromString(s) {
21
+ let buf;
22
+ try {
23
+ buf = hex.decode(s);
24
+ }
25
+ catch {
26
+ throw new Error("invalid metadata format, must be hex");
27
+ }
28
+ return Metadata.fromBytes(buf);
29
+ }
30
+ static fromBytes(buf) {
31
+ if (!buf || buf.length === 0) {
32
+ throw new Error("missing metadata");
33
+ }
34
+ const reader = new BufferReader(buf);
35
+ return Metadata.fromReader(reader);
36
+ }
37
+ serialize() {
38
+ const writer = new BufferWriter();
39
+ this.serializeTo(writer);
40
+ return writer.toBytes();
41
+ }
42
+ toString() {
43
+ return hex.encode(this.serialize());
44
+ }
45
+ get keyString() {
46
+ return new TextDecoder().decode(this.key);
47
+ }
48
+ get valueString() {
49
+ return new TextDecoder().decode(this.value);
50
+ }
51
+ validate() {
52
+ if (this.key.length === 0) {
53
+ throw new Error("missing metadata key");
54
+ }
55
+ if (this.value.length === 0) {
56
+ throw new Error("missing metadata value");
57
+ }
58
+ }
59
+ static fromReader(reader) {
60
+ let key;
61
+ let value;
62
+ try {
63
+ key = reader.readVarSlice();
64
+ }
65
+ catch {
66
+ throw new Error("invalid metadata length");
67
+ }
68
+ try {
69
+ value = reader.readVarSlice();
70
+ }
71
+ catch {
72
+ throw new Error("invalid metadata length");
73
+ }
74
+ const md = new Metadata(key, value);
75
+ md.validate();
76
+ return md;
77
+ }
78
+ serializeTo(writer) {
79
+ writer.writeVarSlice(this.key);
80
+ writer.writeVarSlice(this.value);
81
+ }
82
+ }
83
+ export class MetadataList {
84
+ constructor(items) {
85
+ this.items = items;
86
+ }
87
+ static fromString(s) {
88
+ let buf;
89
+ try {
90
+ buf = hex.decode(s);
91
+ }
92
+ catch {
93
+ throw new Error("invalid metadata list format");
94
+ }
95
+ return MetadataList.fromBytes(buf);
96
+ }
97
+ static fromBytes(buf) {
98
+ if (!buf || buf.length === 0) {
99
+ throw new Error("missing metadata list");
100
+ }
101
+ const reader = new BufferReader(buf);
102
+ return MetadataList.fromReader(reader);
103
+ }
104
+ static fromReader(reader) {
105
+ const count = Number(reader.readVarUint());
106
+ const items = Array.from({ length: count }, () => Metadata.fromReader(reader));
107
+ return new MetadataList(items);
108
+ }
109
+ serializeTo(writer) {
110
+ writer.writeVarUint(this.items.length);
111
+ for (const item of this) {
112
+ item.serializeTo(writer);
113
+ }
114
+ }
115
+ serialize() {
116
+ const writer = new BufferWriter();
117
+ this.serializeTo(writer);
118
+ return writer.toBytes();
119
+ }
120
+ [Symbol.iterator]() {
121
+ return this.items[Symbol.iterator]();
122
+ }
123
+ get length() {
124
+ return this.items.length;
125
+ }
126
+ hash() {
127
+ if (this.items.length === 0)
128
+ throw new Error("missing metadata list");
129
+ const levels = buildMetadataMerkleTree(this.items);
130
+ return levels[levels.length - 1][0]; // the last level is the root
131
+ }
132
+ }
133
+ MetadataList.ARK_LEAF_TAG = "ArkadeAssetLeaf";
134
+ MetadataList.ARK_BRANCH_TAG = "ArkadeAssetBranch";
135
+ MetadataList.ARK_LEAF_VERSION = 0x00;
136
+ function computeMetadataLeafHash(md) {
137
+ const writer = new BufferWriter();
138
+ writer.writeByte(MetadataList.ARK_LEAF_VERSION);
139
+ writer.writeVarSlice(md.key);
140
+ writer.writeVarSlice(md.value);
141
+ return schnorr.utils.taggedHash(MetadataList.ARK_LEAF_TAG, writer.toBytes());
142
+ }
143
+ function computeMetadataBranchHash(a, b) {
144
+ const [smaller, larger] = compareBytes(a, b) === -1 ? [a, b] : [b, a];
145
+ return schnorr.utils.taggedHash(MetadataList.ARK_BRANCH_TAG, smaller, larger);
146
+ }
147
+ function buildMetadataMerkleTree(leaves) {
148
+ if (leaves.length === 0)
149
+ return [];
150
+ const leafHashes = leaves.map(computeMetadataLeafHash);
151
+ const levels = [leafHashes];
152
+ let current = leafHashes;
153
+ while (current.length > 1) {
154
+ const next = [];
155
+ for (let i = 0; i < current.length; i += 2) {
156
+ if (i + 1 < current.length) {
157
+ next.push(computeMetadataBranchHash(current[i], current[i + 1]));
158
+ }
159
+ else {
160
+ next.push(current[i]);
161
+ }
162
+ }
163
+ levels.push(next);
164
+ current = next;
165
+ }
166
+ return levels;
167
+ }
@@ -0,0 +1,159 @@
1
+ import { hex } from "@scure/base";
2
+ import { Script } from "@scure/btc-signer";
3
+ import { concatBytes, equalBytes } from "@scure/btc-signer/utils.js";
4
+ import { ARKADE_MAGIC, MARKER_ASSET_PAYLOAD, AssetRefType } from './types.js';
5
+ import { AssetGroup } from './assetGroup.js';
6
+ import { BufferReader, BufferWriter } from './utils.js';
7
+ export class AssetPacketNotFoundError extends Error {
8
+ constructor(txid) {
9
+ super(`asset packet not found in tx ${txid}`);
10
+ this.name = "AssetPacketNotFoundError";
11
+ }
12
+ }
13
+ /**
14
+ * Packet represents a collection of asset groups.
15
+ * A packet is encoded in OP_RETURN output of an asset transaction.
16
+ * @param groups - the asset groups in the packet
17
+ */
18
+ export class Packet {
19
+ constructor(groups) {
20
+ this.groups = groups;
21
+ }
22
+ static create(groups) {
23
+ const p = new Packet(groups);
24
+ p.validate();
25
+ return p;
26
+ }
27
+ static fromString(s) {
28
+ let buf;
29
+ try {
30
+ buf = hex.decode(s);
31
+ }
32
+ catch {
33
+ throw new Error("invalid output script format, must be hex");
34
+ }
35
+ return Packet.fromScript(buf);
36
+ }
37
+ static fromScript(script) {
38
+ const rawPacket = extractRawPacketFromScript(script);
39
+ const reader = new BufferReader(rawPacket);
40
+ return Packet.fromReader(reader);
41
+ }
42
+ static fromTxOut(pkScript) {
43
+ return Packet.fromScript(pkScript);
44
+ }
45
+ static fromTx(tx) {
46
+ for (let i = 0; i < tx.outputsLength; i++) {
47
+ try {
48
+ const output = tx.getOutput(i);
49
+ if (!output?.script) {
50
+ continue;
51
+ }
52
+ return Packet.fromScript(output.script);
53
+ }
54
+ catch (error) {
55
+ continue;
56
+ }
57
+ }
58
+ throw new AssetPacketNotFoundError(tx.id);
59
+ }
60
+ static isAssetPacket(script) {
61
+ try {
62
+ extractRawPacketFromScript(script);
63
+ return true;
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ leafTxPacket(intentTxid) {
70
+ const leafGroups = this.groups.map((group) => group.toBatchLeafAssetGroup(intentTxid));
71
+ return new Packet(leafGroups);
72
+ }
73
+ txOut() {
74
+ return {
75
+ script: this.serialize(),
76
+ amount: 0n,
77
+ };
78
+ }
79
+ serialize() {
80
+ const writer = new BufferWriter();
81
+ writer.writeVarUint(this.groups.length);
82
+ for (const group of this.groups) {
83
+ group.serializeTo(writer);
84
+ }
85
+ const packetData = writer.toBytes();
86
+ const data = concatBytes(ARKADE_MAGIC, new Uint8Array([MARKER_ASSET_PAYLOAD]), packetData);
87
+ return buildOpReturnScript(data);
88
+ }
89
+ toString() {
90
+ return hex.encode(this.serialize());
91
+ }
92
+ validate() {
93
+ if (this.groups.length === 0) {
94
+ throw new Error("missing assets");
95
+ }
96
+ for (const group of this.groups) {
97
+ if (group.controlAsset !== null &&
98
+ group.controlAsset.ref.type === AssetRefType.ByGroup &&
99
+ group.controlAsset.ref.groupIndex >= this.groups.length) {
100
+ throw new Error(`invalid control asset group index, ${group.controlAsset.ref.groupIndex} out of range [0, ${this.groups.length - 1}]`);
101
+ }
102
+ }
103
+ }
104
+ static fromReader(reader) {
105
+ const count = Number(reader.readVarUint());
106
+ const groups = [];
107
+ for (let i = 0; i < count; i++) {
108
+ groups.push(AssetGroup.fromReader(reader));
109
+ }
110
+ if (reader.remaining() > 0) {
111
+ throw new Error(`invalid packet length, left ${reader.remaining()} unknown bytes to read`);
112
+ }
113
+ const packet = new Packet(groups);
114
+ packet.validate();
115
+ return packet;
116
+ }
117
+ }
118
+ function extractRawPacketFromScript(script) {
119
+ if (!script || script.length === 0) {
120
+ throw new Error("missing output script");
121
+ }
122
+ let decoded;
123
+ try {
124
+ decoded = Script.decode(script);
125
+ }
126
+ catch {
127
+ throw new Error("invalid OP_RETURN output script");
128
+ }
129
+ if (decoded.length === 0 || decoded[0] !== "RETURN") {
130
+ throw new Error("OP_RETURN not found in output script");
131
+ }
132
+ // concat all data pushes after RETURN
133
+ const dataPushes = decoded
134
+ .slice(1)
135
+ .filter((item) => item instanceof Uint8Array);
136
+ if (dataPushes.length === 0) {
137
+ throw new Error("missing OP_RETURN data");
138
+ }
139
+ const payload = concatBytes(...dataPushes);
140
+ if (payload.length < ARKADE_MAGIC.length + 1) {
141
+ throw new Error("invalid script length");
142
+ }
143
+ const magicSlice = new Uint8Array(payload.slice(0, ARKADE_MAGIC.length));
144
+ if (!equalBytes(magicSlice, ARKADE_MAGIC)) {
145
+ throw new Error(`invalid magic prefix, got ${hex.encode(magicSlice)} want ${hex.encode(ARKADE_MAGIC)}`);
146
+ }
147
+ const marker = payload[ARKADE_MAGIC.length];
148
+ if (marker !== MARKER_ASSET_PAYLOAD) {
149
+ throw new Error(`invalid asset marker, got ${marker} want ${MARKER_ASSET_PAYLOAD}`);
150
+ }
151
+ const packetData = new Uint8Array(payload.slice(ARKADE_MAGIC.length + 1));
152
+ if (packetData.length === 0) {
153
+ throw new Error("missing packet data");
154
+ }
155
+ return packetData;
156
+ }
157
+ function buildOpReturnScript(data) {
158
+ return Script.encode(["RETURN", data]);
159
+ }
@@ -0,0 +1,22 @@
1
+ export const TX_HASH_SIZE = 32;
2
+ export const ASSET_ID_SIZE = 34;
3
+ export const ASSET_VERSION = 0x01;
4
+ export var AssetInputType;
5
+ (function (AssetInputType) {
6
+ AssetInputType[AssetInputType["Unspecified"] = 0] = "Unspecified";
7
+ AssetInputType[AssetInputType["Local"] = 1] = "Local";
8
+ AssetInputType[AssetInputType["Intent"] = 2] = "Intent";
9
+ })(AssetInputType || (AssetInputType = {}));
10
+ export var AssetRefType;
11
+ (function (AssetRefType) {
12
+ AssetRefType[AssetRefType["Unspecified"] = 0] = "Unspecified";
13
+ AssetRefType[AssetRefType["ByID"] = 1] = "ByID";
14
+ AssetRefType[AssetRefType["ByGroup"] = 2] = "ByGroup";
15
+ })(AssetRefType || (AssetRefType = {}));
16
+ // Presence byte masks for AssetGroup
17
+ export const MASK_ASSET_ID = 0x01;
18
+ export const MASK_CONTROL_ASSET = 0x02;
19
+ export const MASK_METADATA = 0x04;
20
+ // ARK magic bytes and marker
21
+ export const ARKADE_MAGIC = new Uint8Array([0x41, 0x52, 0x4b]); // "ARK"
22
+ export const MARKER_ASSET_PAYLOAD = 0x00;
@@ -0,0 +1,99 @@
1
+ export class BufferWriter {
2
+ constructor() {
3
+ this.buffer = [];
4
+ }
5
+ write(data) {
6
+ for (const byte of data) {
7
+ this.buffer.push(byte);
8
+ }
9
+ }
10
+ writeByte(byte) {
11
+ this.buffer.push(byte & 0xff);
12
+ }
13
+ writeUint16LE(value) {
14
+ const buf = new Uint8Array(2);
15
+ new DataView(buf.buffer).setUint16(0, value, true); // true = little endian
16
+ this.write(buf);
17
+ }
18
+ writeVarUint(value) {
19
+ if (typeof value === "number") {
20
+ if (!Number.isInteger(value) || value < 0) {
21
+ throw new RangeError("writeVarUint: value must be a non-negative integer");
22
+ }
23
+ }
24
+ else if (value < 0n) {
25
+ throw new RangeError("writeVarUint: value must be a non-negative integer");
26
+ }
27
+ const val = typeof value === "number" ? BigInt(value) : value;
28
+ const bytes = [];
29
+ let remaining = val;
30
+ do {
31
+ let byte = Number(remaining & 0x7fn);
32
+ remaining >>= 7n;
33
+ if (remaining > 0n) {
34
+ byte |= 0x80;
35
+ }
36
+ bytes.push(byte);
37
+ } while (remaining > 0n);
38
+ this.write(new Uint8Array(bytes));
39
+ }
40
+ writeVarSlice(data) {
41
+ this.writeVarUint(data.length);
42
+ this.write(data);
43
+ }
44
+ toBytes() {
45
+ return new Uint8Array(this.buffer);
46
+ }
47
+ }
48
+ export class BufferReader {
49
+ constructor(data) {
50
+ this.offset = 0;
51
+ this.view = new DataView(data.buffer, data.byteOffset, data.byteLength);
52
+ }
53
+ remaining() {
54
+ return this.view.byteLength - this.offset;
55
+ }
56
+ readByte() {
57
+ if (this.offset >= this.view.byteLength) {
58
+ throw new Error("unexpected end of buffer");
59
+ }
60
+ return this.view.getUint8(this.offset++);
61
+ }
62
+ readSlice(size) {
63
+ if (this.offset + size > this.view.byteLength) {
64
+ throw new Error("unexpected end of buffer");
65
+ }
66
+ const result = new Uint8Array(this.view.buffer, this.view.byteOffset + this.offset, size);
67
+ this.offset += size;
68
+ return result;
69
+ }
70
+ readUint16LE() {
71
+ if (this.offset + 2 > this.view.byteLength) {
72
+ throw new Error("unexpected end of buffer");
73
+ }
74
+ const value = this.view.getUint16(this.offset, true);
75
+ this.offset += 2;
76
+ return value;
77
+ }
78
+ readVarUint() {
79
+ let result = 0n;
80
+ let shift = 0n;
81
+ let byte;
82
+ do {
83
+ if (this.offset >= this.view.byteLength) {
84
+ throw new Error("unexpected end of buffer");
85
+ }
86
+ byte = this.view.getUint8(this.offset++);
87
+ result |= BigInt(byte & 0x7f) << shift;
88
+ shift += 7n;
89
+ } while (byte & 0x80);
90
+ return result;
91
+ }
92
+ readVarSlice() {
93
+ const length = Number(this.readVarUint());
94
+ return this.readSlice(length);
95
+ }
96
+ }
97
+ export function isZeroBytes(bytes) {
98
+ return bytes.every((byte) => byte === 0);
99
+ }
@@ -0,0 +1,141 @@
1
+ import { hex } from "@scure/base";
2
+ import { contractHandlers } from './handlers/index.js';
3
+ /**
4
+ * Prefix for arkcontract strings.
5
+ */
6
+ const ARKCONTRACT_PREFIX = "arkcontract";
7
+ /**
8
+ * Encode a contract to the arkcontract string format.
9
+ *
10
+ * Format: arkcontract={type}&{key1}={value1}&{key2}={value2}...
11
+ *
12
+ * This format is compatible with NArk and allows contracts to be
13
+ * shared/imported across different Ark implementations.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const contract: Contract = {
18
+ * type: "vhtlc",
19
+ * params: { sender: "ab12...", receiver: "cd34...", ... },
20
+ * // ...
21
+ * };
22
+ *
23
+ * const encoded = encodeArkContract(contract);
24
+ * // "arkcontract=vhtlc&sender=ab12...&receiver=cd34...&..."
25
+ * ```
26
+ */
27
+ export function encodeArkContract(contract) {
28
+ const params = new URLSearchParams();
29
+ // Add contract type first
30
+ params.set(ARKCONTRACT_PREFIX, contract.type);
31
+ // Add all params
32
+ for (const [key, value] of Object.entries(contract.params)) {
33
+ params.set(key, value);
34
+ }
35
+ return params.toString();
36
+ }
37
+ /**
38
+ * Decode an arkcontract string into raw type and data.
39
+ *
40
+ * This is a low-level function that parses the URL-encoded format.
41
+ * For creating typed Contract objects, use `contractFromArkContract`
42
+ * or `contractFromArkContractWithAddress` instead.
43
+ *
44
+ * @param encoded - The arkcontract string
45
+ * @returns Parsed type and key-value data
46
+ * @throws If the string is not a valid arkcontract
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const parsed = decodeArkContract("arkcontract=vhtlc&sender=ab12...");
51
+ * // { type: "vhtlc", data: { sender: "ab12...", ... } }
52
+ * ```
53
+ */
54
+ export function decodeArkContract(encoded) {
55
+ const params = new URLSearchParams(encoded);
56
+ // Extract type from the arkcontract key
57
+ const type = params.get(ARKCONTRACT_PREFIX);
58
+ if (!type) {
59
+ throw new Error(`Invalid arkcontract string: missing '${ARKCONTRACT_PREFIX}' key`);
60
+ }
61
+ // Build data object from all other params
62
+ const data = {};
63
+ for (const [key, value] of params.entries()) {
64
+ if (key !== ARKCONTRACT_PREFIX) {
65
+ data[key] = value;
66
+ }
67
+ }
68
+ return { type, data };
69
+ }
70
+ /**
71
+ * Create a Contract from an arkcontract string.
72
+ *
73
+ * This requires a handler to be registered for the contract type.
74
+ *
75
+ * @param encoded - The arkcontract string
76
+ * @param options - Additional options for the contract
77
+ * @returns A Contract object
78
+ * @throws If the string is invalid or no handler exists for the type
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const contract = contractFromArkContract(
83
+ * "arkcontract=vhtlc&sender=ab12...",
84
+ * {
85
+ * label: "Lightning Receive",
86
+ * }
87
+ * );
88
+ * ```
89
+ */
90
+ export function contractFromArkContract(encoded, options = {}) {
91
+ const parsed = decodeArkContract(encoded);
92
+ const handler = contractHandlers.get(parsed.type);
93
+ if (!handler) {
94
+ throw new Error(`No handler registered for contract type '${parsed.type}'`);
95
+ }
96
+ // Separate params from runtime data
97
+ // This is type-specific - the handler knows which keys are params
98
+ // For now, we treat all data as params
99
+ const params = parsed.data;
100
+ return {
101
+ label: options.label,
102
+ type: parsed.type,
103
+ params,
104
+ state: options.state || "active",
105
+ createdAt: Date.now(),
106
+ expiresAt: options.expiresAt,
107
+ metadata: options.metadata,
108
+ };
109
+ }
110
+ /**
111
+ * Create a full Contract with derived script and address.
112
+ *
113
+ * @param encoded - The arkcontract string
114
+ * @param serverPubKey - Server public key (for address derivation)
115
+ * @param addressPrefix - Address prefix (e.g., "tark" for testnet)
116
+ * @param options - Additional options
117
+ * @returns A complete Contract object
118
+ */
119
+ export function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix, options = {}) {
120
+ const parsed = decodeArkContract(encoded);
121
+ const handler = contractHandlers.getOrThrow(parsed.type);
122
+ const params = parsed.data;
123
+ const vtxoScript = handler.createScript(params);
124
+ return {
125
+ label: options.label,
126
+ type: parsed.type,
127
+ params,
128
+ script: hex.encode(vtxoScript.pkScript),
129
+ address: vtxoScript.address(addressPrefix, serverPubKey).encode(),
130
+ state: options.state || "active",
131
+ createdAt: Date.now(),
132
+ expiresAt: options.expiresAt,
133
+ metadata: options.metadata,
134
+ };
135
+ }
136
+ /**
137
+ * Check if a string is an arkcontract.
138
+ */
139
+ export function isArkContract(str) {
140
+ return str.startsWith(ARKCONTRACT_PREFIX + "=");
141
+ }