@pushchain/core 6.0.27-alpha.3 → 6.0.27-alpha.5

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 (90) hide show
  1. package/AGW.md +35 -6
  2. package/CHANGELOG.md +13 -0
  3. package/MARKETPLACE.md +206 -0
  4. package/package.json +2 -1
  5. package/src/lib/agentic/codec/rules.js +74 -69
  6. package/src/lib/agentic/codec/universal.js +15 -3
  7. package/src/lib/agentic/constants.d.ts +36 -1
  8. package/src/lib/agentic/constants.js +14 -1
  9. package/src/lib/agentic/contracts/reader.d.ts +21 -0
  10. package/src/lib/agentic/contracts/reader.js +3 -0
  11. package/src/lib/agentic/error-messages.d.ts +3 -0
  12. package/src/lib/agentic/error-messages.js +127 -0
  13. package/src/lib/agentic/errors.d.ts +12 -3
  14. package/src/lib/agentic/errors.js +76 -0
  15. package/src/lib/agentic/management/common.js +6 -0
  16. package/src/lib/agentic/management/destination.d.ts +5 -0
  17. package/src/lib/agentic/management/destination.js +32 -0
  18. package/src/lib/agentic/management/prepare.js +80 -55
  19. package/src/lib/agentic/management/svm-public.js +13 -4
  20. package/src/lib/agentic/presets/index.js +8 -9
  21. package/src/lib/agentic/presets/routes.d.ts +1 -1
  22. package/src/lib/agentic/presets/routes.js +6 -7
  23. package/src/lib/agentic/presets/types.d.ts +1 -6
  24. package/src/lib/agentic/public-rule.js +18 -2
  25. package/src/lib/constants/index.d.ts +35 -0
  26. package/src/lib/index.d.ts +4 -0
  27. package/src/lib/index.js +6 -2
  28. package/src/lib/job/job.d.ts +35 -0
  29. package/src/lib/job/job.js +382 -0
  30. package/src/lib/job/types.d.ts +94 -0
  31. package/src/lib/job/types.js +3 -0
  32. package/src/lib/job/watch.d.ts +3 -0
  33. package/src/lib/job/watch.js +169 -0
  34. package/src/lib/job-spec/codec.d.ts +18 -0
  35. package/src/lib/job-spec/codec.js +348 -0
  36. package/src/lib/job-spec/constants.d.ts +32 -0
  37. package/src/lib/job-spec/constants.js +36 -0
  38. package/src/lib/job-spec/helpers.d.ts +19 -0
  39. package/src/lib/job-spec/helpers.js +138 -0
  40. package/src/lib/job-spec/index.d.ts +14 -0
  41. package/src/lib/job-spec/index.js +17 -0
  42. package/src/lib/job-spec/preview.d.ts +8 -0
  43. package/src/lib/job-spec/preview.js +298 -0
  44. package/src/lib/job-spec/read.d.ts +20 -0
  45. package/src/lib/job-spec/read.js +224 -0
  46. package/src/lib/job-spec/schema.d.ts +290 -0
  47. package/src/lib/job-spec/schema.js +70 -0
  48. package/src/lib/job-spec/types.d.ts +139 -0
  49. package/src/lib/job-spec/types.js +3 -0
  50. package/src/lib/market/contracts/AgenticCommerce.d.ts +1026 -0
  51. package/src/lib/market/contracts/AgenticCommerce.js +1317 -0
  52. package/src/lib/market/contracts/RulesBindingHook.d.ts +235 -0
  53. package/src/lib/market/contracts/RulesBindingHook.js +314 -0
  54. package/src/lib/market/contracts/UniversalMarketplace.d.ts +1770 -0
  55. package/src/lib/market/contracts/UniversalMarketplace.js +2295 -0
  56. package/src/lib/market/contracts/UniversalMarketplaceErrors.d.ts +309 -0
  57. package/src/lib/market/contracts/UniversalMarketplaceErrors.js +416 -0
  58. package/src/lib/market/contracts/UniversalMarketplaceRules.d.ts +241 -0
  59. package/src/lib/market/contracts/UniversalMarketplaceRules.js +323 -0
  60. package/src/lib/market/data.d.ts +8 -0
  61. package/src/lib/market/data.js +60 -0
  62. package/src/lib/market/deployment.d.ts +14 -0
  63. package/src/lib/market/deployment.js +23 -0
  64. package/src/lib/market/deposit.d.ts +24 -0
  65. package/src/lib/market/deposit.js +271 -0
  66. package/src/lib/market/errors.d.ts +13 -0
  67. package/src/lib/market/errors.js +81 -0
  68. package/src/lib/market/history.d.ts +6 -0
  69. package/src/lib/market/history.js +83 -0
  70. package/src/lib/market/index.d.ts +4 -0
  71. package/src/lib/market/index.js +12 -0
  72. package/src/lib/market/kernel-wire.d.ts +15 -0
  73. package/src/lib/market/kernel-wire.js +41 -0
  74. package/src/lib/market/market.d.ts +55 -0
  75. package/src/lib/market/market.js +635 -0
  76. package/src/lib/market/rules.d.ts +106 -0
  77. package/src/lib/market/rules.js +293 -0
  78. package/src/lib/market/runtime.d.ts +35 -0
  79. package/src/lib/market/runtime.js +130 -0
  80. package/src/lib/market/types.d.ts +180 -0
  81. package/src/lib/market/types.js +3 -0
  82. package/src/lib/orchestrator/internals/errors.d.ts +9 -2
  83. package/src/lib/orchestrator/internals/errors.js +9 -2
  84. package/src/lib/orchestrator/internals/push-chain-tx.js +17 -3
  85. package/src/lib/push-chain/push-chain.d.ts +44 -1
  86. package/src/lib/push-chain/push-chain.js +23 -3
  87. package/src/lib/read-state/read-params.d.ts +9 -0
  88. package/src/lib/read-state/read-params.js +5 -1
  89. package/src/lib/utils.d.ts +15 -0
  90. package/src/lib/utils.js +4 -0
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bindJobPreviewAccounts = bindJobPreviewAccounts;
4
+ exports.decodeJobAnswer = decodeJobAnswer;
5
+ exports.previewJobSpec = previewJobSpec;
6
+ const viem_1 = require("viem");
7
+ const read_state_types_1 = require("../read-state/read-state.types");
8
+ const envelopes_1 = require("../read-state/envelopes");
9
+ const errors_1 = require("../market/errors");
10
+ const codec_1 = require("./codec");
11
+ const helpers_1 = require("./helpers");
12
+ const read_1 = require("./read");
13
+ const constants_1 = require("./constants");
14
+ const resolvers = new WeakMap();
15
+ /** @internal Bind the real client's configured CEA resolver without exposing its runtime. */
16
+ function bindJobPreviewAccounts(universal, resolve) {
17
+ resolvers.set(universal, resolve);
18
+ }
19
+ /** Follow the deployed V2 type codes; uint values above int256.max cannot be compared. */
20
+ function decodeJobAnswer(read, data) {
21
+ const bytes = BigInt((data.length - 2) / 2);
22
+ const invalid = () => {
23
+ throw new errors_1.JobSpecError('INVALID_READ_RESULT', 'The consensus bytes do not contain the selected JobSpec field.');
24
+ };
25
+ const word = (at) => {
26
+ if (at < BigInt(0) || at + BigInt(32) > bytes)
27
+ return invalid();
28
+ return BigInt('0x' + data.slice(2 + Number(at) * 2, 66 + Number(at) * 2));
29
+ };
30
+ const dynamic = (n) => [6, 7, 9].includes(n.code) || n.children.some(dynamic);
31
+ const head = (n) => dynamic(n)
32
+ ? BigInt(1)
33
+ : n.code === 8
34
+ ? n.children.reduce((sum, c) => sum + head(c), BigInt(0))
35
+ : n.code === 10
36
+ ? BigInt(n.size ?? 0) * head(n.children[0])
37
+ : BigInt(1);
38
+ let node = (0, read_1.parseOutputs)(read.outputs);
39
+ let base = BigInt(0);
40
+ for (const index of read.field) {
41
+ let child;
42
+ let start = base;
43
+ let slot;
44
+ if (node.code === 8) {
45
+ child = node.children[index];
46
+ if (!child)
47
+ return invalid();
48
+ slot =
49
+ base +
50
+ BigInt(32) *
51
+ node.children
52
+ .slice(0, index)
53
+ .reduce((sum, c) => sum + head(c), BigInt(0));
54
+ }
55
+ else if (node.code === 9 || node.code === 10) {
56
+ if (BigInt(index) >= (node.code === 9 ? word(base) : BigInt(node.size ?? 0)))
57
+ return invalid();
58
+ child = node.children[0];
59
+ start += node.code === 9 ? BigInt(32) : BigInt(0);
60
+ slot = start + BigInt(32) * BigInt(index) * head(child);
61
+ }
62
+ else
63
+ return invalid();
64
+ base = dynamic(child) ? start + word(slot) : slot;
65
+ if (base > bytes)
66
+ return invalid();
67
+ node = child;
68
+ }
69
+ const value = word(base);
70
+ if (node.code === 6 || node.code === 7) {
71
+ if (base + BigInt(32) + value > bytes)
72
+ return invalid();
73
+ return BigInt.asIntN(256, BigInt((0, viem_1.keccak256)(('0x' +
74
+ data.slice(2 + Number(base + BigInt(32)) * 2, 2 + Number(base + BigInt(32) + value) * 2)))));
75
+ }
76
+ if (node.code === 9)
77
+ return BigInt.asIntN(256, value);
78
+ if ((node.code === 1 && value >= BigInt(1) << BigInt(255)) ||
79
+ (node.code === 3 && value > BigInt(1)) ||
80
+ (node.code === 4 && value >= BigInt(1) << BigInt(160)))
81
+ return invalid();
82
+ return BigInt.asIntN(256, value);
83
+ }
84
+ function compare(value, op, target) {
85
+ switch (op) {
86
+ case 'EQUAL':
87
+ return value === target;
88
+ case 'NOT_EQUAL':
89
+ return value !== target;
90
+ case 'GREATER_THAN':
91
+ return value > target;
92
+ case 'GREATER_OR_EQUAL':
93
+ return value >= target;
94
+ case 'LESS_THAN':
95
+ return value < target;
96
+ case 'LESS_OR_EQUAL':
97
+ return value <= target;
98
+ }
99
+ }
100
+ function combine(tree, checks) {
101
+ const results = tree.of.map((x) => typeof x === 'number' ? checks[x].pass : combine(x, checks));
102
+ const yes = results.filter((v) => v === true).length;
103
+ const unknown = results.filter((v) => v === null).length;
104
+ const required = tree.kind === 'ALL'
105
+ ? results.length
106
+ : tree.kind === 'ANY'
107
+ ? 1
108
+ : tree.k ?? 0;
109
+ return yes >= required ? true : yes + unknown < required ? false : null;
110
+ }
111
+ async function previewJobSpec(subject, options) {
112
+ // Validate and copy before asynchronous work; later caller mutations must not change paid criteria.
113
+ const input = (0, codec_1.decodeJobSpec)((0, codec_1.encodeJobSpec)(subject), {
114
+ format: 'params' in subject ? 'template' : 'spec',
115
+ });
116
+ options = {
117
+ ...options,
118
+ params: options.params && [...options.params],
119
+ baseline: options.baseline && [...options.baseline],
120
+ accounts: { ...options.accounts },
121
+ resume: options.resume && [...options.resume],
122
+ };
123
+ if (options.maxTotalFee !== undefined &&
124
+ (typeof options.maxTotalFee !== 'bigint' || options.maxTotalFee < BigInt(0)))
125
+ throw new errors_1.JobSpecError('INVALID_AMOUNT', 'maxTotalFee must be a nonnegative bigint.');
126
+ if (options.baseline) {
127
+ if (options.baseline.length !== input.reads.length)
128
+ throw new errors_1.JobSpecError('INVALID_BASELINE', 'Provide one baseline entry per read; use null for unknown entries.');
129
+ options.baseline.forEach((value) => {
130
+ if (value !== null)
131
+ (0, codec_1.int256)(value);
132
+ });
133
+ }
134
+ let spec;
135
+ if ('params' in input) {
136
+ if (input.checks.some((c) => c.target === constants_1.PRINCIPAL ||
137
+ (typeof c.target === 'object' && 'principalBps' in c.target)) &&
138
+ options.principal === undefined)
139
+ throw new errors_1.JobSpecError('UNFILLED_PLACEHOLDER', 'Supply principal to resolve principal-based preview targets.');
140
+ const accounts = { ...options.accounts };
141
+ const resolve = resolvers.get(options.client.universal);
142
+ for (const [index, read] of input.reads.entries()) {
143
+ const chain = `${read.chainNamespace}:${read.chainId}`;
144
+ const needed = read.fills?.some((f) => f.source === 'WALLET') ||
145
+ input.checks.some((c) => c.read === index && c.target === 'agentic:wallet');
146
+ if (needed && !accounts[chain] && options.wallet && resolve)
147
+ accounts[chain] = await resolve((0, viem_1.getAddress)(options.wallet), chain);
148
+ }
149
+ spec = (0, helpers_1.resolveJobSpec)(input, {
150
+ principal: options.principal ?? BigInt(0),
151
+ params: options.params ?? [],
152
+ accounts,
153
+ origin: viem_1.zeroHash,
154
+ executeBy: 0,
155
+ settleWindow: 1,
156
+ });
157
+ }
158
+ else
159
+ spec = input;
160
+ const waitOptions = {
161
+ timeoutMs: options.advanced?.timeout,
162
+ pollingIntervalMs: options.advanced?.pollingIntervalMs,
163
+ resultShape: { kind: 'raw' },
164
+ };
165
+ let responses;
166
+ let quoted = BigInt(0);
167
+ let newlyPaid = BigInt(0);
168
+ if (options.resume) {
169
+ if (options.resume.length !== spec.reads.length ||
170
+ options.resume.some((id) => !/^0x[\da-f]{64}$/i.test(id)) ||
171
+ new Set(options.resume.map((x) => x.toLowerCase())).size !==
172
+ options.resume.length)
173
+ throw new errors_1.JobSpecError('INVALID_PREVIEW_RESUME', 'Provide one distinct request ID per read, in read order.');
174
+ responses = [];
175
+ for (const [i, id] of options.resume.entries()) {
176
+ const response = await options.client.universal.trackRead({ requestId: id }, { resultShape: { kind: 'raw' }, progressHook: options.progressHook });
177
+ const read = spec.reads[i];
178
+ let matched = false;
179
+ try {
180
+ const actual = response.request.spec;
181
+ const envelope = (0, envelopes_1.decodeEvmQueryEnvelope)(actual.query);
182
+ const [target, calldata] = (0, viem_1.decodeAbiParameters)([{ type: 'address' }, { type: 'bytes' }], envelope.payload);
183
+ matched =
184
+ response.requestId.toLowerCase() === id.toLowerCase() &&
185
+ actual.account.chainNamespace === read.chainNamespace &&
186
+ actual.account.chainId === read.chainId &&
187
+ actual.minConfirmations >= read.minConfirmations &&
188
+ envelope.queryType === 1 &&
189
+ envelope.refType === 0 &&
190
+ envelope.blockNumber === actual.blockNumber &&
191
+ (0, viem_1.getAddress)(target) === (0, viem_1.getAddress)(read.target) &&
192
+ calldata.toLowerCase() ===
193
+ (read.selector + read.args.slice(2)).toLowerCase();
194
+ }
195
+ catch {
196
+ /* A request from another schema/query cannot stand in for this logical read. */
197
+ }
198
+ if (!matched)
199
+ throw new errors_1.JobSpecError('PREVIEW_REQUEST_MISMATCH', 'The recorded request does not match this resolved JobSpec read.', { read: i, requestId: id });
200
+ responses.push(response);
201
+ }
202
+ quoted = responses.reduce((sum, response) => sum + response.fees.paid, BigInt(0));
203
+ }
204
+ else {
205
+ const prepared = [];
206
+ for (const read of spec.reads) {
207
+ const readOptions = {
208
+ chain: `${read.chainNamespace}:${read.chainId}`,
209
+ callData: (read.selector + read.args.slice(2)),
210
+ minConfirmations: read.minConfirmations,
211
+ expiryBlocks: options.expiryBlocks,
212
+ refundTo: options.refundTo,
213
+ callback: options.callback,
214
+ };
215
+ prepared.push(await options.client.universal.prepareRead(read.target, readOptions));
216
+ }
217
+ quoted = prepared.reduce((sum, read) => sum + read.value, BigInt(0));
218
+ if (options.maxTotalFee !== undefined && quoted > options.maxTotalFee)
219
+ throw new errors_1.JobSpecError('PREVIEW_FEE_EXCEEDED', 'The prepared read fees exceed maxTotalFee. No read was submitted.', { quoted, maxTotalFee: options.maxTotalFee });
220
+ let batch;
221
+ try {
222
+ batch = await options.client.universal.executeReads(prepared, {
223
+ progressHook: options.progressHook,
224
+ advanced: options.advanced,
225
+ waitForCompletion: false,
226
+ });
227
+ }
228
+ catch (cause) {
229
+ const error = cause;
230
+ throw new errors_1.JobSpecError('PREVIEW_INCOMPLETE', 'Read submission could not be confirmed. Track the recorded transactions before requesting more reads.', {
231
+ txHash: error?.txHash,
232
+ transactionHashes: error?.transactionHashes,
233
+ pendingTransactionHash: error?.pendingTransactionHash,
234
+ }, cause);
235
+ }
236
+ responses = batch.reads;
237
+ newlyPaid = quoted;
238
+ }
239
+ const requestIds = responses.map((r) => r.requestId);
240
+ try {
241
+ responses = await Promise.all(responses.map((r) => r.wait(waitOptions)));
242
+ }
243
+ catch (cause) {
244
+ throw new errors_1.JobSpecError('PREVIEW_INCOMPLETE', 'The paid reads are still recoverable. Resume with these request IDs instead of paying again.', { requestIds, txHashes: responses.map((r) => r.txHash) }, cause);
245
+ }
246
+ const reads = responses.map((response, i) => {
247
+ const value = response.raw?.resultData ?? null;
248
+ if (response.outcome !== read_state_types_1.READ_OUTCOME.SUCCESS || value === null)
249
+ return {
250
+ value,
251
+ decoded: null,
252
+ error: response.errorMsg || 'The paid read did not complete successfully.',
253
+ response,
254
+ };
255
+ try {
256
+ return {
257
+ value,
258
+ decoded: decodeJobAnswer(spec.reads[i], value),
259
+ response,
260
+ };
261
+ }
262
+ catch (e) {
263
+ return { value, decoded: null, error: e.message, response };
264
+ }
265
+ });
266
+ const checks = spec.checks.map((check) => {
267
+ let value = reads[check.read].decoded;
268
+ if (value === null)
269
+ return { pass: null, value, reason: 'READ_UNAVAILABLE' };
270
+ if (check.evaluation === 'NUMBER' || check.evaluation === 'PERCENTAGE') {
271
+ const before = options.baseline?.[check.read];
272
+ if (before === undefined || before === null)
273
+ return { pass: null, value: null, reason: 'BASELINE_REQUIRED' };
274
+ if (check.evaluation === 'PERCENTAGE' && before === BigInt(0))
275
+ return { pass: null, value: null, reason: 'ZERO_BASELINE' };
276
+ try {
277
+ value = (0, codec_1.int256)(value - before);
278
+ if (check.evaluation === 'PERCENTAGE')
279
+ value = (0, codec_1.int256)(value * BigInt(10000)) / before;
280
+ }
281
+ catch {
282
+ return { pass: null, value: null, reason: 'ARITHMETIC_OVERFLOW' };
283
+ }
284
+ }
285
+ return { pass: compare(value, check.operation, check.target), value };
286
+ });
287
+ return {
288
+ reads,
289
+ checks,
290
+ pass: combine(spec.logic, checks),
291
+ fees: {
292
+ quoted,
293
+ paid: reads.reduce((sum, r) => sum + r.response.fees.paid, BigInt(0)),
294
+ newlyPaid,
295
+ },
296
+ };
297
+ }
298
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1,20 @@
1
+ import { type AbiParameter, type Hex } from 'viem';
2
+ import type { PrepareJobReadOptions, PreparedJobRead, ExecuteJobReadOptions } from './types';
3
+ import type { ReadOptions } from '../read-state/read-params';
4
+ export declare function inheritReadLabel(source: PreparedJobRead, target: PreparedJobRead): void;
5
+ export declare function jobReadLabel(read: PreparedJobRead): string | undefined;
6
+ /** Same logical call as a JobSpec read, through the normal paid universal-read path. */
7
+ export declare function jobReadOptions(read: PreparedJobRead, options?: ExecuteJobReadOptions): ReadOptions;
8
+ export declare function outputTypes(params: readonly AbiParameter[]): Hex;
9
+ /** Pure ABI preparation, independent of read fees, RPCs and the request preflight. */
10
+ export declare function prepareJobRead(options: PrepareJobReadOptions): PreparedJobRead;
11
+ export interface OutputNode {
12
+ code: number;
13
+ children: OutputNode[];
14
+ size?: number;
15
+ }
16
+ export declare function parseOutputs(outputs: Hex): OutputNode;
17
+ export declare function validateJobRead(r: PreparedJobRead & {
18
+ field?: number[];
19
+ minConfirmations?: number;
20
+ }): void;
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.inheritReadLabel = inheritReadLabel;
4
+ exports.jobReadLabel = jobReadLabel;
5
+ exports.jobReadOptions = jobReadOptions;
6
+ exports.outputTypes = outputTypes;
7
+ exports.prepareJobRead = prepareJobRead;
8
+ exports.parseOutputs = parseOutputs;
9
+ exports.validateJobRead = validateJobRead;
10
+ const viem_1 = require("viem");
11
+ const abi_layout_1 = require("../agentic/codec/abi-layout");
12
+ const errors_1 = require("../market/errors");
13
+ const labels = new WeakMap();
14
+ function inheritReadLabel(source, target) {
15
+ const value = labels.get(source);
16
+ if (value &&
17
+ value.selector === source.selector &&
18
+ value.outputs === source.outputs &&
19
+ value.target === source.target.toLowerCase())
20
+ labels.set(target, value);
21
+ }
22
+ function jobReadLabel(read) {
23
+ const value = labels.get(read);
24
+ return value &&
25
+ value.selector === read.selector &&
26
+ value.outputs === read.outputs &&
27
+ value.target === read.target.toLowerCase()
28
+ ? value.name
29
+ : undefined;
30
+ }
31
+ /** Same logical call as a JobSpec read, through the normal paid universal-read path. */
32
+ function jobReadOptions(read, options = {}) {
33
+ validateJobRead(read);
34
+ if (read.fills?.length)
35
+ throw new errors_1.JobSpecError('UNFILLED_PLACEHOLDER', 'Resolve WALLET/PARAM holes before sending a prepared read.');
36
+ return {
37
+ ...options,
38
+ chain: `${read.chainNamespace}:${read.chainId}`,
39
+ callData: (read.selector + read.args.slice(2)),
40
+ };
41
+ }
42
+ function outputTypes(params) {
43
+ function type(p, depth) {
44
+ if (depth > 16)
45
+ throw new errors_1.JobSpecError('INVALID_READ', 'Output type nesting exceeds 16.');
46
+ const a = /^(.*)\[(\d*)\]$/.exec(p.type);
47
+ if (a) {
48
+ const base = { ...p, type: a[1] };
49
+ if (!a[2])
50
+ return [9, ...type(base, depth + 1)];
51
+ const n = Number(a[2]);
52
+ if (n < 1 || n > 255)
53
+ throw new errors_1.JobSpecError('INVALID_READ', 'Fixed output arrays must contain 1..255 elements.');
54
+ return [10, n, ...type(base, depth + 1)];
55
+ }
56
+ if (p.type === 'tuple')
57
+ return tuple(p.components, depth + 1);
58
+ if (/^uint(\d+)?$/.test(p.type))
59
+ return [1];
60
+ if (/^int(\d+)?$/.test(p.type))
61
+ return [2];
62
+ if (p.type === 'bool')
63
+ return [3];
64
+ if (p.type === 'address')
65
+ return [4];
66
+ if (/^bytes([1-9]|[12]\d|3[0-2])$/.test(p.type))
67
+ return [5];
68
+ if (p.type === 'bytes')
69
+ return [6];
70
+ if (p.type === 'string')
71
+ return [7];
72
+ throw new errors_1.JobSpecError('INVALID_READ', `Unsupported ABI output ${p.type}.`);
73
+ }
74
+ function tuple(items, depth) {
75
+ if (items.length < 1 || items.length > 255)
76
+ throw new errors_1.JobSpecError('INVALID_READ', 'An output tuple needs 1..255 fields.');
77
+ return [8, items.length, ...items.flatMap((p) => type(p, depth))];
78
+ }
79
+ return ('0x' +
80
+ tuple(params, 0)
81
+ .map((x) => x.toString(16).padStart(2, '0'))
82
+ .join(''));
83
+ }
84
+ /** Pure ABI preparation, independent of read fees, RPCs and the request preflight. */
85
+ function prepareJobRead(options) {
86
+ try {
87
+ if (!/^eip155:[1-9]\d*$/.test(options.chain))
88
+ throw new errors_1.JobSpecError('CHAIN_UNSUPPORTED', 'JobSpec reads currently support EVM chain identifiers only.');
89
+ const candidates = options.abi.filter((x) => x.type === 'function' &&
90
+ x.name === options.functionName &&
91
+ x.inputs.length === (options.args?.length ?? 0));
92
+ if (candidates.length !== 1)
93
+ throw new errors_1.JobSpecError('INVALID_READ', 'Select one exact function ABI for this read, including overloaded functions.');
94
+ const fn = candidates[0];
95
+ if (!['view', 'pure'].includes(fn.stateMutability))
96
+ throw new errors_1.JobSpecError('INVALID_READ', 'A JobSpec read must use a view or pure function.');
97
+ const fills = [];
98
+ const lower = (p, value, indices, depth) => {
99
+ if (depth > 16)
100
+ throw new errors_1.JobSpecError('INVALID_READ', 'Read arguments are nested too deeply.');
101
+ const marker = value === 'agentic:wallet';
102
+ const param = value && typeof value === 'object' && 'param' in value
103
+ ? value.param
104
+ : undefined;
105
+ if (marker || param !== undefined) {
106
+ if (marker && p.type !== 'address')
107
+ throw new errors_1.JobSpecError('INVALID_READ', 'WALLET read arguments must be addresses.');
108
+ if (!marker && !/^u?int(\d+)?$/.test(p.type))
109
+ throw new errors_1.JobSpecError('INVALID_READ', 'PARAM read arguments must be static integers.');
110
+ if (!marker &&
111
+ (!Number.isInteger(param) || Number(param) < 0 || Number(param) > 255))
112
+ throw new errors_1.JobSpecError('INVALID_READ', 'Invalid template parameter index.');
113
+ const word = ((0, abi_layout_1.argumentLocation)(fn.inputs, indices, 'Read placeholder').offset -
114
+ 4) /
115
+ 32;
116
+ if (word > 255)
117
+ throw new errors_1.JobSpecError('INVALID_READ', 'Read placeholder is outside the uint8 word range.');
118
+ fills.push({
119
+ word,
120
+ source: marker ? 'WALLET' : 'PARAM',
121
+ ...(!marker ? { param: Number(param) } : {}),
122
+ });
123
+ return marker ? viem_1.zeroAddress : BigInt(0);
124
+ }
125
+ const a = /^(.*)\[(\d*)\]$/.exec(p.type);
126
+ if (a) {
127
+ if (!Array.isArray(value))
128
+ throw new errors_1.JobSpecError('INVALID_READ', 'Array argument must be an array.');
129
+ return value.map((v, i) => lower({ ...p, type: a[1] }, v, [...indices, i], depth + 1));
130
+ }
131
+ if (p.type === 'tuple') {
132
+ const fields = p
133
+ .components;
134
+ return fields.map((field, i) => lower(field, Array.isArray(value)
135
+ ? value[i]
136
+ : value?.[field.name ?? ''], [...indices, i], depth + 1));
137
+ }
138
+ return value;
139
+ };
140
+ const values = fn.inputs.map((p, i) => lower(p, options.args?.[i], [i], 0));
141
+ const [chainNamespace, chainId] = options.chain.split(':');
142
+ const prepared = {
143
+ chainNamespace,
144
+ chainId,
145
+ target: (0, viem_1.getAddress)(options.target),
146
+ selector: (0, viem_1.toFunctionSelector)(fn),
147
+ args: (0, viem_1.encodeAbiParameters)(fn.inputs, values),
148
+ outputs: outputTypes(fn.outputs),
149
+ ...(fills.length ? { fills } : {}),
150
+ };
151
+ labels.set(prepared, {
152
+ selector: prepared.selector,
153
+ outputs: prepared.outputs,
154
+ target: prepared.target.toLowerCase(),
155
+ name: fn.name,
156
+ parameters: fn.outputs,
157
+ });
158
+ return prepared;
159
+ }
160
+ catch (cause) {
161
+ if (cause instanceof errors_1.JobSpecError)
162
+ throw cause;
163
+ throw new errors_1.JobSpecError('INVALID_READ', 'The read arguments or ABI are invalid.', undefined, cause);
164
+ }
165
+ }
166
+ function parseOutputs(outputs) {
167
+ if (!(0, viem_1.isHex)(outputs) || outputs.length % 2 !== 0 || outputs.length > 8194)
168
+ throw new errors_1.JobSpecError('INVALID_READ', 'Invalid output type layout.');
169
+ const bytes = outputs
170
+ .slice(2)
171
+ .match(/../g)
172
+ ?.map((x) => parseInt(x, 16)) ?? [];
173
+ let pos = 0;
174
+ function read(depth) {
175
+ if (depth > 16 || pos >= bytes.length)
176
+ throw new errors_1.JobSpecError('INVALID_READ', 'Invalid output type layout.');
177
+ const code = bytes[pos++];
178
+ const n = { code, children: [] };
179
+ if (code === 8 || code === 10) {
180
+ n.size = bytes[pos++];
181
+ if (!n.size)
182
+ throw new errors_1.JobSpecError('INVALID_READ', 'An output tuple/array cannot be empty.');
183
+ if (code === 8)
184
+ for (let i = 0; i < n.size; i++)
185
+ n.children.push(read(depth + 1));
186
+ else
187
+ n.children.push(read(depth + 1));
188
+ }
189
+ else if (code === 9)
190
+ n.children.push(read(depth + 1));
191
+ else if (code < 1 || code > 7)
192
+ throw new errors_1.JobSpecError('INVALID_READ', 'Unknown output type code.');
193
+ return n;
194
+ }
195
+ const root = read(0);
196
+ if (root.code !== 8 || pos !== bytes.length)
197
+ throw new errors_1.JobSpecError('INVALID_READ', 'Outputs must encode exactly one root tuple.');
198
+ return root;
199
+ }
200
+ function validateJobRead(r) {
201
+ if (r.chainNamespace !== 'eip155' ||
202
+ !/^[1-9]\d*$/.test(r.chainId) ||
203
+ !(0, viem_1.isAddress)(r.target) ||
204
+ !/^0x[\da-f]{8}$/i.test(r.selector) ||
205
+ !(0, viem_1.isHex)(r.args) ||
206
+ r.args.length % 2)
207
+ throw new errors_1.JobSpecError('INVALID_READ', 'Invalid EVM JobSpec read.');
208
+ let node = parseOutputs(r.outputs);
209
+ const field = r.field ?? [0];
210
+ if (field.length < 1 || field.length > 16)
211
+ throw new errors_1.JobSpecError('INVALID_READ', 'Output field path must have 1..16 indexes.');
212
+ for (const i of field) {
213
+ if (!Number.isInteger(i) ||
214
+ i < 0 ||
215
+ i > 255 ||
216
+ ![8, 9, 10].includes(node.code) ||
217
+ (node.code !== 9 && i >= (node.size ?? 0)))
218
+ throw new errors_1.JobSpecError('INVALID_READ', 'Output field path does not resolve.');
219
+ node = node.children[node.code === 8 ? i : 0];
220
+ }
221
+ if ([8, 10].includes(node.code))
222
+ throw new errors_1.JobSpecError('INVALID_READ', 'Choose a scalar or dynamic-length output field.');
223
+ }
224
+ //# sourceMappingURL=read.js.map