@pushchain/core 6.0.27-alpha.0 → 6.0.27-alpha.2

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 (82) hide show
  1. package/AGW.md +104 -19
  2. package/CHANGELOG.md +16 -0
  3. package/package.json +1 -1
  4. package/src/lib/agentic/agentic.types.d.ts +8 -3
  5. package/src/lib/agentic/capabilities.d.ts +1 -1
  6. package/src/lib/agentic/capabilities.js +1 -1
  7. package/src/lib/agentic/codec/abi-layout.d.ts +5 -0
  8. package/src/lib/agentic/codec/abi-layout.js +50 -3
  9. package/src/lib/agentic/codec/defaults.d.ts +2 -2
  10. package/src/lib/agentic/codec/defaults.js +2 -2
  11. package/src/lib/agentic/codec/ids.d.ts +1 -1
  12. package/src/lib/agentic/codec/ids.js +1 -1
  13. package/src/lib/agentic/codec/native.d.ts +4 -6
  14. package/src/lib/agentic/codec/native.js +27 -14
  15. package/src/lib/agentic/codec/pins.d.ts +20 -0
  16. package/src/lib/agentic/codec/pins.js +29 -0
  17. package/src/lib/agentic/codec/rules.d.ts +1 -1
  18. package/src/lib/agentic/codec/rules.js +3 -3
  19. package/src/lib/agentic/codec/session.d.ts +2 -2
  20. package/src/lib/agentic/codec/session.js +3 -3
  21. package/src/lib/agentic/codec/svm-terms.d.ts +1 -1
  22. package/src/lib/agentic/codec/svm-terms.js +7 -3
  23. package/src/lib/agentic/codec/universal-terms.d.ts +15 -0
  24. package/src/lib/agentic/codec/universal-terms.js +2 -0
  25. package/src/lib/agentic/codec/universal.js +22 -6
  26. package/src/lib/agentic/constants.d.ts +1 -0
  27. package/src/lib/agentic/constants.js +1 -0
  28. package/src/lib/agentic/contracts/abi/{v5 → v6}/agent-validator.js +1 -1
  29. package/src/lib/agentic/contracts/abi/{v5 → v6}/agw-factory.d.ts +299 -0
  30. package/src/lib/agentic/contracts/abi/{v5 → v6}/agw-factory.js +393 -2
  31. package/src/lib/agentic/contracts/abi/{v5 → v6}/agw.d.ts +96 -1
  32. package/src/lib/agentic/contracts/abi/{v5 → v6}/agw.js +128 -3
  33. package/src/lib/agentic/contracts/abi/{v5 → v6}/index.d.ts +1 -1
  34. package/src/lib/agentic/contracts/abi/{v5 → v6}/index.js +3 -3
  35. package/src/lib/agentic/contracts/abi/{v5 → v6}/smart-session.js +1 -1
  36. package/src/lib/agentic/contracts/abi/{v5 → v6}/universal-rules-policy.d.ts +329 -308
  37. package/src/lib/agentic/contracts/abi/{v5 → v6}/universal-rules-policy.js +396 -369
  38. package/src/lib/agentic/contracts/donut-v6.d.ts +11 -0
  39. package/src/lib/agentic/contracts/donut-v6.js +15 -0
  40. package/src/lib/agentic/contracts/{v5.d.ts → v6.d.ts} +800 -384
  41. package/src/lib/agentic/contracts/{v5.js → v6.js} +60 -33
  42. package/src/lib/agentic/deployments.d.ts +5 -5
  43. package/src/lib/agentic/deployments.js +19 -19
  44. package/src/lib/agentic/errors.d.ts +1 -7
  45. package/src/lib/agentic/errors.js +1 -9
  46. package/src/lib/agentic/execution/outbound.d.ts +4 -4
  47. package/src/lib/agentic/execution/outbound.js +5 -5
  48. package/src/lib/agentic/execution/send.js +3 -11
  49. package/src/lib/agentic/execution/svm-outbound.d.ts +1 -1
  50. package/src/lib/agentic/execution/svm-payload.js +1 -1
  51. package/src/lib/agentic/execution/svm-public.js +1 -7
  52. package/src/lib/agentic/execution/svm-send.d.ts +1 -1
  53. package/src/lib/agentic/execution/svm-send.js +0 -3
  54. package/src/lib/agentic/index.d.ts +2 -2
  55. package/src/lib/agentic/management/common.js +7 -5
  56. package/src/lib/agentic/management/create.d.ts +1 -13
  57. package/src/lib/agentic/management/create.js +24 -157
  58. package/src/lib/agentic/management/svm.js +2 -2
  59. package/src/lib/agentic/presets/aave-reserves.d.ts +4 -0
  60. package/src/lib/agentic/presets/aave-reserves.js +147 -0
  61. package/src/lib/agentic/presets/catalog.d.ts +30 -3
  62. package/src/lib/agentic/presets/catalog.js +344 -3
  63. package/src/lib/agentic/presets/index.js +186 -22
  64. package/src/lib/agentic/presets/operation-limits.d.ts +13 -0
  65. package/src/lib/agentic/presets/operation-limits.js +111 -0
  66. package/src/lib/agentic/presets/types.d.ts +44 -9
  67. package/src/lib/agentic/public-rule.d.ts +2 -2
  68. package/src/lib/agentic/public-rule.js +24 -40
  69. package/src/lib/agentic/reads/rules.js +27 -11
  70. package/src/lib/agentic/reads/svm.d.ts +1 -1
  71. package/src/lib/agentic/reads/svm.js +2 -2
  72. package/src/lib/agentic/response.js +7 -7
  73. package/src/lib/agentic/revert.js +5 -5
  74. package/src/lib/agentic/runtime.js +12 -3
  75. package/src/lib/agentic/utils.js +1 -1
  76. package/src/lib/constants/index.d.ts +1 -0
  77. package/src/lib/index.d.ts +2 -2
  78. package/src/lib/push-chain/push-chain.d.ts +1 -0
  79. package/src/lib/agentic/contracts/donut-v5.d.ts +0 -11
  80. package/src/lib/agentic/contracts/donut-v5.js +0 -15
  81. /package/src/lib/agentic/contracts/abi/{v5 → v6}/agent-validator.d.ts +0 -0
  82. /package/src/lib/agentic/contracts/abi/{v5 → v6}/smart-session.d.ts +0 -0
