@smartagentkit/sdk 0.1.2 → 0.1.3
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.
- package/dist/index.d.mts +29 -7
- package/dist/index.d.ts +29 -7
- package/dist/index.js +320 -155
- package/dist/index.mjs +324 -157
- package/package.json +1 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,9 @@ import {
|
|
|
3
3
|
createPublicClient,
|
|
4
4
|
createWalletClient,
|
|
5
5
|
http,
|
|
6
|
-
encodeFunctionData
|
|
6
|
+
encodeFunctionData,
|
|
7
|
+
isAddress as isAddress2,
|
|
8
|
+
isHex
|
|
7
9
|
} from "viem";
|
|
8
10
|
import {
|
|
9
11
|
privateKeyToAccount,
|
|
@@ -18,7 +20,7 @@ import { erc7579Actions } from "permissionless/actions/erc7579";
|
|
|
18
20
|
import { getHookMultiPlexer } from "@rhinestone/module-sdk";
|
|
19
21
|
|
|
20
22
|
// src/presets.ts
|
|
21
|
-
import { parseEther } from "viem";
|
|
23
|
+
import { parseEther, isAddress } from "viem";
|
|
22
24
|
|
|
23
25
|
// src/constants.ts
|
|
24
26
|
var MODULE_TYPE_VALIDATOR = 1;
|
|
@@ -30,6 +32,7 @@ var ENTRYPOINT_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
|
|
|
30
32
|
var SAFE_7579_MODULE = "0x7579EE8307284F293B1927136486880611F20002";
|
|
31
33
|
var SAFE_7579_LAUNCHPAD = "0x7579011aB74c46090561ea277Ba79D510c6C00ff";
|
|
32
34
|
var RHINESTONE_ATTESTER = "0x000000333034E9f539ce08819E12c1b8Cb29084d";
|
|
35
|
+
var SMART_SESSIONS_VALIDATOR = "0x00000000002B0eCfbD0496EE71e01257dA0E37DE";
|
|
33
36
|
var ATTESTERS_THRESHOLD = 1;
|
|
34
37
|
var WINDOW_1_HOUR = 3600;
|
|
35
38
|
var WINDOW_1_DAY = 86400;
|
|
@@ -167,15 +170,6 @@ var MODULE_ONINSTALL_ABI = [
|
|
|
167
170
|
stateMutability: "nonpayable"
|
|
168
171
|
}
|
|
169
172
|
];
|
|
170
|
-
var SET_TRUSTED_FORWARDER_ABI = [
|
|
171
|
-
{
|
|
172
|
-
name: "setTrustedForwarder",
|
|
173
|
-
type: "function",
|
|
174
|
-
inputs: [{ name: "forwarder", type: "address" }],
|
|
175
|
-
outputs: [],
|
|
176
|
-
stateMutability: "nonpayable"
|
|
177
|
-
}
|
|
178
|
-
];
|
|
179
173
|
var HOOK_MULTIPLEXER_ABI = [
|
|
180
174
|
{
|
|
181
175
|
name: "addHook",
|
|
@@ -202,119 +196,6 @@ var MODULE_ADDRESSES = {
|
|
|
202
196
|
// Will be populated after deployment
|
|
203
197
|
};
|
|
204
198
|
|
|
205
|
-
// src/presets.ts
|
|
206
|
-
var PRESETS = {
|
|
207
|
-
/**
|
|
208
|
-
* DeFi Trader preset:
|
|
209
|
-
* - Daily spending limit on ETH and stablecoins
|
|
210
|
-
* - Allowlist of approved DEX contracts
|
|
211
|
-
* - Emergency pause with owner as guardian
|
|
212
|
-
*/
|
|
213
|
-
"defi-trader": (owner, params = {}) => [
|
|
214
|
-
{
|
|
215
|
-
type: "spending-limit",
|
|
216
|
-
limits: [
|
|
217
|
-
{
|
|
218
|
-
token: NATIVE_TOKEN,
|
|
219
|
-
limit: params.dailyEthLimit ?? parseEther("1"),
|
|
220
|
-
window: WINDOW_1_DAY
|
|
221
|
-
},
|
|
222
|
-
...params.stablecoinLimits ?? []
|
|
223
|
-
]
|
|
224
|
-
},
|
|
225
|
-
// Only include allowlist if specific DEXes are provided;
|
|
226
|
-
// an empty allowlist in "allow" mode would block all transactions.
|
|
227
|
-
...params.allowedDexes?.length ? [
|
|
228
|
-
{
|
|
229
|
-
type: "allowlist",
|
|
230
|
-
mode: "allow",
|
|
231
|
-
targets: params.allowedDexes.map((addr) => ({
|
|
232
|
-
address: addr,
|
|
233
|
-
selector: "0x00000000"
|
|
234
|
-
}))
|
|
235
|
-
}
|
|
236
|
-
] : [],
|
|
237
|
-
{
|
|
238
|
-
type: "emergency-pause",
|
|
239
|
-
guardian: params.guardian ?? owner,
|
|
240
|
-
autoUnpauseAfter: WINDOW_1_DAY
|
|
241
|
-
}
|
|
242
|
-
],
|
|
243
|
-
/**
|
|
244
|
-
* Treasury Agent preset:
|
|
245
|
-
* - Lower spending limits with longer windows
|
|
246
|
-
* - Emergency pause (manual only)
|
|
247
|
-
*/
|
|
248
|
-
"treasury-agent": (owner, params = {}) => [
|
|
249
|
-
{
|
|
250
|
-
type: "spending-limit",
|
|
251
|
-
limits: [
|
|
252
|
-
{
|
|
253
|
-
token: NATIVE_TOKEN,
|
|
254
|
-
limit: params.weeklyEthLimit ?? parseEther("5"),
|
|
255
|
-
window: WINDOW_1_WEEK
|
|
256
|
-
}
|
|
257
|
-
]
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
type: "emergency-pause",
|
|
261
|
-
guardian: params.guardian ?? owner,
|
|
262
|
-
autoUnpauseAfter: 0
|
|
263
|
-
}
|
|
264
|
-
],
|
|
265
|
-
/**
|
|
266
|
-
* Payment Agent preset:
|
|
267
|
-
* - Strict spending limits
|
|
268
|
-
* - Allowlist of approved recipients only
|
|
269
|
-
* - Emergency pause
|
|
270
|
-
*/
|
|
271
|
-
"payment-agent": (owner, params = {}) => [
|
|
272
|
-
{
|
|
273
|
-
type: "spending-limit",
|
|
274
|
-
limits: [
|
|
275
|
-
{
|
|
276
|
-
token: NATIVE_TOKEN,
|
|
277
|
-
limit: params.dailyLimit ?? parseEther("0.1"),
|
|
278
|
-
window: WINDOW_1_DAY
|
|
279
|
-
}
|
|
280
|
-
]
|
|
281
|
-
},
|
|
282
|
-
// Only include allowlist if specific recipients are provided;
|
|
283
|
-
// an empty allowlist in "allow" mode would block all transactions.
|
|
284
|
-
...params.approvedRecipients?.length ? [
|
|
285
|
-
{
|
|
286
|
-
type: "allowlist",
|
|
287
|
-
mode: "allow",
|
|
288
|
-
targets: params.approvedRecipients.map(
|
|
289
|
-
(addr) => ({
|
|
290
|
-
address: addr
|
|
291
|
-
})
|
|
292
|
-
)
|
|
293
|
-
}
|
|
294
|
-
] : [],
|
|
295
|
-
{
|
|
296
|
-
type: "emergency-pause",
|
|
297
|
-
guardian: params.guardian ?? owner,
|
|
298
|
-
autoUnpauseAfter: 3600
|
|
299
|
-
}
|
|
300
|
-
],
|
|
301
|
-
/**
|
|
302
|
-
* Minimal preset:
|
|
303
|
-
* - Just emergency pause
|
|
304
|
-
* - For agents that need maximum flexibility with a kill switch
|
|
305
|
-
*/
|
|
306
|
-
minimal: (owner, params = {}) => [
|
|
307
|
-
{
|
|
308
|
-
type: "emergency-pause",
|
|
309
|
-
guardian: params.guardian ?? owner,
|
|
310
|
-
autoUnpauseAfter: 0
|
|
311
|
-
}
|
|
312
|
-
]
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
// src/policies.ts
|
|
316
|
-
import { encodeAbiParameters, parseAbiParameters } from "viem";
|
|
317
|
-
|
|
318
199
|
// src/errors.ts
|
|
319
200
|
var SmartAgentKitError = class extends Error {
|
|
320
201
|
constructor(message, options) {
|
|
@@ -365,7 +246,174 @@ var SessionError = class extends SmartAgentKitError {
|
|
|
365
246
|
}
|
|
366
247
|
};
|
|
367
248
|
|
|
249
|
+
// src/presets.ts
|
|
250
|
+
function validatePresetParams(presetName, params, spec) {
|
|
251
|
+
for (const [key, expectedType] of Object.entries(spec)) {
|
|
252
|
+
if (params[key] === void 0) continue;
|
|
253
|
+
const value = params[key];
|
|
254
|
+
switch (expectedType) {
|
|
255
|
+
case "bigint":
|
|
256
|
+
if (typeof value !== "bigint") {
|
|
257
|
+
throw new PolicyConfigError(
|
|
258
|
+
`Preset "${presetName}": parameter "${key}" must be a bigint, got ${typeof value}`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
case "Address":
|
|
263
|
+
if (typeof value !== "string" || !isAddress(value)) {
|
|
264
|
+
throw new PolicyConfigError(
|
|
265
|
+
`Preset "${presetName}": parameter "${key}" must be a valid Ethereum address`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
break;
|
|
269
|
+
case "Address[]":
|
|
270
|
+
if (!Array.isArray(value) || !value.every((v) => typeof v === "string" && isAddress(v))) {
|
|
271
|
+
throw new PolicyConfigError(
|
|
272
|
+
`Preset "${presetName}": parameter "${key}" must be an array of valid Ethereum addresses`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
var PRESETS = {
|
|
280
|
+
/**
|
|
281
|
+
* DeFi Trader preset:
|
|
282
|
+
* - Daily spending limit on ETH and stablecoins
|
|
283
|
+
* - Allowlist of approved DEX contracts
|
|
284
|
+
* - Emergency pause with owner as guardian
|
|
285
|
+
*/
|
|
286
|
+
"defi-trader": (owner, params = {}) => {
|
|
287
|
+
validatePresetParams("defi-trader", params, {
|
|
288
|
+
dailyEthLimit: "bigint",
|
|
289
|
+
guardian: "Address",
|
|
290
|
+
allowedDexes: "Address[]"
|
|
291
|
+
});
|
|
292
|
+
return [
|
|
293
|
+
{
|
|
294
|
+
type: "spending-limit",
|
|
295
|
+
limits: [
|
|
296
|
+
{
|
|
297
|
+
token: NATIVE_TOKEN,
|
|
298
|
+
limit: params.dailyEthLimit ?? parseEther("1"),
|
|
299
|
+
window: WINDOW_1_DAY
|
|
300
|
+
},
|
|
301
|
+
...params.stablecoinLimits ?? []
|
|
302
|
+
]
|
|
303
|
+
},
|
|
304
|
+
// Only include allowlist if specific DEXes are provided;
|
|
305
|
+
// an empty allowlist in "allow" mode would block all transactions.
|
|
306
|
+
...params.allowedDexes?.length ? [
|
|
307
|
+
{
|
|
308
|
+
type: "allowlist",
|
|
309
|
+
mode: "allow",
|
|
310
|
+
targets: params.allowedDexes.map((addr) => ({
|
|
311
|
+
address: addr
|
|
312
|
+
// Omit selector to use the wildcard (0x431e2cf5) — allows all
|
|
313
|
+
// function calls, not just ETH transfers. 0x00000000 is NOT a
|
|
314
|
+
// wildcard; it only matches empty calldata.
|
|
315
|
+
}))
|
|
316
|
+
}
|
|
317
|
+
] : [],
|
|
318
|
+
{
|
|
319
|
+
type: "emergency-pause",
|
|
320
|
+
guardian: params.guardian ?? owner,
|
|
321
|
+
autoUnpauseAfter: WINDOW_1_DAY
|
|
322
|
+
}
|
|
323
|
+
];
|
|
324
|
+
},
|
|
325
|
+
/**
|
|
326
|
+
* Treasury Agent preset:
|
|
327
|
+
* - Lower spending limits with longer windows
|
|
328
|
+
* - Emergency pause (manual only)
|
|
329
|
+
*/
|
|
330
|
+
"treasury-agent": (owner, params = {}) => {
|
|
331
|
+
validatePresetParams("treasury-agent", params, {
|
|
332
|
+
weeklyEthLimit: "bigint",
|
|
333
|
+
guardian: "Address"
|
|
334
|
+
});
|
|
335
|
+
return [
|
|
336
|
+
{
|
|
337
|
+
type: "spending-limit",
|
|
338
|
+
limits: [
|
|
339
|
+
{
|
|
340
|
+
token: NATIVE_TOKEN,
|
|
341
|
+
limit: params.weeklyEthLimit ?? parseEther("5"),
|
|
342
|
+
window: WINDOW_1_WEEK
|
|
343
|
+
}
|
|
344
|
+
]
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
type: "emergency-pause",
|
|
348
|
+
guardian: params.guardian ?? owner,
|
|
349
|
+
autoUnpauseAfter: 0
|
|
350
|
+
}
|
|
351
|
+
];
|
|
352
|
+
},
|
|
353
|
+
/**
|
|
354
|
+
* Payment Agent preset:
|
|
355
|
+
* - Strict spending limits
|
|
356
|
+
* - Allowlist of approved recipients only
|
|
357
|
+
* - Emergency pause
|
|
358
|
+
*/
|
|
359
|
+
"payment-agent": (owner, params = {}) => {
|
|
360
|
+
validatePresetParams("payment-agent", params, {
|
|
361
|
+
dailyLimit: "bigint",
|
|
362
|
+
guardian: "Address",
|
|
363
|
+
approvedRecipients: "Address[]"
|
|
364
|
+
});
|
|
365
|
+
return [
|
|
366
|
+
{
|
|
367
|
+
type: "spending-limit",
|
|
368
|
+
limits: [
|
|
369
|
+
{
|
|
370
|
+
token: NATIVE_TOKEN,
|
|
371
|
+
limit: params.dailyLimit ?? parseEther("0.1"),
|
|
372
|
+
window: WINDOW_1_DAY
|
|
373
|
+
}
|
|
374
|
+
]
|
|
375
|
+
},
|
|
376
|
+
// Only include allowlist if specific recipients are provided;
|
|
377
|
+
// an empty allowlist in "allow" mode would block all transactions.
|
|
378
|
+
...params.approvedRecipients?.length ? [
|
|
379
|
+
{
|
|
380
|
+
type: "allowlist",
|
|
381
|
+
mode: "allow",
|
|
382
|
+
targets: params.approvedRecipients.map(
|
|
383
|
+
(addr) => ({
|
|
384
|
+
address: addr
|
|
385
|
+
})
|
|
386
|
+
)
|
|
387
|
+
}
|
|
388
|
+
] : [],
|
|
389
|
+
{
|
|
390
|
+
type: "emergency-pause",
|
|
391
|
+
guardian: params.guardian ?? owner,
|
|
392
|
+
autoUnpauseAfter: 3600
|
|
393
|
+
}
|
|
394
|
+
];
|
|
395
|
+
},
|
|
396
|
+
/**
|
|
397
|
+
* Minimal preset:
|
|
398
|
+
* - Just emergency pause
|
|
399
|
+
* - For agents that need maximum flexibility with a kill switch
|
|
400
|
+
*/
|
|
401
|
+
minimal: (owner, params = {}) => {
|
|
402
|
+
validatePresetParams("minimal", params, {
|
|
403
|
+
guardian: "Address"
|
|
404
|
+
});
|
|
405
|
+
return [
|
|
406
|
+
{
|
|
407
|
+
type: "emergency-pause",
|
|
408
|
+
guardian: params.guardian ?? owner,
|
|
409
|
+
autoUnpauseAfter: 0
|
|
410
|
+
}
|
|
411
|
+
];
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
368
415
|
// src/policies.ts
|
|
416
|
+
import { encodeAbiParameters, parseAbiParameters } from "viem";
|
|
369
417
|
function encodePolicyInitData(policy, moduleAddresses, trustedForwarder = "0x0000000000000000000000000000000000000000") {
|
|
370
418
|
const zeroAddress = "0x0000000000000000000000000000000000000000";
|
|
371
419
|
switch (policy.type) {
|
|
@@ -480,11 +528,11 @@ var base_sepolia_default = {
|
|
|
480
528
|
safe7579Launchpad: "0x7579011aB74c46090561ea277Ba79D510c6C00ff",
|
|
481
529
|
rhinestoneAttester: "0x000000333034E9f539ce08819E12c1b8Cb29084d",
|
|
482
530
|
hookMultiPlexer: "0xF6782ed057F95f334D04F0Af1Af4D14fb84DE549",
|
|
483
|
-
spendingLimitHook: "
|
|
484
|
-
allowlistHook: "
|
|
485
|
-
emergencyPauseHook: "
|
|
486
|
-
automationExecutor: "
|
|
487
|
-
moduleSetupHelper: "
|
|
531
|
+
spendingLimitHook: "0xd67a5E6784A66Ddf4C09EA7bbf81Ab89532624E4",
|
|
532
|
+
allowlistHook: "0x7899b03386A3874393A3769D637977d947A9Fc66",
|
|
533
|
+
emergencyPauseHook: "0xAc0cE5672aED1Bfe5549b885f883a770Acd8cAE3",
|
|
534
|
+
automationExecutor: "0x795DB663b70bAe110C10694DF3f5D801b76E2b20",
|
|
535
|
+
moduleSetupHelper: "0xcBb12Eb2CF324B1C34160F72E037589CEEC35Fa0"
|
|
488
536
|
};
|
|
489
537
|
|
|
490
538
|
// src/deployments/sepolia.json
|
|
@@ -660,6 +708,11 @@ function getRemoveAction(permissionId) {
|
|
|
660
708
|
// src/client.ts
|
|
661
709
|
function resolveAccount(key) {
|
|
662
710
|
if (typeof key === "string") {
|
|
711
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
|
|
712
|
+
throw new WalletCreationError(
|
|
713
|
+
"Invalid private key format. Expected a 0x-prefixed 32-byte hex string."
|
|
714
|
+
);
|
|
715
|
+
}
|
|
663
716
|
return privateKeyToAccount(key);
|
|
664
717
|
}
|
|
665
718
|
return mnemonicToAccount(key.mnemonic, {
|
|
@@ -710,7 +763,7 @@ var SmartAgentKitClient = class {
|
|
|
710
763
|
const ownerAccount = resolveAccount(ownerKey);
|
|
711
764
|
if (ownerAccount.address.toLowerCase() !== params.owner.toLowerCase()) {
|
|
712
765
|
throw new WalletCreationError(
|
|
713
|
-
|
|
766
|
+
"Owner address does not match the provided signing key. Verify that the private key or mnemonic corresponds to the specified owner address."
|
|
714
767
|
);
|
|
715
768
|
}
|
|
716
769
|
const hookModule = getHookMultiPlexer({
|
|
@@ -767,7 +820,7 @@ var SmartAgentKitClient = class {
|
|
|
767
820
|
} catch (error) {
|
|
768
821
|
if (error instanceof WalletCreationError) throw error;
|
|
769
822
|
throw new WalletCreationError(
|
|
770
|
-
|
|
823
|
+
"Wallet deployment failed. Check your RPC/bundler configuration and that the owner key is correct.",
|
|
771
824
|
error
|
|
772
825
|
);
|
|
773
826
|
}
|
|
@@ -821,7 +874,13 @@ var SmartAgentKitClient = class {
|
|
|
821
874
|
* the smart account via Smart Sessions. The session is scoped to
|
|
822
875
|
* specific target contracts, function selectors, and time window.
|
|
823
876
|
*
|
|
824
|
-
* @returns The session key address
|
|
877
|
+
* @returns The session key address and permission ID.
|
|
878
|
+
*
|
|
879
|
+
* SECURITY: The session private key is intentionally NOT returned or stored
|
|
880
|
+
* by the SDK. The caller should use the `sessionKey` address to identify
|
|
881
|
+
* the session on-chain, and manage key material externally via a secure
|
|
882
|
+
* key management system. To use a pre-generated key pair, provide the
|
|
883
|
+
* session key address in `params.sessionKey`.
|
|
825
884
|
*/
|
|
826
885
|
async createSession(wallet, params, ownerKey) {
|
|
827
886
|
const client = this.getWalletClient(wallet.address);
|
|
@@ -874,7 +933,6 @@ var SmartAgentKitClient = class {
|
|
|
874
933
|
walletSessions.push({
|
|
875
934
|
permissionId,
|
|
876
935
|
sessionKeyAddress: sessionAccount.address,
|
|
877
|
-
sessionKeyPrivateKey: sessionPrivateKey,
|
|
878
936
|
expiresAt: params.expiresAt,
|
|
879
937
|
actions: params.actions.map((a) => ({
|
|
880
938
|
target: a.target,
|
|
@@ -884,13 +942,12 @@ var SmartAgentKitClient = class {
|
|
|
884
942
|
this.sessions.set(wallet.address, walletSessions);
|
|
885
943
|
return {
|
|
886
944
|
sessionKey: sessionAccount.address,
|
|
887
|
-
privateKey: sessionPrivateKey,
|
|
888
945
|
permissionId
|
|
889
946
|
};
|
|
890
947
|
} catch (error) {
|
|
891
948
|
if (error instanceof SessionError) throw error;
|
|
892
949
|
throw new SessionError(
|
|
893
|
-
|
|
950
|
+
"Session creation failed. Check that the wallet is deployed and the owner key is correct."
|
|
894
951
|
);
|
|
895
952
|
}
|
|
896
953
|
}
|
|
@@ -911,7 +968,7 @@ var SmartAgentKitClient = class {
|
|
|
911
968
|
);
|
|
912
969
|
} catch (error) {
|
|
913
970
|
throw new SessionError(
|
|
914
|
-
|
|
971
|
+
"Session revocation failed. Check the permission ID and wallet connection."
|
|
915
972
|
);
|
|
916
973
|
}
|
|
917
974
|
}
|
|
@@ -935,6 +992,7 @@ var SmartAgentKitClient = class {
|
|
|
935
992
|
* Hooks (spending limits, allowlist, pause) are enforced on-chain.
|
|
936
993
|
*/
|
|
937
994
|
async execute(wallet, params) {
|
|
995
|
+
this.validateTransaction(params, wallet.address);
|
|
938
996
|
const client = this.getWalletClient(wallet.address);
|
|
939
997
|
try {
|
|
940
998
|
const hash = await client.sendTransaction({
|
|
@@ -948,8 +1006,9 @@ var SmartAgentKitClient = class {
|
|
|
948
1006
|
});
|
|
949
1007
|
return hash;
|
|
950
1008
|
} catch (error) {
|
|
1009
|
+
if (error instanceof ExecutionError) throw error;
|
|
951
1010
|
throw new ExecutionError(
|
|
952
|
-
|
|
1011
|
+
"Transaction failed. Check that the target, value, and calldata are correct.",
|
|
953
1012
|
error
|
|
954
1013
|
);
|
|
955
1014
|
}
|
|
@@ -959,6 +1018,9 @@ var SmartAgentKitClient = class {
|
|
|
959
1018
|
* All calls are encoded into a single UserOperation with batch mode.
|
|
960
1019
|
*/
|
|
961
1020
|
async executeBatch(wallet, params) {
|
|
1021
|
+
for (const call of params.calls) {
|
|
1022
|
+
this.validateTransaction(call, wallet.address);
|
|
1023
|
+
}
|
|
962
1024
|
const client = this.getWalletClient(wallet.address);
|
|
963
1025
|
try {
|
|
964
1026
|
const calls = params.calls.map((call) => ({
|
|
@@ -971,8 +1033,9 @@ var SmartAgentKitClient = class {
|
|
|
971
1033
|
});
|
|
972
1034
|
return hash;
|
|
973
1035
|
} catch (error) {
|
|
1036
|
+
if (error instanceof ExecutionError) throw error;
|
|
974
1037
|
throw new ExecutionError(
|
|
975
|
-
|
|
1038
|
+
"Batch transaction failed. Check that all targets, values, and calldata are correct.",
|
|
976
1039
|
error
|
|
977
1040
|
);
|
|
978
1041
|
}
|
|
@@ -1075,10 +1138,58 @@ var SmartAgentKitClient = class {
|
|
|
1075
1138
|
}
|
|
1076
1139
|
// ─── Private Helpers ──────────────────────────────────────────
|
|
1077
1140
|
resolvePolicies(params) {
|
|
1141
|
+
let policies;
|
|
1078
1142
|
if (params.preset) {
|
|
1079
|
-
|
|
1143
|
+
policies = PRESETS[params.preset](params.owner, params.presetParams);
|
|
1144
|
+
} else {
|
|
1145
|
+
policies = params.policies ?? [];
|
|
1080
1146
|
}
|
|
1081
|
-
|
|
1147
|
+
if (policies.length > 0 && this.config.moduleAddresses) {
|
|
1148
|
+
const moduleAddresses = this.config.moduleAddresses;
|
|
1149
|
+
const infrastructureAddresses = [];
|
|
1150
|
+
if (moduleAddresses.spendingLimitHook) {
|
|
1151
|
+
infrastructureAddresses.push(moduleAddresses.spendingLimitHook);
|
|
1152
|
+
}
|
|
1153
|
+
if (moduleAddresses.allowlistHook) {
|
|
1154
|
+
infrastructureAddresses.push(moduleAddresses.allowlistHook);
|
|
1155
|
+
}
|
|
1156
|
+
if (moduleAddresses.emergencyPauseHook) {
|
|
1157
|
+
infrastructureAddresses.push(moduleAddresses.emergencyPauseHook);
|
|
1158
|
+
}
|
|
1159
|
+
if (moduleAddresses.automationExecutor) {
|
|
1160
|
+
infrastructureAddresses.push(moduleAddresses.automationExecutor);
|
|
1161
|
+
}
|
|
1162
|
+
infrastructureAddresses.push(HOOK_MULTIPLEXER_ADDRESS);
|
|
1163
|
+
infrastructureAddresses.push(SMART_SESSIONS_VALIDATOR);
|
|
1164
|
+
let hasAllowlist = false;
|
|
1165
|
+
for (const policy of policies) {
|
|
1166
|
+
if (policy.type === "allowlist") {
|
|
1167
|
+
hasAllowlist = true;
|
|
1168
|
+
const existing = new Set(
|
|
1169
|
+
(policy.protectedAddresses ?? []).map((a) => a.toLowerCase())
|
|
1170
|
+
);
|
|
1171
|
+
const merged = [...policy.protectedAddresses ?? []];
|
|
1172
|
+
for (const addr of infrastructureAddresses) {
|
|
1173
|
+
if (!existing.has(addr.toLowerCase())) {
|
|
1174
|
+
merged.push(addr);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
policy.protectedAddresses = merged;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
const hasHooks = policies.some(
|
|
1181
|
+
(p) => p.type === "spending-limit" || p.type === "emergency-pause"
|
|
1182
|
+
);
|
|
1183
|
+
if (hasHooks && !hasAllowlist) {
|
|
1184
|
+
policies.push({
|
|
1185
|
+
type: "allowlist",
|
|
1186
|
+
mode: "block",
|
|
1187
|
+
targets: [],
|
|
1188
|
+
protectedAddresses: infrastructureAddresses
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
return policies;
|
|
1082
1193
|
}
|
|
1083
1194
|
requireModuleAddresses(policies) {
|
|
1084
1195
|
if (policies.length === 0) return void 0;
|
|
@@ -1136,7 +1247,7 @@ var SmartAgentKitClient = class {
|
|
|
1136
1247
|
switch (policy.type) {
|
|
1137
1248
|
case "spending-limit": {
|
|
1138
1249
|
const hookAddress = moduleAddresses.spendingLimitHook;
|
|
1139
|
-
const initData = encodeSpendingLimitInitData(policy);
|
|
1250
|
+
const initData = encodeSpendingLimitInitData(policy, hookMultiPlexerAddress);
|
|
1140
1251
|
this.pushSubHookInitCalls(
|
|
1141
1252
|
calls,
|
|
1142
1253
|
hookAddress,
|
|
@@ -1147,7 +1258,7 @@ var SmartAgentKitClient = class {
|
|
|
1147
1258
|
}
|
|
1148
1259
|
case "allowlist": {
|
|
1149
1260
|
const hookAddress = moduleAddresses.allowlistHook;
|
|
1150
|
-
const initData = encodeAllowlistInitData(policy);
|
|
1261
|
+
const initData = encodeAllowlistInitData(policy, hookMultiPlexerAddress);
|
|
1151
1262
|
this.pushSubHookInitCalls(
|
|
1152
1263
|
calls,
|
|
1153
1264
|
hookAddress,
|
|
@@ -1158,7 +1269,7 @@ var SmartAgentKitClient = class {
|
|
|
1158
1269
|
}
|
|
1159
1270
|
case "emergency-pause": {
|
|
1160
1271
|
const hookAddress = moduleAddresses.emergencyPauseHook;
|
|
1161
|
-
const initData = encodeEmergencyPauseInitData(policy);
|
|
1272
|
+
const initData = encodeEmergencyPauseInitData(policy, hookMultiPlexerAddress);
|
|
1162
1273
|
this.pushSubHookInitCalls(
|
|
1163
1274
|
calls,
|
|
1164
1275
|
hookAddress,
|
|
@@ -1177,10 +1288,13 @@ var SmartAgentKitClient = class {
|
|
|
1177
1288
|
});
|
|
1178
1289
|
}
|
|
1179
1290
|
/**
|
|
1180
|
-
* Push the
|
|
1181
|
-
* 1. onInstall(initData) on the sub-hook
|
|
1182
|
-
* 2.
|
|
1183
|
-
*
|
|
1291
|
+
* Push the 2 calls needed to initialize a sub-hook:
|
|
1292
|
+
* 1. onInstall(initData) on the sub-hook — sets trusted forwarder from init data
|
|
1293
|
+
* 2. addHook(hookAddr, GLOBAL) on the HookMultiPlexer
|
|
1294
|
+
*
|
|
1295
|
+
* Note: The trusted forwarder is now set during onInstall via the encoded init data
|
|
1296
|
+
* (passed as the first parameter). A separate setTrustedForwarder call is no longer
|
|
1297
|
+
* needed, reducing gas cost and batch size.
|
|
1184
1298
|
*/
|
|
1185
1299
|
pushSubHookInitCalls(calls, hookAddress, initData, hookMultiPlexerAddress) {
|
|
1186
1300
|
calls.push({
|
|
@@ -1192,15 +1306,6 @@ var SmartAgentKitClient = class {
|
|
|
1192
1306
|
args: [initData]
|
|
1193
1307
|
})
|
|
1194
1308
|
});
|
|
1195
|
-
calls.push({
|
|
1196
|
-
to: hookAddress,
|
|
1197
|
-
value: 0n,
|
|
1198
|
-
data: encodeFunctionData({
|
|
1199
|
-
abi: SET_TRUSTED_FORWARDER_ABI,
|
|
1200
|
-
functionName: "setTrustedForwarder",
|
|
1201
|
-
args: [hookMultiPlexerAddress]
|
|
1202
|
-
})
|
|
1203
|
-
});
|
|
1204
1309
|
calls.push({
|
|
1205
1310
|
to: hookMultiPlexerAddress,
|
|
1206
1311
|
value: 0n,
|
|
@@ -1255,6 +1360,69 @@ var SmartAgentKitClient = class {
|
|
|
1255
1360
|
}
|
|
1256
1361
|
});
|
|
1257
1362
|
}
|
|
1363
|
+
/**
|
|
1364
|
+
* Collect all known infrastructure addresses that must never be
|
|
1365
|
+
* targeted by agent-initiated transactions. This prevents an AI agent
|
|
1366
|
+
* from calling hook admin functions (setGuardian, clearTrustedForwarder,
|
|
1367
|
+
* removeSpendingLimit, removeHook, etc.) to weaken its own policy constraints.
|
|
1368
|
+
*/
|
|
1369
|
+
getProtectedAddresses() {
|
|
1370
|
+
const addresses = /* @__PURE__ */ new Set();
|
|
1371
|
+
addresses.add(ENTRYPOINT_V07.toLowerCase());
|
|
1372
|
+
addresses.add(HOOK_MULTIPLEXER_ADDRESS.toLowerCase());
|
|
1373
|
+
addresses.add(SAFE_7579_MODULE.toLowerCase());
|
|
1374
|
+
addresses.add(SAFE_7579_LAUNCHPAD.toLowerCase());
|
|
1375
|
+
addresses.add(SMART_SESSIONS_VALIDATOR.toLowerCase());
|
|
1376
|
+
const moduleAddresses = this.config.moduleAddresses;
|
|
1377
|
+
if (moduleAddresses) {
|
|
1378
|
+
if (moduleAddresses.spendingLimitHook) {
|
|
1379
|
+
addresses.add(moduleAddresses.spendingLimitHook.toLowerCase());
|
|
1380
|
+
}
|
|
1381
|
+
if (moduleAddresses.allowlistHook) {
|
|
1382
|
+
addresses.add(moduleAddresses.allowlistHook.toLowerCase());
|
|
1383
|
+
}
|
|
1384
|
+
if (moduleAddresses.emergencyPauseHook) {
|
|
1385
|
+
addresses.add(moduleAddresses.emergencyPauseHook.toLowerCase());
|
|
1386
|
+
}
|
|
1387
|
+
if (moduleAddresses.automationExecutor) {
|
|
1388
|
+
addresses.add(moduleAddresses.automationExecutor.toLowerCase());
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
return addresses;
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Validate a transaction before submission. Blocks calls to infrastructure
|
|
1395
|
+
* addresses and validates input parameters.
|
|
1396
|
+
*
|
|
1397
|
+
* @throws ExecutionError if the transaction targets a protected address
|
|
1398
|
+
* or has invalid parameters.
|
|
1399
|
+
*/
|
|
1400
|
+
validateTransaction(params, walletAddress) {
|
|
1401
|
+
if (!isAddress2(params.target)) {
|
|
1402
|
+
throw new ExecutionError(
|
|
1403
|
+
`Invalid target address: "${params.target}". Expected a 0x-prefixed 20-byte hex address.`
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
const protectedAddresses = this.getProtectedAddresses();
|
|
1407
|
+
if (protectedAddresses.has(params.target.toLowerCase())) {
|
|
1408
|
+
throw new ExecutionError(
|
|
1409
|
+
`Transaction blocked: target ${params.target} is a protected infrastructure contract. Agent wallets cannot call hook, multiplexer, or EntryPoint contracts directly.`
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1412
|
+
if (walletAddress && params.target.toLowerCase() === walletAddress.toLowerCase()) {
|
|
1413
|
+
throw new ExecutionError(
|
|
1414
|
+
`Transaction blocked: target ${params.target} is the wallet's own address. Self-calls could be used to uninstall security modules.`
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
if (params.value !== void 0 && params.value < 0n) {
|
|
1418
|
+
throw new ExecutionError("Transaction value cannot be negative.");
|
|
1419
|
+
}
|
|
1420
|
+
if (params.data && params.data !== "0x" && !isHex(params.data)) {
|
|
1421
|
+
throw new ExecutionError(
|
|
1422
|
+
`Invalid calldata: "${params.data}". Expected a 0x-prefixed hex string.`
|
|
1423
|
+
);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1258
1426
|
getWalletClient(walletAddress) {
|
|
1259
1427
|
const client = this.walletClients.get(walletAddress);
|
|
1260
1428
|
if (!client) {
|
|
@@ -1309,4 +1477,3 @@ export {
|
|
|
1309
1477
|
getRemoveAction as getRemoveSessionAction,
|
|
1310
1478
|
getSmartSessionsModule
|
|
1311
1479
|
};
|
|
1312
|
-
//# sourceMappingURL=index.mjs.map
|