agentex-creator-sdk 1.0.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 (97) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/LICENSE +21 -0
  3. package/README.md +195 -0
  4. package/dist/packages/contracts/src/deployer-investigation.d.ts +1015 -0
  5. package/dist/packages/contracts/src/deployer-investigation.js +101 -0
  6. package/dist/packages/contracts/src/index.d.ts +1701 -0
  7. package/dist/packages/contracts/src/index.js +380 -0
  8. package/dist/packages/contracts/src/indexed-activity.d.ts +684 -0
  9. package/dist/packages/contracts/src/indexed-activity.js +71 -0
  10. package/dist/packages/contracts/src/indexed-agents.d.ts +299 -0
  11. package/dist/packages/contracts/src/indexed-agents.js +131 -0
  12. package/dist/packages/contracts/src/inspection.d.ts +906 -0
  13. package/dist/packages/contracts/src/inspection.js +114 -0
  14. package/dist/packages/contracts/src/kinds.d.ts +5398 -0
  15. package/dist/packages/contracts/src/kinds.js +156 -0
  16. package/dist/packages/contracts/src/report-presentation.d.ts +346 -0
  17. package/dist/packages/contracts/src/report-presentation.js +120 -0
  18. package/dist/packages/contracts/src/solana-inspection.d.ts +451 -0
  19. package/dist/packages/contracts/src/solana-inspection.js +94 -0
  20. package/dist/packages/contracts/src/token-market.d.ts +193 -0
  21. package/dist/packages/contracts/src/token-market.js +335 -0
  22. package/dist/packages/contracts/src/wallet-analysis.d.ts +866 -0
  23. package/dist/packages/contracts/src/wallet-analysis.js +89 -0
  24. package/dist/packages/contracts/src/watchtower.d.ts +1141 -0
  25. package/dist/packages/contracts/src/watchtower.js +196 -0
  26. package/dist/packages/contracts/src/workflow.d.ts +1568 -0
  27. package/dist/packages/contracts/src/workflow.js +651 -0
  28. package/dist/packages/inspector/src/decode.d.ts +23 -0
  29. package/dist/packages/inspector/src/decode.js +150 -0
  30. package/dist/packages/inspector/src/scope.d.ts +87 -0
  31. package/dist/packages/inspector/src/scope.js +64 -0
  32. package/dist/packages/model/src/analysis.d.ts +149 -0
  33. package/dist/packages/model/src/analysis.js +387 -0
  34. package/dist/packages/model/src/pricing.d.ts +38 -0
  35. package/dist/packages/model/src/pricing.js +49 -0
  36. package/dist/packages/model/src/retry.d.ts +20 -0
  37. package/dist/packages/model/src/retry.js +31 -0
  38. package/dist/packages/model/src/schema.d.ts +10 -0
  39. package/dist/packages/model/src/schema.js +51 -0
  40. package/dist/packages/model/src/summary.d.ts +91 -0
  41. package/dist/packages/model/src/summary.js +177 -0
  42. package/dist/packages/model/src/types.d.ts +81 -0
  43. package/dist/packages/model/src/types.js +19 -0
  44. package/dist/packages/monitoring/src/delivery.d.ts +32 -0
  45. package/dist/packages/monitoring/src/delivery.js +53 -0
  46. package/dist/packages/providers/src/chain-transport.d.ts +42 -0
  47. package/dist/packages/providers/src/chain-transport.js +57 -0
  48. package/dist/packages/providers/src/coverage.d.ts +105 -0
  49. package/dist/packages/providers/src/coverage.js +260 -0
  50. package/dist/packages/providers/src/health.d.ts +273 -0
  51. package/dist/packages/providers/src/health.js +505 -0
  52. package/dist/packages/providers/src/keyed.d.ts +96 -0
  53. package/dist/packages/providers/src/keyed.js +240 -0
  54. package/dist/packages/providers/src/snapshot.d.ts +61 -0
  55. package/dist/packages/providers/src/snapshot.js +77 -0
  56. package/dist/packages/publication/src/fixtures.d.ts +45 -0
  57. package/dist/packages/publication/src/fixtures.js +350 -0
  58. package/dist/packages/research/src/index.d.ts +188 -0
  59. package/dist/packages/research/src/index.js +829 -0
  60. package/dist/packages/runtime/src/checkpoints.d.ts +65 -0
  61. package/dist/packages/runtime/src/checkpoints.js +214 -0
  62. package/dist/packages/runtime/src/policy.d.ts +57 -0
  63. package/dist/packages/runtime/src/policy.js +296 -0
  64. package/dist/packages/sdk/src/bin/agentex-buyer.d.ts +2 -0
  65. package/dist/packages/sdk/src/bin/agentex-buyer.js +4 -0
  66. package/dist/packages/sdk/src/bin/agentex.d.ts +2 -0
  67. package/dist/packages/sdk/src/bin/agentex.js +3 -0
  68. package/dist/packages/sdk/src/buyer-cli.d.ts +10 -0
  69. package/dist/packages/sdk/src/buyer-cli.js +210 -0
  70. package/dist/packages/sdk/src/buyer.d.ts +534 -0
  71. package/dist/packages/sdk/src/buyer.js +441 -0
  72. package/dist/packages/sdk/src/cli.d.ts +14 -0
  73. package/dist/packages/sdk/src/cli.js +149 -0
  74. package/dist/packages/sdk/src/errors.d.ts +31 -0
  75. package/dist/packages/sdk/src/errors.js +24 -0
  76. package/dist/packages/sdk/src/index.d.ts +236 -0
  77. package/dist/packages/sdk/src/index.js +150 -0
  78. package/dist/packages/sdk/src/local.d.ts +11 -0
  79. package/dist/packages/sdk/src/local.js +110 -0
  80. package/dist/packages/sdk/src/rails.d.ts +59 -0
  81. package/dist/packages/sdk/src/rails.js +96 -0
  82. package/dist/packages/sdk/src/report.d.ts +121 -0
  83. package/dist/packages/sdk/src/report.js +114 -0
  84. package/dist/packages/sdk/src/version.d.ts +2 -0
  85. package/dist/packages/sdk/src/version.js +2 -0
  86. package/dist/packages/watchtower/src/index.d.ts +150 -0
  87. package/dist/packages/watchtower/src/index.js +786 -0
  88. package/dist/packages/workflow/src/registry.d.ts +61 -0
  89. package/dist/packages/workflow/src/registry.js +76 -0
  90. package/examples/README.md +34 -0
  91. package/examples/cli-usage.sh +30 -0
  92. package/examples/fixtures/base-weth-input.json +4 -0
  93. package/examples/focused-researcher.json +127 -0
  94. package/examples/pay-with-eth-robinhood.mts +37 -0
  95. package/examples/pay-with-usdc.mts +41 -0
  96. package/examples/quickstart.mts +73 -0
  97. package/package.json +50 -0