@@ -1,10 +1,351 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PRESET_CATALOG = void 0;
4
- /** No approved app/address catalog yet. Empty categories must be hidden by UIs. */
4
+ const viem_1 = require("viem");
5
+ const aave_reserves_1 = require("./aave-reserves");
6
+ /** Mainnet and testnet templates from the October 15 Notion export and protocol sources.
7
+ * Read-only deployment/code evidence and exclusions: plan/agw/research/preset-catalog-2026-10-15/.
8
+ * Mainnet entries are templates only; no mainnet deployment or execution guarantee.
9
+ */
10
+ const address = (value) => (0, viem_1.getAddress)(value.toLowerCase());
11
+ const wallet = 'agentic:wallet';
12
+ const aave = (pool, chain) => [
13
+ ['supply(address,uint256,address,uint16)', 2, 'Supply'],
14
+ ['withdraw(address,uint256,address)', 2, 'Withdraw'],
15
+ ['borrow(address,uint256,uint256,uint16,address)', 4, 'Borrow'],
16
+ ['repay(address,uint256,uint256,address)', 3, 'Repay'],
17
+ ].map(([selector, arg, label]) => ({
18
+ target: pool,
19
+ selector: selector,
20
+ pins: [{ arg: arg, expected: wallet }],
21
+ app: 'Aave V3',
22
+ label: label,
23
+ budget: {
24
+ kind: 'token-argument',
25
+ tokenArg: 0,
26
+ amountArg: 1,
27
+ tokens: aave_reserves_1.AAVE_RESERVES[chain],
28
+ },
29
+ }));
30
+ const market = (target, app, token) => [
31
+ 'mint(uint256)',
32
+ 'redeem(uint256)',
33
+ 'redeemUnderlying(uint256)',
34
+ 'borrow(uint256)',
35
+ 'repayBorrow(uint256)',
36
+ ].map((selector) => ({
37
+ target,
38
+ selector: selector,
39
+ app,
40
+ label: selector.split('(')[0],
41
+ budget: selector === 'redeem(uint256)'
42
+ ? {
43
+ kind: 'unsupported',
44
+ reason: 'SHARE_AMOUNT',
45
+ alternative: 'redeemUnderlying(uint256)',
46
+ }
47
+ : { kind: 'fixed-token', token, amountArg: 0 },
48
+ }));
49
+ const sepoliaPool = address('0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951');
50
+ const basePool = address('0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27');
51
+ const arbitrumPool = address('0xBfC91D59fdAA134A4ED45f7B584cAf96D7792Eff');
52
+ const moonUSDBC = address('0x876852425331a113d8E432eFFB3aC5BEf38f033a');
53
+ const moonWETH = address('0x2F39a349A79492a70E152760ce7123A1933eCf28');
54
+ const venusUSDT = address('0xb7526572FFE56AB9D7489838Bf2E18e3323b441A');
55
+ const venusUSDC = address('0xD5C4C2e2facBEB59D0216D0595d63FcDc6F9A1a7');
56
+ const eigen = address('0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D');
57
+ const stETH = address('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84');
58
+ const wstETH = address('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0');
59
+ const lidoQueue = address('0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1');
60
+ const mainnetMarkets = (chain) => {
61
+ const entries = chain === 'eip155:8453'
62
+ ? [
63
+ [
64
+ '0xEdc817A28E8B93B03976FBd4a3dDBc9f7D176c22',
65
+ 'Moonwell mUSDC',
66
+ '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
67
+ ],
68
+ [
69
+ '0x628ff693426583D9a7FB391E54366292F509D457',
70
+ 'Moonwell mWETH',
71
+ '0x4200000000000000000000000000000000000006',
72
+ ],
73
+ ]
74
+ : chain === 'eip155:56'
75
+ ? [
76
+ [
77
+ '0xfD5840Cd36d94D7229439859C0112a4185BC0255',
78
+ 'Venus vUSDT',
79
+ '0x55d398326f99059fF775485246999027B3197955',
80
+ ],
81
+ [
82
+ '0xecA88125a5ADbe82614ffC12D0DB554E2e2867C8',
83
+ 'Venus vUSDC',
84
+ '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',
85
+ ],
86
+ ]
87
+ : [];
88
+ const controller = chain === 'eip155:8453'
89
+ ? '0xfBb21d0380beE3312B33c4353c8936a0F13EF26C'
90
+ : '0xfD36E2c2a6789Db23113685031d7F16329158384';
91
+ return {
92
+ allowedCalls: [
93
+ ...entries.flatMap(([target, app, token]) => market(address(target), app, address(token))),
94
+ ...(entries.length
95
+ ? [
96
+ {
97
+ target: address(controller),
98
+ selector: 'enterMarkets(address[])',
99
+ app: chain === 'eip155:8453' ? 'Moonwell' : 'Venus',
100
+ label: 'Enter markets',
101
+ budget: { kind: 'setup' },
102
+ },
103
+ ]
104
+ : []),
105
+ ],
106
+ approvals: entries.map(([spender, app, token]) => ({
107
+ spender: address(spender),
108
+ app,
109
+ token: address(token),
110
+ })),
111
+ };
112
+ };
5
113
  exports.PRESET_CATALOG = [
6
- { constant: 'DEXES', name: 'Popular DEXes', chains: [] },
7
- { constant: 'LENDING', name: 'Lending', chains: [] },
114
+ {
115
+ constant: 'DEXES',
116
+ name: 'Popular DEXes',
117
+ chains: [
118
+ ['eip155:1', '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', 'Uniswap V3'],
119
+ [
120
+ 'eip155:8453',
121
+ '0x2626664c2603336E57B271c5C0b26F421741e481',
122
+ 'Uniswap V3',
123
+ ],
124
+ [
125
+ 'eip155:42161',
126
+ '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45',
127
+ 'Uniswap V3',
128
+ ],
129
+ [
130
+ 'eip155:56',
131
+ '0x13f4EA83D0bd40E75C8222255bc855a974568Dd4',
132
+ 'PancakeSwap V3',
133
+ ],
134
+ [
135
+ 'eip155:11155111',
136
+ '0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E',
137
+ 'Uniswap V3',
138
+ ],
139
+ [
140
+ 'eip155:84532',
141
+ '0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4',
142
+ 'Uniswap V3',
143
+ ],
144
+ [
145
+ 'eip155:421614',
146
+ '0x101F443B4d1b059569D643917553c771E1b9663E',
147
+ 'Uniswap V3',
148
+ ],
149
+ [
150
+ 'eip155:97',
151
+ '0x9a489505a00cE272eAa5e07Dba6491314CaE3796',
152
+ 'PancakeSwap V3',
153
+ ],
154
+ ].map(([chain, router, app]) => ({
155
+ chainNamespace: chain,
156
+ allowedCalls: [],
157
+ swapRouters: [{ address: address(router), app }],
158
+ approvals: [{ spender: address(router), app }],
159
+ })),
160
+ },
161
+ {
162
+ constant: 'LENDING',
163
+ name: 'Lending',
164
+ chains: [
165
+ ...[
166
+ ['eip155:1', '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2'],
167
+ ['eip155:8453', '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5'],
168
+ ['eip155:42161', '0x794a61358D6845594F94dc1DB02A252b5b4814aD'],
169
+ ['eip155:56', '0x6807dc923806fE8Fd134338EABCA509979a7e0cB'],
170
+ ].map(([chainNamespace, pool]) => ({
171
+ chainNamespace,
172
+ allowedCalls: [
173
+ ...aave(address(pool), chainNamespace),
174
+ ...mainnetMarkets(chainNamespace).allowedCalls,
175
+ ],
176
+ approvals: [
177
+ {
178
+ spender: address(pool),
179
+ app: 'Aave V3',
180
+ tokens: aave_reserves_1.AAVE_RESERVES[chainNamespace],
181
+ },
182
+ ...(mainnetMarkets(chainNamespace).approvals ?? []),
183
+ ],
184
+ })),
185
+ {
186
+ chainNamespace: 'eip155:11155111',
187
+ allowedCalls: aave(sepoliaPool, 'eip155:11155111'),
188
+ approvals: [
189
+ {
190
+ spender: sepoliaPool,
191
+ app: 'Aave V3',
192
+ tokens: aave_reserves_1.AAVE_RESERVES['eip155:11155111'],
193
+ },
194
+ ],
195
+ },
196
+ {
197
+ chainNamespace: 'eip155:421614',
198
+ allowedCalls: aave(arbitrumPool, 'eip155:421614'),
199
+ approvals: [
200
+ {
201
+ spender: arbitrumPool,
202
+ app: 'Aave V3',
203
+ tokens: aave_reserves_1.AAVE_RESERVES['eip155:421614'],
204
+ },
205
+ ],
206
+ },
207
+ {
208
+ chainNamespace: 'eip155:84532',
209
+ allowedCalls: [
210
+ ...aave(basePool, 'eip155:84532'),
211
+ ...market(moonUSDBC, 'Moonwell mUSDbC', address('0x4616975f7E6045FD9737e95bC527e9e14c727BD2')),
212
+ ...market(moonWETH, 'Moonwell mWETH', address('0x663A6F02d547dFd639BF689FED298712f2FB69Fb')),
213
+ {
214
+ target: address('0xC72ba45f2Ae134F21DAEb2b7B5fd5De0064Ee9bB'),
215
+ selector: 'enterMarkets(address[])',
216
+ app: 'Moonwell',
217
+ label: 'Enter markets',
218
+ budget: { kind: 'setup' },
219
+ },
220
+ ],
221
+ approvals: [
222
+ {
223
+ spender: basePool,
224
+ app: 'Aave V3',
225
+ tokens: aave_reserves_1.AAVE_RESERVES['eip155:84532'],
226
+ },
227
+ {
228
+ spender: moonUSDBC,
229
+ app: 'Moonwell mUSDbC',
230
+ token: address('0x4616975f7E6045FD9737e95bC527e9e14c727BD2'),
231
+ },
232
+ {
233
+ spender: moonWETH,
234
+ app: 'Moonwell mWETH',
235
+ token: address('0x663A6F02d547dFd639BF689FED298712f2FB69Fb'),
236
+ },
237
+ ],
238
+ },
239
+ {
240
+ chainNamespace: 'eip155:97',
241
+ allowedCalls: [
242
+ ...market(venusUSDT, 'Venus vUSDT', address('0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c')),
243
+ ...market(venusUSDC, 'Venus vUSDC', address('0x16227D60f7a0e586C66B005219dfc887D13C9531')),
244
+ {
245
+ target: address('0x94d1820b2D1c7c7452A163983Dc888CEC546b77D'),
246
+ selector: 'enterMarkets(address[])',
247
+ app: 'Venus',
248
+ label: 'Enter markets',
249
+ budget: { kind: 'setup' },
250
+ },
251
+ ],
252
+ approvals: [
253
+ {
254
+ spender: venusUSDT,
255
+ app: 'Venus vUSDT',
256
+ token: address('0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c'),
257
+ },
258
+ {
259
+ spender: venusUSDC,
260
+ app: 'Venus vUSDC',
261
+ token: address('0x16227D60f7a0e586C66B005219dfc887D13C9531'),
262
+ },
263
+ ],
264
+ },
265
+ ],
266
+ },
267
+ {
268
+ constant: 'STAKING',
269
+ name: 'Staking',
270
+ chains: [
271
+ {
272
+ chainNamespace: 'eip155:1',
273
+ allowedCalls: [
274
+ {
275
+ target: stETH,
276
+ selector: 'submit(address)',
277
+ maxValue: BigInt(0),
278
+ app: 'Lido',
279
+ label: 'Stake ETH',
280
+ budget: { kind: 'native-value' },
281
+ },
282
+ {
283
+ target: wstETH,
284
+ selector: 'wrap(uint256)',
285
+ app: 'Lido wstETH',
286
+ label: 'Wrap stETH',
287
+ budget: { kind: 'fixed-token', token: stETH, amountArg: 0 },
288
+ },
289
+ {
290
+ target: wstETH,
291
+ selector: 'unwrap(uint256)',
292
+ app: 'Lido wstETH',
293
+ label: 'Unwrap wstETH',
294
+ budget: { kind: 'fixed-token', token: wstETH, amountArg: 0 },
295
+ },
296
+ {
297
+ target: lidoQueue,
298
+ selector: 'requestWithdrawals(uint256[],address)',
299
+ pins: [{ arg: 1, expected: wallet }],
300
+ app: 'Lido withdrawal queue',
301
+ label: 'Request withdrawal',
302
+ budget: { kind: 'unsupported', reason: 'DYNAMIC_AMOUNT' },
303
+ },
304
+ {
305
+ target: lidoQueue,
306
+ selector: 'claimWithdrawals(uint256[],uint256[])',
307
+ app: 'Lido withdrawal queue',
308
+ label: 'Claim finalized withdrawals',
309
+ budget: { kind: 'unsupported', reason: 'POSITION_AMOUNT' },
310
+ },
311
+ {
312
+ target: lidoQueue,
313
+ selector: 'claimWithdrawal(uint256)',
314
+ app: 'Lido withdrawal queue',
315
+ label: 'Claim finalized withdrawal',
316
+ budget: { kind: 'unsupported', reason: 'POSITION_AMOUNT' },
317
+ },
318
+ {
319
+ target: address('0x858646372CC42E1A627fcE94aa7A7033e7CF075A'),
320
+ selector: 'depositIntoStrategy(address,address,uint256)',
321
+ app: 'EigenLayer',
322
+ label: 'Deposit into strategy (withdrawals not included)',
323
+ budget: { kind: 'token-argument', tokenArg: 1, amountArg: 2 },
324
+ },
325
+ ],
326
+ approvals: [
327
+ { spender: wstETH, token: stETH, app: 'Lido wstETH' },
328
+ {
329
+ spender: address('0x858646372CC42E1A627fcE94aa7A7033e7CF075A'),
330
+ app: 'EigenLayer',
331
+ },
332
+ ],
333
+ },
334
+ {
335
+ chainNamespace: 'eip155:11155111',
336
+ allowedCalls: [
337
+ {
338
+ target: eigen,
339
+ selector: 'depositIntoStrategy(address,address,uint256)',
340
+ app: 'EigenLayer',
341
+ label: 'Deposit into strategy (withdrawals not included)',
342
+ budget: { kind: 'token-argument', tokenArg: 1, amountArg: 2 },
343
+ },
344
+ ],
345
+ approvals: [{ spender: eigen, app: 'EigenLayer' }],
346
+ },
347
+ ],
348
+ },
8
349
  { constant: 'PREDICTION', name: 'Prediction markets', chains: [] },
9
350
  ];
