@hivemind-os/collective-core 0.2.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 (145) hide show
  1. package/.test-data/05a845c4-1682-41b9-97e5-65a5263156c0/spending.sqlite +0 -0
  2. package/.test-data/10e18ba5-98f0-42e0-8899-06a09459ae85/agents.sqlite +0 -0
  3. package/.test-data/20464456-23cb-4ff7-8df5-3c129fb95a90/agents.sqlite +0 -0
  4. package/.test-data/2e2ec66c-e8b4-43eb-945f-cca84ed0a0f6/agents.sqlite +0 -0
  5. package/.test-data/2f5ef9b7-01da-4ba0-a6fa-af8063a2567c/agents.sqlite +0 -0
  6. package/.test-data/3ac13cd5-84c9-4e71-8b89-6d3ef4dd819c/agents.sqlite +0 -0
  7. package/.test-data/40b7dd4a-fae0-4a5d-a6a0-64c9048af35e/agents.sqlite +0 -0
  8. package/.test-data/59511a04-42f8-4286-bb1e-733795e08749/agents.sqlite +0 -0
  9. package/.test-data/6778e8c5-6eb5-416d-8aca-9d559cdf83e4/agents.sqlite +0 -0
  10. package/.test-data/7648dc86-df90-4460-8f9c-55cdb481324b/agents.sqlite +0 -0
  11. package/.test-data/77162d98-6b22-41b1-a50f-536fab739f8a/agents.sqlite +0 -0
  12. package/.test-data/798dbdab-cbe7-4edd-8a5b-ae99c285fe17/agents.sqlite +0 -0
  13. package/.test-data/8033d6ac-8b85-454d-b708-00ac695b22f8/agents.sqlite +0 -0
  14. package/.test-data/9155a4f4-cda3-487c-9eed-921c82d7550f/agents.sqlite +0 -0
  15. package/.test-data/9bfeee53-c231-46c3-8c93-2180933f5d50/agents.sqlite +0 -0
  16. package/.test-data/a4c64287-79f6-46e9-847d-2803c63a74fd/agents.sqlite +0 -0
  17. package/.test-data/b8f58952-1ed8-46ff-abd7-21fb86e9457f/agents.sqlite +0 -0
  18. package/.test-data/c3060504-3187-41ed-8532-82332be48b0b/spending.sqlite +0 -0
  19. package/.test-data/cc471629-8006-4fc1-b8a1-399d2df2cc4e/agents.sqlite +0 -0
  20. package/.test-data/dbca3bef-397d-4bbc-bd4c-4f7b14103e04/spending.sqlite +0 -0
  21. package/.test-data/f1283dd1-6602-4de7-a050-16aac7abc288/agents.sqlite +0 -0
  22. package/.turbo/turbo-build.log +14 -0
  23. package/dist/index.d.ts +1675 -0
  24. package/dist/index.js +8006 -0
  25. package/dist/index.js.map +1 -0
  26. package/package.json +41 -0
  27. package/src/auth/device-flow.ts +108 -0
  28. package/src/auth/ed25519-provider.ts +43 -0
  29. package/src/auth/errors.ts +82 -0
  30. package/src/auth/evm-key.ts +55 -0
  31. package/src/auth/index.ts +8 -0
  32. package/src/auth/session-state.ts +25 -0
  33. package/src/auth/session-store.ts +510 -0
  34. package/src/auth/types.ts +81 -0
  35. package/src/auth/zklogin-provider.ts +902 -0
  36. package/src/blobstore/WALRUS_FINDINGS.md +284 -0
  37. package/src/blobstore/encrypted-store.ts +56 -0
  38. package/src/blobstore/fs-store.ts +91 -0
  39. package/src/blobstore/hybrid-store.ts +144 -0
  40. package/src/blobstore/index.ts +5 -0
  41. package/src/blobstore/interface.ts +33 -0
  42. package/src/blobstore/walrus-spike.ts +345 -0
  43. package/src/blobstore/walrus-store.ts +551 -0
  44. package/src/cache/agent-cache.ts +403 -0
  45. package/src/cache/index.ts +1 -0
  46. package/src/crypto/encryption.ts +152 -0
  47. package/src/crypto/index.ts +2 -0
  48. package/src/crypto/x25519.ts +41 -0
  49. package/src/dispute/client.ts +191 -0
  50. package/src/dispute/index.ts +1 -0
  51. package/src/events/index.ts +2 -0
  52. package/src/events/parser.ts +291 -0
  53. package/src/events/subscription.ts +131 -0
  54. package/src/evm/constants.ts +6 -0
  55. package/src/evm/index.ts +2 -0
  56. package/src/evm/wallet.ts +136 -0
  57. package/src/identity/did.ts +36 -0
  58. package/src/identity/index.ts +4 -0
  59. package/src/identity/keypair.ts +199 -0
  60. package/src/identity/signing.ts +28 -0
  61. package/src/index.ts +22 -0
  62. package/src/internal/parsing.ts +416 -0
  63. package/src/marketplace/client.ts +349 -0
  64. package/src/marketplace/index.ts +1 -0
  65. package/src/metering/hash-chain.ts +94 -0
  66. package/src/metering/index.ts +4 -0
  67. package/src/metering/meter.ts +80 -0
  68. package/src/metering/streaming.ts +196 -0
  69. package/src/metering/verification.ts +104 -0
  70. package/src/payment/index.ts +1 -0
  71. package/src/payment/rail-selector.ts +41 -0
  72. package/src/registry/client.ts +328 -0
  73. package/src/registry/index.ts +1 -0
  74. package/src/relay/consumer-client.ts +497 -0
  75. package/src/relay/index.ts +1 -0
  76. package/src/relay-registry/client.ts +295 -0
  77. package/src/relay-registry/discovery.ts +109 -0
  78. package/src/relay-registry/index.ts +2 -0
  79. package/src/reputation/anchor-client.ts +126 -0
  80. package/src/reputation/event-publisher.ts +67 -0
  81. package/src/reputation/index.ts +5 -0
  82. package/src/reputation/merkle.ts +79 -0
  83. package/src/reputation/score-calculator.ts +133 -0
  84. package/src/reputation/serialization.ts +37 -0
  85. package/src/reputation/store.ts +165 -0
  86. package/src/reputation/validation.ts +135 -0
  87. package/src/routing/circuit-breaker.ts +111 -0
  88. package/src/routing/fan-out.ts +266 -0
  89. package/src/routing/index.ts +4 -0
  90. package/src/routing/performance.ts +244 -0
  91. package/src/routing/selector.ts +225 -0
  92. package/src/spending/index.ts +1 -0
  93. package/src/spending/policy.ts +271 -0
  94. package/src/staking/client.ts +319 -0
  95. package/src/staking/index.ts +1 -0
  96. package/src/sui/client.ts +214 -0
  97. package/src/sui/index.ts +2 -0
  98. package/src/sui/tx-helpers.ts +1070 -0
  99. package/src/task/client.ts +215 -0
  100. package/src/task/index.ts +1 -0
  101. package/src/x402/client.ts +295 -0
  102. package/src/x402/index.ts +1 -0
  103. package/tests/auth/device-flow.test.ts +62 -0
  104. package/tests/auth/ed25519-provider.test.ts +24 -0
  105. package/tests/auth/evm-key.test.ts +31 -0
  106. package/tests/auth/session-store.test.ts +201 -0
  107. package/tests/auth/zklogin-provider.test.ts +366 -0
  108. package/tests/blobstore/encrypted-store.test.ts +78 -0
  109. package/tests/blobstore.test.ts +91 -0
  110. package/tests/cache.test.ts +124 -0
  111. package/tests/crypto/encryption.test.ts +70 -0
  112. package/tests/crypto/x25519.test.ts +47 -0
  113. package/tests/dispute/client.test.ts +238 -0
  114. package/tests/events.test.ts +202 -0
  115. package/tests/evm/wallet.test.ts +101 -0
  116. package/tests/hybrid-store.test.ts +121 -0
  117. package/tests/identity.test.ts +161 -0
  118. package/tests/marketplace.test.ts +308 -0
  119. package/tests/metering/hash-chain.test.ts +32 -0
  120. package/tests/metering/meter.test.ts +23 -0
  121. package/tests/metering/streaming.test.ts +52 -0
  122. package/tests/metering/verification.test.ts +27 -0
  123. package/tests/payment/rail-selector.test.ts +95 -0
  124. package/tests/registry.test.ts +183 -0
  125. package/tests/relay-consumer-client.test.ts +119 -0
  126. package/tests/relay-registry/client.test.ts +261 -0
  127. package/tests/reputation/event-publisher.test.ts +70 -0
  128. package/tests/reputation/merkle.test.ts +44 -0
  129. package/tests/reputation/score-calculator.test.ts +104 -0
  130. package/tests/reputation/store.test.ts +94 -0
  131. package/tests/routing/circuit-breaker.test.ts +45 -0
  132. package/tests/routing/fan-out.test.ts +123 -0
  133. package/tests/routing/performance.test.ts +49 -0
  134. package/tests/routing/selector.test.ts +114 -0
  135. package/tests/spending.test.ts +133 -0
  136. package/tests/staking/client.test.ts +286 -0
  137. package/tests/sui-client.test.ts +85 -0
  138. package/tests/task.test.ts +249 -0
  139. package/tests/tx-helpers.test.ts +70 -0
  140. package/tests/walrus-spike.test.ts +100 -0
  141. package/tests/walrus-store.test.ts +196 -0
  142. package/tests/x402/client.test.ts +116 -0
  143. package/tsconfig.json +9 -0
  144. package/tsup.config.ts +11 -0
  145. package/vitest.config.ts +8 -0