@@ -0,0 +1,23 @@
1
+ import { type Address } from 'viem';
2
+ import type { DecodedAction, TransactionInspectionInput, TransactionInspectionReport } from '../../contracts/src/inspection.js';
3
+ /** Pure, offline calldata decoding. Unknown selectors stay unknown; nothing is looked up in public signature databases. */
4
+ export declare const MAX_UINT256: bigint;
5
+ export declare const MAX_MULTICALL_DEPTH = 2;
6
+ export declare const MAX_DECODED_ACTIONS = 32;
7
+ export declare const MAX_GRANTEES = 3;
8
+ export interface DecodedGrant {
9
+ role: 'spender' | 'operator';
10
+ grantee: Address;
11
+ owner: Address;
12
+ approved: boolean;
13
+ actionPaths: string[];
14
+ }
15
+ export interface DecodedTransaction {
16
+ transaction: TransactionInspectionReport['transaction'];
17
+ actions: DecodedAction[];
18
+ grants: DecodedGrant[];
19
+ omittedGrants: number;
20
+ tokenFamily: 'fungible' | 'non-fungible' | null;
21
+ actionLimitReached: boolean;
22
+ }
23
+ export declare function decodeTransaction(input: TransactionInspectionInput): DecodedTransaction;
@@ -0,0 +1,150 @@
1
+ import { decodeFunctionData, encodeFunctionData, formatUnits, getAddress, keccak256, parseAbiItem, toFunctionSelector } from 'viem';
2
+ /** Pure, offline calldata decoding. Unknown selectors stay unknown; nothing is looked up in public signature databases. */
3
+ export const MAX_UINT256 = 2n ** 256n - 1n;
4
+ export const MAX_MULTICALL_DEPTH = 2;
5
+ export const MAX_DECODED_ACTIONS = 32;
6
+ export const MAX_GRANTEES = 3;
7
+ const INLINE_BYTES = 256;
8
+ const GENERIC_NOTE = 'Decoded from the selector and canonical ABI encoding; the target is not verified to implement this standard.';
9
+ const DECODERS = [
10
+ ['erc20.transfer', 'function transfer(address to, uint256 amount)'],
11
+ ['erc20.approve', 'function approve(address spender, uint256 amount)'],
12
+ ['erc20-or-erc721.transferFrom', 'function transferFrom(address from, address to, uint256 amountOrTokenId)'],
13
+ ['erc20.increaseAllowance', 'function increaseAllowance(address spender, uint256 addedValue)'],
14
+ ['erc20.decreaseAllowance', 'function decreaseAllowance(address spender, uint256 subtractedValue)'],
15
+ ['eip2612.permit', 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)'],
16
+ ['erc721-or-erc1155.setApprovalForAll', 'function setApprovalForAll(address operator, bool approved)'],
17
+ ['erc721.safeTransferFrom', 'function safeTransferFrom(address from, address to, uint256 tokenId)'],
18
+ ['erc721.safeTransferFrom', 'function safeTransferFrom(address from, address to, uint256 tokenId, bytes data)'],
19
+ ['erc1155.safeTransferFrom', 'function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data)'],
20
+ ['weth.deposit', 'function deposit()'],
21
+ ['weth.withdraw', 'function withdraw(uint256 amount)'],
22
+ ['multicall', 'function multicall(bytes[] data)'],
23
+ ];
24
+ const NOTES = {
25
+ 'erc20.approve': 'ERC-721 approve(address,uint256) shares this selector; for an ERC-721 target the amount is a token id.',
26
+ 'erc20-or-erc721.transferFrom': 'ERC-20 and ERC-721 transferFrom share this selector; the third value is an amount or a token id depending on the target.',
27
+ 'eip2612.permit': 'Submits an off-chain signed allowance for the stated owner. The signature is not verified here; v, r and s remain only in the input calldata.',
28
+ 'erc721-or-erc1155.setApprovalForAll': 'Grants or revokes an operator over every token of this contract held by the owner (ERC-721 and ERC-1155 share this selector).',
29
+ 'weth.deposit': 'Interpreted as WETH-style wrapping by selector only; other contracts use deposit() differently.',
30
+ 'weth.withdraw': 'Interpreted as WETH-style unwrapping by selector only; vaults and other contracts use withdraw(uint256) differently.',
31
+ multicall: 'Inner calls are decoded as calls to the same target (self-multicall); an implementation can route them differently.',
32
+ };
33
+ const TABLE = new Map(DECODERS.map(([kind, signature]) => { const abi = parseAbiItem(signature); return [toFunctionSelector(abi), { kind, abi, signature: `${abi.name}(${abi.inputs.map((input) => input.type).join(',')})` }]; }));
34
+ const FUNGIBLE = new Set(['erc20.transfer', 'erc20.approve', 'erc20-or-erc721.transferFrom', 'erc20.increaseAllowance', 'erc20.decreaseAllowance', 'eip2612.permit', 'weth.deposit', 'weth.withdraw']);
35
+ const NON_FUNGIBLE = new Set(['erc721-or-erc1155.setApprovalForAll', 'erc721.safeTransferFrom', 'erc1155.safeTransferFrom']);
36
+ const bytesOf = (data) => (data.length - 2) / 2;
37
+ function formatArgument(type, value) {
38
+ if (type === 'address')
39
+ return getAddress(value);
40
+ if (type === 'bool')
41
+ return value === true;
42
+ if (/^u?int\d*$/.test(type))
43
+ return value.toString();
44
+ const hex = value.toLowerCase();
45
+ if (type === 'bytes' && bytesOf(hex) > INLINE_BYTES)
46
+ return `${bytesOf(hex)} bytes, keccak256 ${keccak256(hex)}`;
47
+ return hex;
48
+ }
49
+ function decodeCall(data, target, path, depth, state) {
50
+ if (state.actions.length >= MAX_DECODED_ACTIONS) {
51
+ state.limit = true;
52
+ return;
53
+ }
54
+ const base = { path, depth, target };
55
+ if (bytesOf(data) < 4) {
56
+ state.actions.push({ ...base, status: 'invalid', kind: 'unknown', selector: null, signature: null, arguments: { dataBytes: String(bytesOf(data)) }, notes: ['Calldata is shorter than a four-byte function selector.'] });
57
+ return;
58
+ }
59
+ const selector = data.slice(0, 10);
60
+ const decoder = TABLE.get(selector);
61
+ const unknown = (status, note) => state.actions.push({ ...base, status, kind: 'unknown', selector, signature: null, arguments: { dataBytes: String(bytesOf(data)) }, notes: [note] });
62
+ if (!decoder) {
63
+ unknown('unknown', 'No supported decoder exists for this selector. Its effect is not guessed.');
64
+ return;
65
+ }
66
+ let args;
67
+ try {
68
+ args = decodeFunctionData({ abi: [decoder.abi], data }).args ?? [];
69
+ }
70
+ catch {
71
+ unknown('invalid', `The selector matches ${decoder.signature}, but the arguments are not a valid ABI encoding.`);
72
+ return;
73
+ }
74
+ const canonical = encodeFunctionData({ abi: [decoder.abi], functionName: decoder.abi.name, args }).toLowerCase();
75
+ const notes = [GENERIC_NOTE, ...(NOTES[decoder.kind] ? [NOTES[decoder.kind]] : [])];
76
+ if (canonical !== data) {
77
+ if (!data.startsWith(canonical)) {
78
+ unknown('invalid', `The selector matches ${decoder.signature}, but the encoding is not canonical; arguments are not reported.`);
79
+ return;
80
+ }
81
+ notes.push(`${bytesOf(data) - bytesOf(canonical)} trailing bytes follow the canonical ABI encoding and are not interpreted.`);
82
+ }
83
+ const record = {};
84
+ decoder.abi.inputs.forEach((input, index) => {
85
+ if (decoder.kind === 'eip2612.permit' && ['v', 'r', 's'].includes(input.name ?? ''))
86
+ return;
87
+ if (decoder.kind === 'multicall') {
88
+ record.calls = String(args[index].length);
89
+ return;
90
+ }
91
+ record[input.name] = formatArgument(input.type, args[index]);
92
+ });
93
+ const action = { ...base, status: 'decoded', kind: decoder.kind, selector, signature: decoder.signature, arguments: record, notes };
94
+ state.actions.push(action);
95
+ if (decoder.kind !== 'multicall')
96
+ return;
97
+ const calls = args[0];
98
+ if (depth >= MAX_MULTICALL_DEPTH) {
99
+ action.status = 'bound-reached';
100
+ action.notes.push(`The nested multicall depth limit (${MAX_MULTICALL_DEPTH}) was reached; ${calls.length} inner calls are not decoded.`);
101
+ return;
102
+ }
103
+ for (const [index, call] of calls.entries()) {
104
+ decodeCall(call.toLowerCase(), target, `${path}.${index}`, depth + 1, state);
105
+ if (state.limit) {
106
+ action.notes.push(`Decoding stopped at the ${MAX_DECODED_ACTIONS}-action limit; later inner calls are not decoded.`);
107
+ return;
108
+ }
109
+ }
110
+ }
111
+ export function decodeTransaction(input) {
112
+ const data = input.data.toLowerCase();
113
+ const kind = input.to === null ? 'contract-creation' : data === '0x' ? 'native-transfer' : 'call';
114
+ const transaction = { kind, selector: kind === 'call' && bytesOf(data) >= 4 ? data.slice(0, 10) : null, dataBytes: bytesOf(data), dataHash: keccak256(data),
115
+ valueAtomic: input.value, valueFormatted: formatUnits(BigInt(input.value), 18), valueUnit: 'native-18-decimals' };
116
+ const state = { actions: [], limit: false };
117
+ if (input.to === null)
118
+ state.actions.push({ path: '0', depth: 0, target: null, status: 'decoded', kind: 'contract-creation', selector: null, signature: null,
119
+ arguments: { initCodeBytes: String(bytesOf(data)), initCodeHash: keccak256(data) }, notes: ['Init code is not decoded. Constructor effects and the deployed runtime code are only partially observable through simulation.'] });
120
+ else if (data === '0x')
121
+ state.actions.push({ path: '0', depth: 0, target: getAddress(input.to), status: 'decoded', kind: 'native-transfer', selector: null, signature: null,
122
+ arguments: { valueAtomic: input.value }, notes: ['Empty calldata. If the target has code, its receive or fallback logic runs and is not decoded.'] });
123
+ else
124
+ decodeCall(data, getAddress(input.to), '0', 0, state);
125
+ const grants = new Map();
126
+ let omittedGrants = 0;
127
+ for (const action of state.actions) {
128
+ if (action.status !== 'decoded')
129
+ continue;
130
+ const args = action.arguments;
131
+ const grant = ['erc20.approve', 'erc20.increaseAllowance', 'erc20.decreaseAllowance'].includes(action.kind) ? { role: 'spender', grantee: getAddress(String(args.spender)), owner: getAddress(input.from), approved: true }
132
+ : action.kind === 'eip2612.permit' ? { role: 'spender', grantee: getAddress(String(args.spender)), owner: getAddress(String(args.owner)), approved: true }
133
+ : action.kind === 'erc721-or-erc1155.setApprovalForAll' ? { role: 'operator', grantee: getAddress(String(args.operator)), owner: getAddress(input.from), approved: args.approved === true } : null;
134
+ if (!grant)
135
+ continue;
136
+ const key = `${grant.role}:${grant.owner.toLowerCase()}:${grant.grantee.toLowerCase()}`;
137
+ const existing = grants.get(key);
138
+ if (existing) {
139
+ existing.actionPaths.push(action.path);
140
+ existing.approved ||= grant.approved;
141
+ }
142
+ else if (grants.size < MAX_GRANTEES)
143
+ grants.set(key, { ...grant, actionPaths: [action.path] });
144
+ else
145
+ omittedGrants++;
146
+ }
147
+ const decodedKinds = state.actions.filter((action) => action.status === 'decoded').map((action) => action.kind);
148
+ return { transaction, actions: state.actions, grants: [...grants.values()], omittedGrants, actionLimitReached: state.limit,
149
+ tokenFamily: decodedKinds.some((item) => FUNGIBLE.has(item)) ? 'fungible' : decodedKinds.some((item) => NON_FUNGIBLE.has(item)) ? 'non-fungible' : null };
150
+ }
@@ -0,0 +1,87 @@
1
+ import type { InspectionEvidenceItem, TransactionInspectionInput } from '../../contracts/src/inspection.js';
2
+ import { type DecodedGrant } from './decode.js';
3
+ /**
4
+ * Every state read the inspector may perform is derived from the accepted input alone. The executor builds its
5
+ * requests here, and the runtime validates saved receipts against the same set, so a receipt cannot widen scope.
6
+ */
7
+ export declare const READ_ABI: readonly [{
8
+ readonly name: "name";
9
+ readonly type: "function";
10
+ readonly stateMutability: "view";
11
+ readonly inputs: readonly [];
12
+ readonly outputs: readonly [{
13
+ readonly type: "string";
14
+ }];
15
+ }, {
16
+ readonly name: "symbol";
17
+ readonly type: "function";
18
+ readonly stateMutability: "view";
19
+ readonly inputs: readonly [];
20
+ readonly outputs: readonly [{
21
+ readonly type: "string";
22
+ }];
23
+ }, {
24
+ readonly name: "decimals";
25
+ readonly type: "function";
26
+ readonly stateMutability: "view";
27
+ readonly inputs: readonly [];
28
+ readonly outputs: readonly [{
29
+ readonly type: "uint8";
30
+ }];
31
+ }, {
32
+ readonly name: "allowance";
33
+ readonly type: "function";
34
+ readonly stateMutability: "view";
35
+ readonly inputs: readonly [{
36
+ readonly type: "address";
37
+ readonly name: "owner";
38
+ }, {
39
+ readonly type: "address";
40
+ readonly name: "spender";
41
+ }];
42
+ readonly outputs: readonly [{
43
+ readonly type: "uint256";
44
+ }];
45
+ }, {
46
+ readonly name: "isApprovedForAll";
47
+ readonly type: "function";
48
+ readonly stateMutability: "view";
49
+ readonly inputs: readonly [{
50
+ readonly type: "address";
51
+ readonly name: "owner";
52
+ }, {
53
+ readonly type: "address";
54
+ readonly name: "operator";
55
+ }];
56
+ readonly outputs: readonly [{
57
+ readonly type: "bool";
58
+ }];
59
+ }];
60
+ export declare const INSPECTION_STATE_METHODS: readonly string[];
61
+ export interface RpcRequest {
62
+ method: string;
63
+ params: unknown[];
64
+ }
65
+ export declare const blockTagOf: (blockNumber: string) => string;
66
+ /** The sender-context call object. No gas price, nonce or signature is ever supplied. */
67
+ export declare const transactionCall: (input: TransactionInspectionInput) => {
68
+ data: string;
69
+ value: string;
70
+ to?: `0x${string}` | undefined;
71
+ from: `0x${string}`;
72
+ };
73
+ export declare const inspectionRequests: {
74
+ code: (address: string, tag: string) => RpcRequest;
75
+ slot: (address: string, slot: string, tag: string) => RpcRequest;
76
+ metadata: (address: string, name: "name" | "symbol" | "decimals", tag: string) => RpcRequest;
77
+ grant: (token: string, grant: DecodedGrant, tag: string) => RpcRequest;
78
+ simulate: (input: TransactionInspectionInput, tag: string) => RpcRequest;
79
+ estimate: (input: TransactionInspectionInput, tag: string) => RpcRequest;
80
+ };
81
+ export declare const requestKey: (request: {
82
+ method: string;
83
+ params: readonly unknown[];
84
+ }) => string;
85
+ export declare function plannedStateRequestKeys(input: TransactionInspectionInput, tag: string): Set<string>;
86
+ /** Method, snapshot and request-scope rules for an inspector receipt. Schema, chain identity and hash checks stay with the caller. */
87
+ export declare function inspectionReceiptInScope(receipt: InspectionEvidenceItem, input: TransactionInspectionInput): boolean;
@@ -0,0 +1,64 @@
1
+ import { encodeFunctionData, parseAbi } from 'viem';
2
+ import { contentHash } from '../../contracts/src/index.js';
3
+ import { EIP1967_SLOTS } from '../../research/src/index.js';
4
+ import { decodeTransaction } from './decode.js';
5
+ /**
6
+ * Every state read the inspector may perform is derived from the accepted input alone. The executor builds its
7
+ * requests here, and the runtime validates saved receipts against the same set, so a receipt cannot widen scope.
8
+ */
9
+ export const READ_ABI = parseAbi(['function name() view returns (string)', 'function symbol() view returns (string)', 'function decimals() view returns (uint8)',
10
+ 'function allowance(address owner, address spender) view returns (uint256)', 'function isApprovedForAll(address owner, address operator) view returns (bool)']);
11
+ const READ_GAS = '0x7a120';
12
+ export const INSPECTION_STATE_METHODS = ['eth_getCode', 'eth_getStorageAt', 'eth_call', 'eth_estimateGas'];
13
+ export const blockTagOf = (blockNumber) => `0x${BigInt(blockNumber).toString(16)}`;
14
+ /** The sender-context call object. No gas price, nonce or signature is ever supplied. */
15
+ export const transactionCall = (input) => ({ from: input.from, ...(input.to === null ? {} : { to: input.to }), data: input.data, value: `0x${BigInt(input.value).toString(16)}` });
16
+ export const inspectionRequests = {
17
+ code: (address, tag) => ({ method: 'eth_getCode', params: [address, tag] }),
18
+ slot: (address, slot, tag) => ({ method: 'eth_getStorageAt', params: [address, slot, tag] }),
19
+ metadata: (address, name, tag) => ({ method: 'eth_call', params: [{ to: address, data: encodeFunctionData({ abi: READ_ABI, functionName: name }), gas: READ_GAS }, tag] }),
20
+ grant: (token, grant, tag) => ({ method: 'eth_call', params: [{ to: token, gas: READ_GAS, data: grant.role === 'spender'
21
+ ? encodeFunctionData({ abi: READ_ABI, functionName: 'allowance', args: [grant.owner, grant.grantee] })
22
+ : encodeFunctionData({ abi: READ_ABI, functionName: 'isApprovedForAll', args: [grant.owner, grant.grantee] }) }, tag] }),
23
+ simulate: (input, tag) => ({ method: 'eth_call', params: [transactionCall(input), tag] }),
24
+ estimate: (input, tag) => ({ method: 'eth_estimateGas', params: [transactionCall(input), tag] }),
25
+ };
26
+ export const requestKey = (request) => contentHash({ method: request.method, params: request.params });
27
+ export function plannedStateRequestKeys(input, tag) {
28
+ const keys = new Set();
29
+ const add = (request) => keys.add(requestKey(JSON.parse(JSON.stringify(request))));
30
+ const requests = inspectionRequests;
31
+ if (input.to !== null) {
32
+ add(requests.code(input.to, tag));
33
+ for (const slot of Object.values(EIP1967_SLOTS))
34
+ add(requests.slot(input.to, slot, tag));
35
+ for (const name of ['name', 'symbol', 'decimals'])
36
+ add(requests.metadata(input.to, name, tag));
37
+ for (const grant of decodeTransaction(input).grants) {
38
+ add(requests.code(grant.grantee, tag));
39
+ add(requests.grant(input.to, grant, tag));
40
+ }
41
+ }
42
+ add(requests.simulate(input, tag));
43
+ add(requests.estimate(input, tag));
44
+ return keys;
45
+ }
46
+ /** Method, snapshot and request-scope rules for an inspector receipt. Schema, chain identity and hash checks stay with the caller. */
47
+ export function inspectionReceiptInScope(receipt, input) {
48
+ const method = receipt.source.method;
49
+ const params = receipt.request;
50
+ if (method === 'eth_chainId')
51
+ return params.length === 0 && receipt.snapshot === null;
52
+ if (method === 'eth_getBlockByNumber') {
53
+ // `latest` is the instant-read head; `finalized` only admits receipts checkpointed before that rule.
54
+ if (params.length !== 2 || params[1] !== false || typeof params[0] !== 'string' || (params[0] !== 'latest' && params[0] !== 'finalized' && !/^0x(?:0|[1-9a-fA-F][a-fA-F0-9]*)$/.test(params[0])))
55
+ return false;
56
+ return !receipt.snapshot || params[0] === blockTagOf(receipt.snapshot.blockNumber);
57
+ }
58
+ if (!INSPECTION_STATE_METHODS.includes(method) || !receipt.snapshot || (receipt.finality !== 'sequencer-confirmed' && receipt.finality !== 'finalized'))
59
+ return false;
60
+ if (input.snapshotBlock !== undefined && receipt.snapshot.blockNumber !== input.snapshotBlock)
61
+ return false;
62
+ const tag = blockTagOf(receipt.snapshot.blockNumber);
63
+ return params.at(-1) === tag && plannedStateRequestKeys(input, tag).has(requestKey({ method, params }));
64
+ }
@@ -0,0 +1,149 @@
1
+ import { z } from 'zod';
2
+ import type { ToolContext, WorkflowToolRegistry } from '../../workflow/src/registry.js';
3
+ import { type TariffTable } from './pricing.js';
4
+ import { type RetryPolicy } from './retry.js';
5
+ import { type ModelClient, type ModelEffort, type ModelUsageEntry } from './types.js';
6
+ /**
7
+ * G02 bounded analysis node. Deterministic tools produce every on-chain fact; the model chooses permitted investigative steps,
8
+ * synthesises cited evidence and states uncertainty. Everything that grants or limits capability is enforced here, outside the
9
+ * model: the tool set is fixed before the first request, arguments are validated by zod, every read goes through the caller's
10
+ * `ToolContext` permits, and step/tool/token/cost caps are checked before each request. Tool output and supplied facts are
11
+ * untrusted data and cannot change the tool set or limits. Findings survive only when every cited evidence id was supplied or
12
+ * captured in this node and every address, hash and significant number in the claim appears in that cited evidence.
13
+ */
14
+ export declare const EVIDENCE_ID: RegExp;
15
+ export declare const AnalysisLimitsSchema: z.ZodObject<{
16
+ maxSteps: z.ZodNumber;
17
+ maxInputTokens: z.ZodNumber;
18
+ maxOutputTokens: z.ZodNumber;
19
+ maxCostMicrousd: z.ZodNumber;
20
+ maxToolCalls: z.ZodOptional<z.ZodNumber>;
21
+ }, z.core.$strict>;
22
+ export type AnalysisLimits = z.infer<typeof AnalysisLimitsSchema>;
23
+ /** Final structured output. Completion criteria: an end_turn response whose text parses against this schema. */
24
+ export declare const AnalysisOutputSchema: z.ZodObject<{
25
+ status: z.ZodEnum<{
26
+ answered: "answered";
27
+ "insufficient-evidence": "insufficient-evidence";
28
+ }>;
29
+ findings: z.ZodArray<z.ZodObject<{
30
+ claim: z.ZodString;
31
+ evidenceIds: z.ZodArray<z.ZodString>;
32
+ confidence: z.ZodEnum<{
33
+ supported: "supported";
34
+ uncertain: "uncertain";
35
+ }>;
36
+ }, z.core.$strict>>;
37
+ unknowns: z.ZodArray<z.ZodString>;
38
+ }, z.core.$strict>;
39
+ export type AnalysisOutput = z.infer<typeof AnalysisOutputSchema>;
40
+ export type AnalysisFinding = {
41
+ claim: string;
42
+ evidenceIds: string[];
43
+ confidence: 'supported' | 'uncertain';
44
+ };
45
+ export type RejectedFinding = {
46
+ claim: string;
47
+ evidenceIds: string[];
48
+ reason: 'unknown-evidence' | 'ungrounded-value';
49
+ detail: string;
50
+ };
51
+ export type AnalysisStopReason = 'completed' | 'insufficient-evidence' | 'step-limit' | 'input-token-limit' | 'output-token-limit' | 'cost-limit' | 'refusal' | 'max-tokens' | 'invalid-output' | 'unexpected-stop' | 'provider-error' | 'cancelled';
52
+ export interface AnalysisProgressEvent {
53
+ step: string;
54
+ message: string;
55
+ }
56
+ export interface AnalysisNodeInput {
57
+ task: string;
58
+ allowedTools: string[];
59
+ /** Supplied evidence. `completeness` (from the evidence envelope) downgrades findings citing incomplete evidence to "uncertain". */
60
+ facts: {
61
+ evidenceId: string;
62
+ summary: unknown;
63
+ completeness?: string;
64
+ }[];
65
+ limits: {
66
+ maxSteps: number;
67
+ maxInputTokens: number;
68
+ maxOutputTokens: number;
69
+ maxCostMicrousd: number;
70
+ maxToolCalls?: number;
71
+ };
72
+ toolContext: ToolContext;
73
+ signal: AbortSignal;
74
+ }
75
+ export interface AnalysisNodeDeps {
76
+ client: ModelClient;
77
+ now?: () => Date;
78
+ /** Approved deterministic tools (packages/tools TOOL_REGISTRY). Required when `allowedTools` is non-empty. */
79
+ registry?: WorkflowToolRegistry;
80
+ model?: string;
81
+ effort?: ModelEffort;
82
+ retry?: RetryPolicy;
83
+ tariffs?: TariffTable;
84
+ onProgress?: (event: AnalysisProgressEvent) => void | Promise<void>;
85
+ sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
86
+ /**
87
+ * Runtime permit before each model request (lease/fencing check and worst-case spend reservation against the run budget).
88
+ * A throw is a runtime refusal: it propagates unchanged and no request is sent.
89
+ */
90
+ beforeModelRequest?: (operation: {
91
+ step: number;
92
+ maxOutputTokens: number;
93
+ worstCaseMicrousd: number;
94
+ model: string;
95
+ }) => void | Promise<void>;
96
+ /** Durable usage checkpoint after each billed model response. A throw propagates unchanged (the response is not used). */
97
+ onModelUsage?: (entry: {
98
+ step: number;
99
+ usage: ModelUsageEntry[];
100
+ costMicrousd: number;
101
+ stopReason: string;
102
+ modelServed: string;
103
+ }) => void | Promise<void>;
104
+ }
105
+ export interface AnalysisUsage {
106
+ inputTokens: number;
107
+ outputTokens: number;
108
+ cacheReadTokens: number;
109
+ cacheWriteTokens: number;
110
+ costMicrousd: number;
111
+ steps: number;
112
+ toolCalls: number;
113
+ requests: number;
114
+ retries: number;
115
+ model: string;
116
+ requestedModel: string;
117
+ fallbackUsed: boolean;
118
+ elapsedMs: number;
119
+ }
120
+ export interface AnalysisNodeResult {
121
+ findings: AnalysisFinding[];
122
+ unknowns: string[];
123
+ rejected: RejectedFinding[];
124
+ /** Evidence captured by tool executions in this node (supplied facts excluded). */
125
+ evidenceIds: string[];
126
+ usage: AnalysisUsage;
127
+ stopReason: AnalysisStopReason;
128
+ refusalCategory: string | null;
129
+ providerError: string | null;
130
+ }
131
+ export declare class AnalysisConfigurationError extends Error {
132
+ readonly code = "ANALYSIS_CONFIGURATION";
133
+ constructor(message: string);
134
+ }
135
+ export declare const ANALYSIS_SYSTEM_PROMPT: string;
136
+ /** Scalars in a value as strings, bounded against hostile nesting and size. Addresses inside label strings are masked (V03 review). */
137
+ export declare function groundingStrings(value: unknown, limit?: number): string[];
138
+ /** Null when every address, hash and significant number in the claim appears in the cited evidence. */
139
+ export declare function groundingIssue(claim: string, cited: readonly string[]): string | null;
140
+ export interface KnownEvidence {
141
+ strings: string[];
142
+ completeness: string | null;
143
+ }
144
+ /** Provenance gate: rejects findings citing unknown evidence or ungrounded values; downgrades findings citing incomplete evidence. */
145
+ export declare function checkFindings(findings: AnalysisOutput['findings'], known: ReadonlyMap<string, KnownEvidence>): {
146
+ findings: AnalysisFinding[];
147
+ rejected: RejectedFinding[];
148
+ };
149
+ export declare function runAnalysisNode(rawInput: AnalysisNodeInput, deps: AnalysisNodeDeps): Promise<AnalysisNodeResult>;