10
351
  //# sourceMappingURL=catalog.js.map
@@ -6,6 +6,7 @@ const viem_1 = require("viem");
6
6
  const errors_1 = require("../errors");
7
7
  const selectors_1 = require("../codec/selectors");
8
8
  const catalog_1 = require("./catalog");
9
+ const operation_limits_1 = require("./operation-limits");
9
10
  const MAX_UINT256 = (BigInt(1) << BigInt(256)) - BigInt(1);
10
11
  const invalid = (message) => new errors_1.AgenticError(errors_1.AGENTIC_ERROR_CODE.INVALID_RULE, message);
11
12
  function cap(value, name) {
@@ -20,12 +21,19 @@ function copyCall(call) {
20
21
  ...call,
21
22
  ...(call.pins
22
23
  ? {
23
- pins: call.pins.map((p) => ({
24
- ...p,
25
- ...('token' in p && p.token && typeof p.token === 'object'
26
- ? { token: { ...p.token } }
27
- : {}),
28
- })),
24
+ pins: call.pins.map((pin) => {
25
+ if (pin.account !== undefined)
26
+ return {
27
+ ...pin,
28
+ ...(pin.token && typeof pin.token === 'object'
29
+ ? { token: { ...pin.token } }
30
+ : {}),
31
+ };
32
+ return {
33
+ ...pin,
34
+ arg: typeof pin.arg === 'number' ? pin.arg : [...pin.arg],
35
+ };
36
+ }),
29
37
  }
30
38
  : {}),
31
39
  };
@@ -43,8 +51,24 @@ function buildPresetApi(catalog) {
43
51
  ...p,
44
52
  chains: p.chains.map((c) => ({
45
53
  ...c,
46
- allowedCalls: c.allowedCalls.map(copyCall),
47
- approvals: c.approvals?.map((a) => ({ ...a })),
54
+ allowedCalls: c.allowedCalls.map((call) => ({
55
+ ...copyCall(call),
56
+ ...(call.budget
57
+ ? {
58
+ budget: {
59
+ ...call.budget,
60
+ ...(call.budget.kind === 'token-argument' && call.budget.tokens
61
+ ? { tokens: [...call.budget.tokens] }
62
+ : {}),
63
+ },
64
+ }
65
+ : {}),
66
+ })),
67
+ approvals: c.approvals?.map((a) => ({
68
+ ...a,
69
+ ...(a.tokens ? { tokens: [...a.tokens] } : {}),
70
+ })),
71
+ swapRouters: c.swapRouters?.map((r) => ({ ...r })),
48
72
  })),
49
73
  }));