@@ -0,0 +1,1070 @@
1
+ import type { Capability } from '@hivemind-os/collective-types';
2
+ import { Transaction } from '@mysten/sui/transactions';
3
+
4
+ import { stringToBytes } from '../internal/parsing.js';
5
+
6
+ export const CLOCK_OBJECT_ID = '0x6';
7
+ const OBJECT_ID_PATTERN = /^0x([0-9a-f]+)$/i;
8
+ const MAX_OBJECT_ID_HEX_LENGTH = 64;
9
+ const MAX_U64 = (1n << 64n) - 1n;
10
+
11
+ export interface RegisterAgentParams {
12
+ packageId: string;
13
+ registryId: string;
14
+ name: string;
15
+ did: string;
16
+ description: string;
17
+ capabilities: Capability[];
18
+ endpoint: string;
19
+ }
20
+
21
+ export interface UpdateAgentParams {
22
+ packageId: string;
23
+ registryId: string;
24
+ cardId: string;
25
+ name: string;
26
+ description: string;
27
+ endpoint: string;
28
+ }
29
+
30
+ export interface SetEncryptionKeyParams {
31
+ packageId: string;
32
+ cardId: string;
33
+ encryptionPublicKey: Uint8Array;
34
+ }
35
+
36
+ export interface UpdateCapabilitiesParams {
37
+ packageId: string;
38
+ registryId: string;
39
+ cardId: string;
40
+ capabilities: Capability[];
41
+ }
42
+
43
+ export interface DeactivateAgentParams {
44
+ packageId: string;
45
+ registryId: string;
46
+ cardId: string;
47
+ }
48
+
49
+ export interface ReactivateAgentParams {
50
+ packageId: string;
51
+ registryId: string;
52
+ cardId: string;
53
+ }
54
+
55
+ export interface PostTaskParams {
56
+ packageId: string;
57
+ capability: string;
58
+ category: string;
59
+ inputBlobId: string;
60
+ agreementHash?: string;
61
+ priceMist: bigint;
62
+ disputeWindowMs: number;
63
+ expiryHours: number;
64
+ }
65
+
66
+ export interface PostMeteredTaskParams {
67
+ packageId: string;
68
+ capability: string;
69
+ category: string;
70
+ inputBlobId: string;
71
+ agreementHash?: string;
72
+ maxPriceMist: bigint;
73
+ unitPriceMist: bigint;
74
+ disputeWindowMs: number;
75
+ expiryHours: number;
76
+ }
77
+
78
+ export interface AcceptTaskParams {
79
+ packageId: string;
80
+ taskId: string;
81
+ }
82
+
83
+ export interface CompleteTaskParams {
84
+ packageId: string;
85
+ taskId: string;
86
+ resultBlobId: string;
87
+ providerCardId?: string;
88
+ }
89
+
90
+ export interface CompleteMeteredTaskParams {
91
+ packageId: string;
92
+ taskId: string;
93
+ resultBlobId: string;
94
+ meteredUnits: number;
95
+ verificationHash: string;
96
+ providerCardId?: string;
97
+ }
98
+
99
+ export interface ReleasePaymentParams {
100
+ packageId: string;
101
+ taskId: string;
102
+ }
103
+
104
+ export interface ReleaseMeteredPaymentParams {
105
+ packageId: string;
106
+ taskId: string;
107
+ }
108
+
109
+ export interface ClaimPaymentParams {
110
+ packageId: string;
111
+ taskId: string;
112
+ providerCardId?: string;
113
+ }
114
+
115
+ export interface CancelTaskParams {
116
+ packageId: string;
117
+ taskId: string;
118
+ }
119
+
120
+ export interface RefundExpiredTaskParams {
121
+ packageId: string;
122
+ taskId: string;
123
+ }
124
+
125
+ export interface PlaceBidParams {
126
+ packageId: string;
127
+ taskId: string;
128
+ bidPriceMist: bigint;
129
+ reputationScore: bigint;
130
+ evidenceBlob?: string;
131
+ }
132
+
133
+ export interface AcceptBidParams {
134
+ packageId: string;
135
+ taskId: string;
136
+ bidId: string;
137
+ otherBidIds?: string[];
138
+ }
139
+
140
+ export interface WithdrawBidParams {
141
+ packageId: string;
142
+ bidId: string;
143
+ }
144
+
145
+ export interface RejectBidParams {
146
+ packageId: string;
147
+ taskId: string;
148
+ bidId: string;
149
+ }
150
+
151
+ export interface OpenDisputeParams {
152
+ packageId: string;
153
+ taskId: string;
154
+ evidenceBlobId: string;
155
+ proposedSplitMist: bigint;
156
+ arbitratorAddress?: string;
157
+ }
158
+
159
+ export interface RespondToDisputeParams {
160
+ packageId: string;
161
+ disputeId: string;
162
+ evidenceBlobId: string;
163
+ proposedSplitMist: bigint;
164
+ }
165
+
166
+ export interface AcceptResolutionParams {
167
+ packageId: string;
168
+ disputeId: string;
169
+ taskId: string;
170
+ }
171
+
172
+ export interface ArbitrateDisputeParams {
173
+ packageId: string;
174
+ disputeId: string;
175
+ taskId: string;
176
+ rulingSplitMist: bigint;
177
+ }
178
+
179
+ export interface PublishReputationAnchorParams {
180
+ packageId: string;
181
+ merkleRoot: number[];
182
+ eventCount: number;
183
+ blobId: string;
184
+ fromTimestamp: number;
185
+ toTimestamp: number;
186
+ }
187
+
188
+ export interface DepositStakeParams {
189
+ packageId: string;
190
+ amountMist: bigint;
191
+ stakeType: 'agent' | 'relay';
192
+ }
193
+
194
+ export interface AddStakeParams {
195
+ packageId: string;
196
+ stakeId: string;
197
+ amountMist: bigint;
198
+ }
199
+
200
+ export interface StartDeactivationParams {
201
+ packageId: string;
202
+ stakeId: string;
203
+ }
204
+
205
+ export interface WithdrawStakeParams {
206
+ packageId: string;
207
+ stakeId: string;
208
+ }
209
+
210
+ export interface SlashStakeParams {
211
+ packageId: string;
212
+ stakeId: string;
213
+ taskId: string;
214
+ }
215
+
216
+ export interface RegisterRelayParams {
217
+ packageId: string;
218
+ endpoint: string;
219
+ stakeId: string;
220
+ capabilities: string[];
221
+ region: string;
222
+ routingFeeBps: number;
223
+ }
224
+
225
+ export interface RelayMutationParams {
226
+ packageId: string;
227
+ relayId: string;
228
+ }
229
+
230
+ export interface RecordRelayRoutingParams extends RelayMutationParams {
231
+ feeAmountMist: bigint;
232
+ }
233
+
234
+ export function buildRegisterAgentTx(params: RegisterAgentParams): Transaction {
235
+ validateRegisterAgentParams(params);
236
+
237
+ const tx = new Transaction();
238
+ const capabilityVectors = toCapabilityVectors(params.capabilities);
239
+
240
+ tx.moveCall({
241
+ target: `${params.packageId}::registry::register_agent`,
242
+ arguments: [
243
+ tx.object(params.registryId),
244
+ tx.pure.string(params.name),
245
+ tx.pure.string(params.did),
246
+ tx.pure.string(params.description),
247
+ tx.pure.vector('string', capabilityVectors.names),
248
+ tx.pure.vector('string', capabilityVectors.descriptions),
249
+ tx.pure.vector('string', capabilityVectors.versions),
250
+ tx.pure.vector('u64', capabilityVectors.prices),
251
+ tx.pure.vector('string', capabilityVectors.currencies),
252
+ tx.pure.string(params.endpoint),
253
+ tx.object(CLOCK_OBJECT_ID),
254
+ ],
255
+ });
256
+
257
+ return tx;
258
+ }
259
+
260
+ export function buildUpdateAgentTx(params: UpdateAgentParams): Transaction {
261
+ validateUpdateAgentParams(params);
262
+
263
+ const tx = new Transaction();
264
+ tx.moveCall({
265
+ target: `${params.packageId}::registry::update_agent`,
266
+ arguments: [
267
+ tx.object(params.registryId),
268
+ tx.object(params.cardId),
269
+ tx.pure.string(params.name),
270
+ tx.pure.string(params.description),
271
+ tx.pure.string(params.endpoint),
272
+ tx.object(CLOCK_OBJECT_ID),
273
+ ],
274
+ });
275
+
276
+ return tx;
277
+ }
278
+
279
+ export function buildUpdateCapabilitiesTx(params: UpdateCapabilitiesParams): Transaction {
280
+ validateUpdateCapabilitiesParams(params);
281
+
282
+ const tx = new Transaction();
283
+ const capabilityVectors = toCapabilityVectors(params.capabilities);
284
+
285
+ tx.moveCall({
286
+ target: `${params.packageId}::registry::update_capabilities`,
287
+ arguments: [
288
+ tx.object(params.registryId),
289
+ tx.object(params.cardId),
290
+ tx.pure.vector('string', capabilityVectors.names),
291
+ tx.pure.vector('string', capabilityVectors.descriptions),
292
+ tx.pure.vector('string', capabilityVectors.versions),
293
+ tx.pure.vector('u64', capabilityVectors.prices),
294
+ tx.pure.vector('string', capabilityVectors.currencies),
295
+ tx.object(CLOCK_OBJECT_ID),
296
+ ],
297
+ });
298
+
299
+ return tx;
300
+ }
301
+
302
+ export function buildSetEncryptionKeyTx(params: SetEncryptionKeyParams): Transaction {
303
+ validateSetEncryptionKeyParams(params);
304
+
305
+ const tx = new Transaction();
306
+ tx.moveCall({
307
+ target: `${params.packageId}::registry::set_encryption_key`,
308
+ arguments: [
309
+ tx.object(params.cardId),
310
+ tx.pure.vector('u8', [...params.encryptionPublicKey]),
311
+ ],
312
+ });
313
+
314
+ return tx;
315
+ }
316
+
317
+ export function buildDeactivateAgentTx(params: DeactivateAgentParams): Transaction {
318
+ validateAgentCardMutationParams(params);
319
+
320
+ const tx = new Transaction();
321
+ tx.moveCall({
322
+ target: `${params.packageId}::registry::deactivate_agent`,
323
+ arguments: [tx.object(params.registryId), tx.object(params.cardId)],
324
+ });
325
+
326
+ return tx;
327
+ }
328
+
329
+ export function buildReactivateAgentTx(params: ReactivateAgentParams): Transaction {
330
+ validateAgentCardMutationParams(params);
331
+
332
+ const tx = new Transaction();
333
+ tx.moveCall({
334
+ target: `${params.packageId}::registry::reactivate_agent`,
335
+ arguments: [tx.object(params.registryId), tx.object(params.cardId), tx.object(CLOCK_OBJECT_ID)],
336
+ });
337
+
338
+ return tx;
339
+ }
340
+
341
+ export function buildPostTaskTx(params: PostTaskParams): Transaction {
342
+ validatePostTaskParams(params);
343
+
344
+ const tx = new Transaction();
345
+ const [paymentCoin] = tx.splitCoins(tx.gas, [tx.pure.u64(params.priceMist)]);
346
+
347
+ tx.moveCall({
348
+ target: `${params.packageId}::task::post_open_task`,
349
+ arguments: [
350
+ tx.pure.string(params.capability),
351
+ tx.pure.string(params.category),
352
+ tx.pure.vector('u8', [...stringToBytes(params.inputBlobId)]),
353
+ tx.pure.vector('u8', [...stringToBytes(params.agreementHash ?? '')]),
354
+ paymentCoin,
355
+ tx.pure.u64(params.disputeWindowMs),
356
+ tx.pure.u64(params.expiryHours),
357
+ tx.object(CLOCK_OBJECT_ID),
358
+ ],
359
+ });
360
+
361
+ return tx;
362
+ }
363
+
364
+ export function buildPostMeteredTaskTx(params: PostMeteredTaskParams): Transaction {
365
+ validatePostMeteredTaskParams(params);
366
+
367
+ const tx = new Transaction();
368
+ const [paymentCoin] = tx.splitCoins(tx.gas, [tx.pure.u64(params.maxPriceMist)]);
369
+
370
+ tx.moveCall({
371
+ target: `${params.packageId}::task::post_metered_task`,
372
+ arguments: [
373
+ tx.pure.string(params.capability),
374
+ tx.pure.vector('u8', [...stringToBytes(params.inputBlobId)]),
375
+ tx.pure.vector('u8', [...stringToBytes(params.agreementHash ?? '')]),
376
+ paymentCoin,
377
+ tx.pure.u64(params.unitPriceMist),
378
+ tx.pure.u64(params.disputeWindowMs),
379
+ tx.pure.u64(params.expiryHours),
380
+ tx.pure.string(params.category),
381
+ tx.object(CLOCK_OBJECT_ID),
382
+ ],
383
+ });
384
+
385
+ return tx;
386
+ }
387
+
388
+ export function buildAcceptTaskTx(params: AcceptTaskParams): Transaction {
389
+ validateTaskMutationParams(params);
390
+
391
+ const tx = new Transaction();
392
+ tx.moveCall({
393
+ target: `${params.packageId}::task::accept_task`,
394
+ arguments: [tx.object(params.taskId), tx.object(CLOCK_OBJECT_ID)],
395
+ });
396
+
397
+ return tx;
398
+ }
399
+
400
+ export function buildCompleteTaskTx(params: CompleteTaskParams): Transaction {
401
+ validateTaskCompletionParams(params);
402
+
403
+ const tx = new Transaction();
404
+ tx.moveCall({
405
+ target: `${params.packageId}::task::${params.providerCardId ? 'complete_task_with_card' : 'complete_task'}`,
406
+ arguments: params.providerCardId
407
+ ? [
408
+ tx.object(params.taskId),
409
+ tx.object(params.providerCardId),
410
+ tx.pure.vector('u8', [...stringToBytes(params.resultBlobId)]),
411
+ tx.object(CLOCK_OBJECT_ID),
412
+ ]
413
+ : [
414
+ tx.object(params.taskId),
415
+ tx.pure.vector('u8', [...stringToBytes(params.resultBlobId)]),
416
+ tx.object(CLOCK_OBJECT_ID),
417
+ ],
418
+ });
419
+
420
+ return tx;
421
+ }
422
+
423
+ export function buildCompleteMeteredTaskTx(params: CompleteMeteredTaskParams): Transaction {
424
+ validateMeteredTaskCompletionParams(params);
425
+
426
+ const tx = new Transaction();
427
+ tx.moveCall({
428
+ target: `${params.packageId}::task::${params.providerCardId ? 'complete_metered_task_with_card' : 'complete_metered_task'}`,
429
+ arguments: params.providerCardId
430
+ ? [
431
+ tx.object(params.taskId),
432
+ tx.object(params.providerCardId),
433
+ tx.pure.u64(params.meteredUnits),
434
+ tx.pure.vector('u8', [...stringToBytes(params.resultBlobId)]),
435
+ tx.pure.vector('u8', [...hexToBytes(params.verificationHash)]),
436
+ tx.object(CLOCK_OBJECT_ID),
437
+ ]
438
+ : [
439
+ tx.object(params.taskId),
440
+ tx.pure.u64(params.meteredUnits),
441
+ tx.pure.vector('u8', [...stringToBytes(params.resultBlobId)]),
442
+ tx.pure.vector('u8', [...hexToBytes(params.verificationHash)]),
443
+ tx.object(CLOCK_OBJECT_ID),
444
+ ],
445
+ });
446
+
447
+ return tx;
448
+ }
449
+
450
+ export function buildReleasePaymentTx(params: ReleasePaymentParams): Transaction {
451
+ validateTaskMutationParams(params);
452
+
453
+ const tx = new Transaction();
454
+ tx.moveCall({
455
+ target: `${params.packageId}::task::release_payment`,
456
+ arguments: [tx.object(params.taskId)],
457
+ });
458
+
459
+ return tx;
460
+ }
461
+
462
+ export function buildReleaseMeteredPaymentTx(params: ReleaseMeteredPaymentParams): Transaction {
463
+ validateTaskMutationParams(params);
464
+
465
+ const tx = new Transaction();
466
+ tx.moveCall({
467
+ target: `${params.packageId}::task::release_metered_payment`,
468
+ arguments: [tx.object(params.taskId)],
469
+ });
470
+
471
+ return tx;
472
+ }
473
+
474
+ export function buildClaimPaymentTx(params: ClaimPaymentParams): Transaction {
475
+ validateClaimPaymentParams(params);
476
+
477
+ const tx = new Transaction();
478
+ tx.moveCall({
479
+ target: `${params.packageId}::task::${params.providerCardId ? 'claim_payment_with_card' : 'claim_payment'}`,
480
+ arguments: params.providerCardId
481
+ ? [tx.object(params.taskId), tx.object(params.providerCardId), tx.object(CLOCK_OBJECT_ID)]
482
+ : [tx.object(params.taskId), tx.object(CLOCK_OBJECT_ID)],
483
+ });
484
+
485
+ return tx;
486
+ }
487
+
488
+ export function buildCancelTaskTx(params: CancelTaskParams): Transaction {
489
+ validateTaskMutationParams(params);
490
+
491
+ const tx = new Transaction();
492
+ tx.moveCall({
493
+ target: `${params.packageId}::task::cancel_task`,
494
+ arguments: [tx.object(params.taskId)],
495
+ });
496
+
497
+ return tx;
498
+ }
499
+
500
+ export function buildRefundExpiredTaskTx(params: RefundExpiredTaskParams): Transaction {
501
+ validateTaskMutationParams(params);
502
+
503
+ const tx = new Transaction();
504
+ tx.moveCall({
505
+ target: `${params.packageId}::task::refund_expired_task`,
506
+ arguments: [tx.object(params.taskId), tx.object(CLOCK_OBJECT_ID)],
507
+ });
508
+
509
+ return tx;
510
+ }
511
+
512
+ export function buildPlaceBidTx(params: PlaceBidParams): Transaction {
513
+ validatePlaceBidParams(params);
514
+
515
+ const tx = new Transaction();
516
+ tx.moveCall({
517
+ target: `${params.packageId}::marketplace::place_bid`,
518
+ arguments: [
519
+ tx.object(params.taskId),
520
+ tx.pure.u64(params.reputationScore),
521
+ tx.pure.u64(params.bidPriceMist),
522
+ tx.pure.vector('u8', [...stringToBytes(params.evidenceBlob ?? '')]),
523
+ tx.object(CLOCK_OBJECT_ID),
524
+ ],
525
+ });
526
+
527
+ return tx;
528
+ }
529
+
530
+ export function buildAcceptBidTx(params: AcceptBidParams): Transaction {
531
+ validateAcceptBidParams(params);
532
+
533
+ const tx = new Transaction();
534
+ for (const bidId of params.otherBidIds ?? []) {
535
+ tx.moveCall({
536
+ target: `${params.packageId}::marketplace::reject_bid`,
537
+ arguments: [tx.object(bidId), tx.object(params.taskId)],
538
+ });
539
+ }
540
+
541
+ tx.moveCall({
542
+ target: `${params.packageId}::marketplace::accept_bid`,
543
+ arguments: [tx.object(params.taskId), tx.object(params.bidId), tx.object(CLOCK_OBJECT_ID)],
544
+ });
545
+
546
+ return tx;
547
+ }
548
+
549
+ export function buildWithdrawBidTx(params: WithdrawBidParams): Transaction {
550
+ validateWithdrawBidParams(params);
551
+
552
+ const tx = new Transaction();
553
+ tx.moveCall({
554
+ target: `${params.packageId}::marketplace::withdraw_bid`,
555
+ arguments: [tx.object(params.bidId)],
556
+ });
557
+
558
+ return tx;
559
+ }
560
+
561
+ export function buildRejectBidTx(params: RejectBidParams): Transaction {
562
+ validateRejectBidParams(params);
563
+
564
+ const tx = new Transaction();
565
+ tx.moveCall({
566
+ target: `${params.packageId}::marketplace::reject_bid`,
567
+ arguments: [tx.object(params.bidId), tx.object(params.taskId)],
568
+ });
569
+
570
+ return tx;
571
+ }
572
+
573
+ export function buildOpenDisputeTx(params: OpenDisputeParams): Transaction {
574
+ validateOpenDisputeParams(params);
575
+
576
+ const tx = new Transaction();
577
+ tx.moveCall({
578
+ target: `${params.packageId}::dispute::open_dispute`,
579
+ arguments: [
580
+ tx.object(params.taskId),
581
+ tx.pure.vector('u8', [...stringToBytes(params.evidenceBlobId)]),
582
+ tx.pure.u64(params.proposedSplitMist),
583
+ tx.pure.address(params.arbitratorAddress ?? '0x0'),
584
+ tx.object(CLOCK_OBJECT_ID),
585
+ ],
586
+ });
587
+
588
+ return tx;
589
+ }
590
+
591
+ export function buildRespondToDisputeTx(params: RespondToDisputeParams): Transaction {
592
+ validateRespondToDisputeParams(params);
593
+
594
+ const tx = new Transaction();
595
+ tx.moveCall({
596
+ target: `${params.packageId}::dispute::respond_to_dispute`,
597
+ arguments: [
598
+ tx.object(params.disputeId),
599
+ tx.pure.vector('u8', [...stringToBytes(params.evidenceBlobId)]),
600
+ tx.pure.u64(params.proposedSplitMist),
601
+ tx.object(CLOCK_OBJECT_ID),
602
+ ],
603
+ });
604
+
605
+ return tx;
606
+ }
607
+
608
+ export function buildAcceptResolutionTx(params: AcceptResolutionParams): Transaction {
609
+ validateAcceptResolutionParams(params);
610
+
611
+ const tx = new Transaction();
612
+ tx.moveCall({
613
+ target: `${params.packageId}::dispute::accept_resolution`,
614
+ arguments: [tx.object(params.disputeId), tx.object(params.taskId), tx.object(CLOCK_OBJECT_ID)],
615
+ });
616
+
617
+ return tx;
618
+ }
619
+
620
+ export function buildArbitrateDisputeTx(params: ArbitrateDisputeParams): Transaction {
621
+ validateArbitrateDisputeParams(params);
622
+
623
+ const tx = new Transaction();
624
+ tx.moveCall({
625
+ target: `${params.packageId}::dispute::arbitrate`,
626
+ arguments: [
627
+ tx.object(params.disputeId),
628
+ tx.object(params.taskId),
629
+ tx.pure.u64(params.rulingSplitMist),
630
+ tx.object(CLOCK_OBJECT_ID),
631
+ ],
632
+ });
633
+
634
+ return tx;
635
+ }
636
+
637
+ export function buildPublishReputationAnchorTx(params: PublishReputationAnchorParams): Transaction {
638
+ validatePublishReputationAnchorParams(params);
639
+
640
+ const tx = new Transaction();
641
+ tx.moveCall({
642
+ target: `${params.packageId}::reputation::publish_anchor`,
643
+ arguments: [
644
+ tx.pure.vector('u8', params.merkleRoot),
645
+ tx.pure.u64(params.eventCount),
646
+ tx.pure.vector('u8', [...stringToBytes(params.blobId)]),
647
+ tx.pure.u64(params.fromTimestamp),
648
+ tx.pure.u64(params.toTimestamp),
649
+ tx.object(CLOCK_OBJECT_ID),
650
+ ],
651
+ });
652
+
653
+ return tx;
654
+ }
655
+
656
+ export function buildDepositStakeTx(params: DepositStakeParams): Transaction {
657
+ validateDepositStakeParams(params);
658
+
659
+ const tx = new Transaction();
660
+ const [paymentCoin] = tx.splitCoins(tx.gas, [tx.pure.u64(params.amountMist)]);
661
+ tx.moveCall({
662
+ target: `${params.packageId}::staking::deposit_stake`,
663
+ arguments: [paymentCoin, tx.pure.u8(stakeTypeToMoveValue(params.stakeType)), tx.object(CLOCK_OBJECT_ID)],
664
+ });
665
+ return tx;
666
+ }
667
+
668
+ export function buildAddStakeTx(params: AddStakeParams): Transaction {
669
+ validateAddStakeParams(params);
670
+
671
+ const tx = new Transaction();
672
+ const [paymentCoin] = tx.splitCoins(tx.gas, [tx.pure.u64(params.amountMist)]);
673
+ tx.moveCall({
674
+ target: `${params.packageId}::staking::add_stake`,
675
+ arguments: [tx.object(params.stakeId), paymentCoin],
676
+ });
677
+ return tx;
678
+ }
679
+
680
+ export function buildStartDeactivationTx(params: StartDeactivationParams): Transaction {
681
+ validateStakeMutationParams(params);
682
+
683
+ const tx = new Transaction();
684
+ tx.moveCall({
685
+ target: `${params.packageId}::staking::start_deactivation`,
686
+ arguments: [tx.object(params.stakeId), tx.object(CLOCK_OBJECT_ID)],
687
+ });
688
+ return tx;
689
+ }
690
+
691
+ export function buildWithdrawStakeTx(params: WithdrawStakeParams): Transaction {
692
+ validateStakeMutationParams(params);
693
+
694
+ const tx = new Transaction();
695
+ tx.moveCall({
696
+ target: `${params.packageId}::staking::withdraw_stake`,
697
+ arguments: [tx.object(params.stakeId), tx.object(CLOCK_OBJECT_ID)],
698
+ });
699
+ return tx;
700
+ }
701
+
702
+ export function buildSlashExpiredEscrowTx(params: SlashStakeParams): Transaction {
703
+ validateSlashStakeParams(params);
704
+
705
+ const tx = new Transaction();
706
+ tx.moveCall({
707
+ target: `${params.packageId}::staking::slash_expired_escrow`,
708
+ arguments: [tx.object(params.stakeId), tx.object(params.taskId), tx.object(CLOCK_OBJECT_ID)],
709
+ });
710
+ return tx;
711
+ }
712
+
713
+ export function buildSlashNonDeliveryTx(params: SlashStakeParams): Transaction {
714
+ validateSlashStakeParams(params);
715
+
716
+ const tx = new Transaction();
717
+ tx.moveCall({
718
+ target: `${params.packageId}::staking::slash_non_delivery`,
719
+ arguments: [tx.object(params.stakeId), tx.object(params.taskId), tx.object(CLOCK_OBJECT_ID)],
720
+ });
721
+ return tx;
722
+ }
723
+
724
+ export function buildRegisterRelayTx(params: RegisterRelayParams): Transaction {
725
+ validateRegisterRelayParams(params);
726
+
727
+ const tx = new Transaction();
728
+ tx.moveCall({
729
+ target: `${params.packageId}::relay_registry::register_relay`,
730
+ arguments: [
731
+ tx.pure.string(params.endpoint),
732
+ tx.object(params.stakeId),
733
+ tx.pure.vector('string', params.capabilities),
734
+ tx.pure.string(params.region),
735
+ tx.pure.u64(params.routingFeeBps),
736
+ tx.object(CLOCK_OBJECT_ID),
737
+ ],
738
+ });
739
+ return tx;
740
+ }
741
+
742
+ export function buildHeartbeatRelayTx(params: RelayMutationParams): Transaction {
743
+ validateRelayMutationParams(params);
744
+
745
+ const tx = new Transaction();
746
+ tx.moveCall({
747
+ target: `${params.packageId}::relay_registry::heartbeat`,
748
+ arguments: [tx.object(params.relayId), tx.object(CLOCK_OBJECT_ID)],
749
+ });
750
+ return tx;
751
+ }
752
+
753
+ export function buildDeactivateRelayTx(params: RelayMutationParams): Transaction {
754
+ validateRelayMutationParams(params);
755
+
756
+ const tx = new Transaction();
757
+ tx.moveCall({
758
+ target: `${params.packageId}::relay_registry::deactivate_relay`,
759
+ arguments: [tx.object(params.relayId)],
760
+ });
761
+ return tx;
762
+ }
763
+
764
+ export function buildRecordRelayRoutingTx(params: RecordRelayRoutingParams): Transaction {
765
+ validateRecordRelayRoutingParams(params);
766
+
767
+ const tx = new Transaction();
768
+ tx.moveCall({
769
+ target: `${params.packageId}::relay_registry::record_routing`,
770
+ arguments: [tx.object(params.relayId), tx.pure.u64(params.feeAmountMist)],
771
+ });
772
+ return tx;
773
+ }
774
+
775
+ function validateRegisterAgentParams(params: RegisterAgentParams): void {
776
+ assertObjectId(params.packageId, 'packageId');
777
+ assertObjectId(params.registryId, 'registryId');
778
+ assertNonEmptyString(params.name, 'name');
779
+ assertNonEmptyString(params.description, 'description');
780
+ assertNonEmptyString(params.endpoint, 'endpoint');
781
+ assertDid(params.did, 'did');
782
+ assertCapabilities(params.capabilities);
783
+ }
784
+
785
+ function validateUpdateAgentParams(params: UpdateAgentParams): void {
786
+ assertObjectId(params.packageId, 'packageId');
787
+ assertObjectId(params.registryId, 'registryId');
788
+ assertObjectId(params.cardId, 'cardId');
789
+ assertNonEmptyString(params.name, 'name');
790
+ assertNonEmptyString(params.description, 'description');
791
+ assertNonEmptyString(params.endpoint, 'endpoint');
792
+ }
793
+
794
+ function validateUpdateCapabilitiesParams(params: UpdateCapabilitiesParams): void {
795
+ assertObjectId(params.packageId, 'packageId');
796
+ assertObjectId(params.registryId, 'registryId');
797
+ assertObjectId(params.cardId, 'cardId');
798
+ assertCapabilities(params.capabilities);
799
+ }
800
+
801
+ function validateSetEncryptionKeyParams(params: SetEncryptionKeyParams): void {
802
+ assertObjectId(params.packageId, 'packageId');
803
+ assertObjectId(params.cardId, 'cardId');
804
+ assertEncryptionPublicKey(params.encryptionPublicKey, 'encryptionPublicKey');
805
+ }
806
+
807
+ function validateAgentCardMutationParams(params: {
808
+ packageId: string;
809
+ registryId: string;
810
+ cardId: string;
811
+ }): void {
812
+ assertObjectId(params.packageId, 'packageId');
813
+ assertObjectId(params.registryId, 'registryId');
814
+ assertObjectId(params.cardId, 'cardId');
815
+ }
816
+
817
+ function validatePostTaskParams(params: PostTaskParams): void {
818
+ assertObjectId(params.packageId, 'packageId');
819
+ assertNonEmptyString(params.capability, 'capability');
820
+ assertNonEmptyString(params.category, 'category');
821
+ assertNonEmptyString(params.inputBlobId, 'inputBlobId');
822
+ assertOptionalString(params.agreementHash, 'agreementHash');
823
+ assertU64(params.priceMist, 'priceMist');
824
+ assertSafeNonNegativeInteger(params.disputeWindowMs, 'disputeWindowMs');
825
+ assertSafeNonNegativeInteger(params.expiryHours, 'expiryHours');
826
+ }
827
+
828
+ function validatePostMeteredTaskParams(params: PostMeteredTaskParams): void {
829
+ assertObjectId(params.packageId, 'packageId');
830
+ assertNonEmptyString(params.capability, 'capability');
831
+ assertNonEmptyString(params.category, 'category');
832
+ assertNonEmptyString(params.inputBlobId, 'inputBlobId');
833
+ assertOptionalString(params.agreementHash, 'agreementHash');
834
+ assertU64(params.maxPriceMist, 'maxPriceMist');
835
+ assertU64(params.unitPriceMist, 'unitPriceMist');
836
+ assertSafeNonNegativeInteger(params.disputeWindowMs, 'disputeWindowMs');
837
+ assertSafeNonNegativeInteger(params.expiryHours, 'expiryHours');
838
+ }
839
+
840
+ function validateTaskMutationParams(params: { packageId: string; taskId: string }): void {
841
+ assertObjectId(params.packageId, 'packageId');
842
+ assertObjectId(params.taskId, 'taskId');
843
+ }
844
+
845
+ function validatePlaceBidParams(params: PlaceBidParams): void {
846
+ validateTaskMutationParams(params);
847
+ assertU64(params.bidPriceMist, 'bidPriceMist');
848
+ assertU64(params.reputationScore, 'reputationScore');
849
+ assertOptionalString(params.evidenceBlob, 'evidenceBlob');
850
+ }
851
+
852
+ function validateAcceptBidParams(params: AcceptBidParams): void {
853
+ validateTaskMutationParams(params);
854
+ assertObjectId(params.bidId, 'bidId');
855
+ params.otherBidIds?.forEach((bidId, index) => assertObjectId(bidId, `otherBidIds[${index}]`));
856
+ }
857
+
858
+ function validateWithdrawBidParams(params: WithdrawBidParams): void {
859
+ assertObjectId(params.packageId, 'packageId');
860
+ assertObjectId(params.bidId, 'bidId');
861
+ }
862
+
863
+ function validateRejectBidParams(params: RejectBidParams): void {
864
+ validateTaskMutationParams(params);
865
+ assertObjectId(params.bidId, 'bidId');
866
+ }
867
+
868
+ function validateTaskCompletionParams(params: CompleteTaskParams): void {
869
+ validateTaskMutationParams(params);
870
+ assertOptionalObjectId(params.providerCardId, 'providerCardId');
871
+ assertNonEmptyString(params.resultBlobId, 'resultBlobId');
872
+ }
873
+
874
+ function validateMeteredTaskCompletionParams(params: CompleteMeteredTaskParams): void {
875
+ validateTaskMutationParams(params);
876
+ assertOptionalObjectId(params.providerCardId, 'providerCardId');
877
+ assertNonEmptyString(params.resultBlobId, 'resultBlobId');
878
+ assertSafeNonNegativeInteger(params.meteredUnits, 'meteredUnits');
879
+ assertHexString(params.verificationHash, 'verificationHash');
880
+ }
881
+
882
+ function validateClaimPaymentParams(params: ClaimPaymentParams): void {
883
+ validateTaskMutationParams(params);
884
+ assertOptionalObjectId(params.providerCardId, 'providerCardId');
885
+ }
886
+
887
+ function validateOpenDisputeParams(params: OpenDisputeParams): void {
888
+ validateTaskMutationParams(params);
889
+ assertNonEmptyString(params.evidenceBlobId, 'evidenceBlobId');
890
+ assertU64(params.proposedSplitMist, 'proposedSplitMist');
891
+ assertOptionalObjectId(params.arbitratorAddress, 'arbitratorAddress');
892
+ }
893
+
894
+ function validateRespondToDisputeParams(params: RespondToDisputeParams): void {
895
+ assertObjectId(params.packageId, 'packageId');
896
+ assertObjectId(params.disputeId, 'disputeId');
897
+ assertNonEmptyString(params.evidenceBlobId, 'evidenceBlobId');
898
+ assertU64(params.proposedSplitMist, 'proposedSplitMist');
899
+ }
900
+
901
+ function validateAcceptResolutionParams(params: AcceptResolutionParams): void {
902
+ assertObjectId(params.packageId, 'packageId');
903
+ assertObjectId(params.disputeId, 'disputeId');
904
+ assertObjectId(params.taskId, 'taskId');
905
+ }
906
+
907
+ function validateArbitrateDisputeParams(params: ArbitrateDisputeParams): void {
908
+ validateAcceptResolutionParams(params);
909
+ assertU64(params.rulingSplitMist, 'rulingSplitMist');
910
+ }
911
+
912
+ function validatePublishReputationAnchorParams(params: PublishReputationAnchorParams): void {
913
+ assertObjectId(params.packageId, 'packageId');
914
+ if (params.merkleRoot.length === 0) {
915
+ throw new Error('merkleRoot must not be empty.');
916
+ }
917
+ assertSafeNonNegativeInteger(params.eventCount, 'eventCount');
918
+ assertNonEmptyString(params.blobId, 'blobId');
919
+ assertSafeNonNegativeInteger(params.fromTimestamp, 'fromTimestamp');
920
+ assertSafeNonNegativeInteger(params.toTimestamp, 'toTimestamp');
921
+ }
922
+
923
+ function validateDepositStakeParams(params: DepositStakeParams): void {
924
+ assertObjectId(params.packageId, 'packageId');
925
+ assertU64(params.amountMist, 'amountMist');
926
+ assertStakeType(params.stakeType, 'stakeType');
927
+ }
928
+
929
+ function validateAddStakeParams(params: AddStakeParams): void {
930
+ validateStakeMutationParams(params);
931
+ assertU64(params.amountMist, 'amountMist');
932
+ }
933
+
934
+ function validateStakeMutationParams(params: { packageId: string; stakeId: string }): void {
935
+ assertObjectId(params.packageId, 'packageId');
936
+ assertObjectId(params.stakeId, 'stakeId');
937
+ }
938
+
939
+ function validateSlashStakeParams(params: SlashStakeParams): void {
940
+ validateStakeMutationParams(params);
941
+ assertObjectId(params.taskId, 'taskId');
942
+ }
943
+
944
+ function validateRegisterRelayParams(params: RegisterRelayParams): void {
945
+ assertObjectId(params.packageId, 'packageId');
946
+ assertObjectId(params.stakeId, 'stakeId');
947
+ assertNonEmptyString(params.endpoint, 'endpoint');
948
+ assertNonEmptyString(params.region, 'region');
949
+ params.capabilities.forEach((capability, index) => assertNonEmptyString(capability, `capabilities[${index}]`));
950
+ assertSafeNonNegativeInteger(params.routingFeeBps, 'routingFeeBps');
951
+ if (params.routingFeeBps > 10_000) {
952
+ throw new Error('routingFeeBps must be less than or equal to 10000.');
953
+ }
954
+ }
955
+
956
+ function validateRelayMutationParams(params: RelayMutationParams): void {
957
+ assertObjectId(params.packageId, 'packageId');
958
+ assertObjectId(params.relayId, 'relayId');
959
+ }
960
+
961
+ function validateRecordRelayRoutingParams(params: RecordRelayRoutingParams): void {
962
+ validateRelayMutationParams(params);
963
+ assertU64(params.feeAmountMist, 'feeAmountMist');
964
+ }
965
+
966
+ function toCapabilityVectors(capabilities: Capability[]): {
967
+ names: string[];
968
+ descriptions: string[];
969
+ versions: string[];
970
+ prices: bigint[];
971
+ currencies: string[];
972
+ } {
973
+ return {
974
+ names: capabilities.map((capability) => capability.name),
975
+ descriptions: capabilities.map((capability) => capability.description),
976
+ versions: capabilities.map((capability) => capability.version),
977
+ prices: capabilities.map((capability) => capability.pricing.amount),
978
+ currencies: capabilities.map((capability) => capability.pricing.currency),
979
+ };
980
+ }
981
+
982
+ function assertCapabilities(capabilities: Capability[]): void {
983
+ capabilities.forEach((capability, index) => {
984
+ assertNonEmptyString(capability.name, `capabilities[${index}].name`);
985
+ assertNonEmptyString(capability.description, `capabilities[${index}].description`);
986
+ assertNonEmptyString(capability.version, `capabilities[${index}].version`);
987
+ assertNonEmptyString(capability.pricing.currency, `capabilities[${index}].pricing.currency`);
988
+ assertU64(capability.pricing.amount, `capabilities[${index}].pricing.amount`);
989
+ });
990
+ }
991
+
992
+ function assertEncryptionPublicKey(value: Uint8Array, field: string): void {
993
+ if (value.length !== 0 && value.length !== 32) {
994
+ throw new Error(`${field} must be either empty or 32 bytes.`);
995
+ }
996
+ }
997
+
998
+ function assertObjectId(value: string, field: string): void {
999
+ const trimmed = value.trim();
1000
+ const match = OBJECT_ID_PATTERN.exec(trimmed);
1001
+ const hex = match?.[1];
1002
+
1003
+ if (hex === undefined || hex.length > MAX_OBJECT_ID_HEX_LENGTH || /^0+$/i.test(hex)) {
1004
+ throw new Error(`${field} must be a 0x-prefixed hex object id.`);
1005
+ }
1006
+ }
1007
+
1008
+ function assertOptionalObjectId(value: string | undefined, field: string): void {
1009
+ if (value !== undefined) {
1010
+ assertObjectId(value, field);
1011
+ }
1012
+ }
1013
+
1014
+ function assertNonEmptyString(value: string, field: string): void {
1015
+ if (value.trim().length === 0) {
1016
+ throw new Error(`${field} must be a non-empty string.`);
1017
+ }
1018
+ }
1019
+
1020
+ function assertOptionalString(value: string | undefined, field: string): void {
1021
+ if (value !== undefined) {
1022
+ assertNonEmptyString(value, field);
1023
+ }
1024
+ }
1025
+
1026
+ function assertHexString(value: string, field: string): void {
1027
+ if (!/^[a-f0-9]+$/i.test(value) || value.length % 2 !== 0) {
1028
+ throw new Error(`${field} must be an even-length hex string.`);
1029
+ }
1030
+ }
1031
+
1032
+ function hexToBytes(value: string): Uint8Array {
1033
+ return new Uint8Array(Buffer.from(value, 'hex'));
1034
+ }
1035
+
1036
+ function assertDid(value: string, field: string): void {
1037
+ if (!value.startsWith('did:mesh:') || value.trim().length <= 'did:mesh:'.length) {
1038
+ throw new Error(`${field} must be a did:mesh identifier.`);
1039
+ }
1040
+ }
1041
+
1042
+ function assertSafeNonNegativeInteger(value: number, field: string): void {
1043
+ if (!Number.isSafeInteger(value) || value < 0) {
1044
+ throw new Error(`${field} must be a non-negative safe integer.`);
1045
+ }
1046
+ }
1047
+
1048
+ function assertU64(value: bigint | number, field: string): void {
1049
+ if (typeof value === 'number') {
1050
+ if (!Number.isSafeInteger(value) || value < 0) {
1051
+ throw new Error(`${field} must be a non-negative safe integer.`);
1052
+ }
1053
+
1054
+ value = BigInt(value);
1055
+ }
1056
+
1057
+ if (value < 0n || value > MAX_U64) {
1058
+ throw new Error(`${field} must fit in an unsigned 64-bit integer.`);
1059
+ }
1060
+ }
1061
+
1062
+ function assertStakeType(value: string, field: string): void {
1063
+ if (value !== 'agent' && value !== 'relay') {
1064
+ throw new Error(`${field} must be either "agent" or "relay".`);
1065
+ }
1066
+ }
1067
+
1068
+ function stakeTypeToMoveValue(value: 'agent' | 'relay'): 0 | 1 {
1069
+ return value === 'relay' ? 1 : 0;
1070
+ }