50
74
  if (new Set(entries.map((e) => e.constant)).size !== entries.length ||
@@ -78,6 +102,8 @@ function buildPresetApi(catalog) {
78
102
  options.validUntil <= Math.floor(Date.now() / 1000) ||
79
103
  options.validUntil >= 2 ** 48))
80
104
  throw invalid('preset validUntil must be a future uint48 timestamp');
105
+ if (options.maxGasPerCall !== undefined)
106
+ cap(options.maxGasPerCall, 'maxGasPerCall');
81
107
  if (options.assets !== undefined && !Array.isArray(options.assets))
82
108
  throw invalid('preset assets must be an array');
83
109
  const chains = options.chainNamespace === undefined
@@ -115,9 +141,88 @@ function buildPresetApi(catalog) {
115
141
  });
116
142
  assets.set(chain, group);
117
143
  }
144
+ const readiness = [];
118
145
  const rules = chains.map((chain) => {
119
- const calls = chain.allowedCalls.map(copyCall);
120
- const approvals = new Map();
146
+ const selectedAssets = assets.get(chain.chainNamespace) ?? [];
147
+ const limits = (0, operation_limits_1.applyOperationLimits)(chain.allowedCalls.map((c) => ({
148
+ ...copyCall(c),
149
+ ...(c.budget ? { budget: c.budget } : {}),
150
+ })), selectedAssets);
151
+ const calls = limits.calls;
152
+ if (chain.swapRouters?.length) {
153
+ const tokens = assets.get(chain.chainNamespace) ?? [];
154
+ if (tokens.some((a) => tokenAddress(a.token) === viem_1.zeroAddress ||
155
+ (typeof a.token !== 'string' && a.token.mechanism === 'native')))
156
+ throw invalid('DEX token pins require explicit ERC20 addresses; use wrapped-native tokens instead of the native marker');
157
+ // Keep discovery useful before a swap pair is selected. These review
158
+ // calls cannot spend input tokens: the amount maximum is explicitly zero.
159
+ // Re-run get with both tokens to generate the executable pair pins.
160
+ if (tokens.length < 2)
161
+ for (const router of chain.swapRouters)
162
+ for (const exactInput of [true, false])
163
+ calls.push({
164
+ target: router.address,
165
+ selector: `${exactInput ? 'exactInputSingle' : 'exactOutputSingle'}((address,address,uint24,address,uint256,uint256,uint160))`,
166
+ pins: [
167
+ ...(tokens.length
168
+ ? [
169
+ {
170
+ arg: [0, 0],
171
+ expected: (0, viem_1.getAddress)(tokenAddress(tokens[0].token)),
172
+ },
173
+ ]
174
+ : []),
175
+ { arg: [0, 3], expected: 'agentic:wallet' },
176
+ { arg: [0, exactInput ? 4 : 5], max: BigInt(0) },
177
+ ],
178
+ app: router.app,
179
+ label: `${exactInput ? 'Swap exact input' : 'Swap exact output'} (select two tokens to enable)`,
180
+ });
181
+ for (const router of chain.swapRouters)
182
+ for (const input of tokens)
183
+ for (const output of tokens) {
184
+ if (tokenAddress(input.token).toLowerCase() ===
185
+ tokenAddress(output.token).toLowerCase())
186
+ continue;
187
+ for (const exactInput of [true, false])
188
+ calls.push({
189
+ target: router.address,
190
+ selector: `${exactInput ? 'exactInputSingle' : 'exactOutputSingle'}((address,address,uint24,address,uint256,uint256,uint160))`,
191
+ pins: [
192
+ {
193
+ arg: [0, 0],
194
+ expected: (0, viem_1.getAddress)(tokenAddress(input.token)),
195
+ },
196
+ {
197
+ arg: [0, 1],
198
+ expected: (0, viem_1.getAddress)(tokenAddress(output.token)),
199
+ },
200
+ { arg: [0, 3], expected: 'agentic:wallet' },
201
+ { arg: [0, exactInput ? 4 : 5], max: input.maxPerCall },
202
+ ],
203
+ app: router.app,
204
+ label: exactInput
205
+ ? 'Swap exact input'
206
+ : 'Swap exact output',
207
+ });
208
+ }
209
+ }
210
+ if (chain.swapRouters?.length) {
211
+ const swaps = calls.filter((c) => c.selector.startsWith('exact'));
212
+ for (const c of swaps) {
213
+ const positive = c.pins?.some((p) => 'max' in p && p.max !== undefined && p.max > BigInt(0));
214
+ if (positive)
215
+ limits.enabled = true;
216
+ else
217
+ limits.disabledCalls.push({
218
+ target: c.target,
219
+ selector: c.selector,
220
+ app: c.app,
221
+ reason: selectedAssets.length < 2 ? 'TOKEN_REQUIRED' : 'ZERO_CAP',
222
+ });
223
+ }
224
+ }
225
+ const approvals = new Set();
121
226
  for (const asset of assets.get(chain.chainNamespace) ?? []) {
122
227
  const token = tokenAddress(asset.token);
123
228
  if (token === viem_1.zeroAddress ||
@@ -127,14 +232,18 @@ function buildPresetApi(catalog) {
127
232
  for (const approval of chain.approvals ?? []) {
128
233
  if (!chain.chainNamespace.startsWith('eip155:'))
129
234
  throw (0, errors_1.capabilityUnavailable)('presetApproval', 'Solana approvals require a separately reviewed instruction template');
235
+ if (approval.token &&
236
+ (0, viem_1.getAddress)(token) !== (0, viem_1.getAddress)(approval.token))
237
+ continue;
238
+ if (approval.tokens &&
239
+ !approval.tokens.some((t) => (0, viem_1.getAddress)(t) === (0, viem_1.getAddress)(token)))
240
+ continue;
130
241
  const spender = (0, viem_1.getAddress)(approval.spender);
131
242
  const target = (0, viem_1.getAddress)(token);
132
- const previous = approvals.get(target);
133
- if (previous && previous !== spender)
134
- throw (0, errors_1.capabilityUnavailable)('presetApproval', 'multiple spenders for one token need a reviewed policy representation; no unrestricted approval is generated');
135
- if (previous)
243
+ const approvalKey = `${target}:${spender}`;
244
+ if (approvals.has(approvalKey))
136
245
  continue;
137
- approvals.set(target, spender);
246
+ approvals.add(approvalKey);
138
247
  calls.push({
139
248
  target,
140
249
  selector: 'approve(address,uint256)',
@@ -149,7 +258,9 @@ function buildPresetApi(catalog) {
149
258
  }
150
259
  if (!calls.length || calls.length > 32)
151
260
  throw (0, errors_1.capabilityUnavailable)('presetCalls', 'preset must contain 1..32 allowed calls including approvals');
152
- const pairs = new Set();
261
+ if (calls.reduce((n, c) => n + (c.pins?.length ?? 0), 0) > 32)
262
+ throw (0, errors_1.capabilityUnavailable)('presetPins', 'preset expansion exceeds 32 pins; reduce the token list or split rules across wallets');
263
+ const pairs = new Map();
153
264
  for (const call of calls) {
154
265
  if (!/^[A-Za-z_$][\w$]*\(.*\)$/.test(call.selector))
155
266
  throw invalid('preset selectors must be full signatures');
@@ -159,10 +270,55 @@ function buildPresetApi(catalog) {
159
270
  const pair = `${chain.chainNamespace.startsWith('eip155:')
160
271
  ? call.target.toLowerCase()
161
272
  : call.target}:${selector}`;
162
- if (pairs.has(pair))
163
- throw (0, errors_1.capabilityUnavailable)('presetCalls', 'duplicate target/function entries need a reviewed policy representation');
164
- pairs.add(pair);
273
+ if (pairs.has(pair) && !chain.chainNamespace.startsWith('eip155:'))
274
+ throw (0, errors_1.capabilityUnavailable)('presetCalls', 'Solana does not support alternative entries for one program/instruction');
275
+ if (pairs.has(pair) && (!call.pins?.length || !pairs.get(pair)))
276
+ throw (0, errors_1.capabilityUnavailable)('presetCalls', 'an unpinned alternative would bypass restrictions for this target/function');
277
+ pairs.set(pair, !!call.pins?.length);
165
278
  }
279
+ const issues = [];
280
+ if (!options.agent)
281
+ issues.push({
282
+ code: 'AGENT_REQUIRED',
283
+ message: 'Choose the agent Push address.',
284
+ });
285
+ if (!options.validUntil)
286
+ issues.push({
287
+ code: 'EXPIRY_REQUIRED',
288
+ message: 'Choose an expiry.',
289
+ });
290
+ if ((options.maxGasPerCall ?? chain.maxGasPerCall ?? BigInt(0)) ===
291
+ BigInt(0))
292
+ issues.push({
293
+ code: 'GAS_BUDGET_REQUIRED',
294
+ message: 'Set a positive PC gas budget per outbound.',
295
+ });
296
+ if (!selectedAssets.length)
297
+ issues.push({
298
+ code: 'ASSETS_REQUIRED',
299
+ message: 'Choose tokens and their limits, then regenerate this preset.',
300
+ });
301
+ if (chain.swapRouters?.length && selectedAssets.length < 2)
302
+ issues.push({
303
+ code: 'TOKEN_PAIR_REQUIRED',
304
+ message: 'Choose both swap tokens, then regenerate this preset.',
305
+ });
306
+ if (!limits.enabled)
307
+ issues.push({
308
+ code: 'NO_ENABLED_OPERATION',
309
+ message: 'No asset operation has a positive per-call limit.',
310
+ });
311
+ readiness.push({
312
+ chainNamespace: chain.chainNamespace,
313
+ ready: issues.length === 0,
314
+ issues,
315
+ disabledCalls: limits.disabledCalls,
316
+ excludedCalls: limits.excludedCalls,
317
+ knownTokens: limits.knownTokens,
318
+ zeroBridgeLimits: selectedAssets
319
+ .filter((a) => a.maxPerCall === BigInt(0) || a.maxTotal === BigInt(0))
320
+ .map(operation_limits_1.assetAddress),
321
+ });
166
322
  return {
167
323
  chainNamespace: chain.chainNamespace,
168
324
  allowedCalls: calls,
@@ -175,12 +331,20 @@ function buildPresetApi(catalog) {
175
331
  ...(options.assets !== undefined
176
332
  ? { assets: assets.get(chain.chainNamespace) ?? [] }
177
333
  : {}),
178
- ...(chain.maxGasPerCall !== undefined
179
- ? { maxGasPerCall: cap(chain.maxGasPerCall, 'maxGasPerCall') }
334
+ ...((options.maxGasPerCall ?? chain.maxGasPerCall) !== undefined
335
+ ? {
336
+ maxGasPerCall: cap(options.maxGasPerCall ?? chain.maxGasPerCall, 'maxGasPerCall'),
337
+ }
180
338
  : {}),
181
339
  };
182
340
  });
183
- return { rules };
341
+ return {
342
+ rules,
343
+ readiness: {
344
+ ready: readiness.length > 0 && readiness.every((c) => c.ready),
345
+ chains: readiness,
346
+ },
347
+ };
184
348
  },
185
349
  };
186
350
  // The overload narrows templates only when both required fields were supplied and validated.
@@ -0,0 +1,13 @@
1
+ import type { RuleAsset, RuleCall } from '../agentic.types';
2
+ import type { PresetCallDefinition } from './catalog';
3
+ import type { PresetCallIssue } from './types';
4
+ export declare const assetAddress: (asset: RuleAsset) => string;
5
+ export declare const nativeAsset: (asset: RuleAsset) => boolean;
6
+ /** Compile reviewed protocol argument positions. No exchange-rate or share guesses. */
7
+ export declare function applyOperationLimits(definitions: readonly PresetCallDefinition[], assets: RuleAsset[]): {
8
+ calls: RuleCall[];
9
+ enabled: boolean;
10
+ disabledCalls: PresetCallIssue[];
11
+ excludedCalls: PresetCallIssue[];
12
+ knownTokens: string[];
13
+ };