@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.js CHANGED
@@ -86,6 +86,7 @@ var ENTRYPOINT_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
86
86
  var SAFE_7579_MODULE = "0x7579EE8307284F293B1927136486880611F20002";
87
87
  var SAFE_7579_LAUNCHPAD = "0x7579011aB74c46090561ea277Ba79D510c6C00ff";
88
88
  var RHINESTONE_ATTESTER = "0x000000333034E9f539ce08819E12c1b8Cb29084d";
89
+ var SMART_SESSIONS_VALIDATOR = "0x00000000002B0eCfbD0496EE71e01257dA0E37DE";
89
90
  var ATTESTERS_THRESHOLD = 1;
90
91
  var WINDOW_1_HOUR = 3600;
91
92
  var WINDOW_1_DAY = 86400;
@@ -223,15 +224,6 @@ var MODULE_ONINSTALL_ABI = [
223
224
  stateMutability: "nonpayable"
224
225
  }
225
226
  ];
226
- var SET_TRUSTED_FORWARDER_ABI = [
227
- {
228
- name: "setTrustedForwarder",
229
- type: "function",
230
- inputs: [{ name: "forwarder", type: "address" }],
231
- outputs: [],
232
- stateMutability: "nonpayable"
233
- }
234
- ];
235
227
  var HOOK_MULTIPLEXER_ABI = [
236
228
  {
237
229
  name: "addHook",
@@ -258,119 +250,6 @@ var MODULE_ADDRESSES = {
258
250
  // Will be populated after deployment
259
251
  };
260
252
 
261
- // src/presets.ts
262
- var PRESETS = {
263
- /**
264
- * DeFi Trader preset:
265
- * - Daily spending limit on ETH and stablecoins
266
- * - Allowlist of approved DEX contracts
267
- * - Emergency pause with owner as guardian
268
- */
269
- "defi-trader": (owner, params = {}) => [
270
- {
271
- type: "spending-limit",
272
- limits: [
273
- {
274
- token: NATIVE_TOKEN,
275
- limit: params.dailyEthLimit ?? (0, import_viem.parseEther)("1"),
276
- window: WINDOW_1_DAY
277
- },
278
- ...params.stablecoinLimits ?? []
279
- ]
280
- },
281
- // Only include allowlist if specific DEXes are provided;
282
- // an empty allowlist in "allow" mode would block all transactions.
283
- ...params.allowedDexes?.length ? [
284
- {
285
- type: "allowlist",
286
- mode: "allow",
287
- targets: params.allowedDexes.map((addr) => ({
288
- address: addr,
289
- selector: "0x00000000"
290
- }))
291
- }
292
- ] : [],
293
- {
294
- type: "emergency-pause",
295
- guardian: params.guardian ?? owner,
296
- autoUnpauseAfter: WINDOW_1_DAY
297
- }
298
- ],
299
- /**
300
- * Treasury Agent preset:
301
- * - Lower spending limits with longer windows
302
- * - Emergency pause (manual only)
303
- */
304
- "treasury-agent": (owner, params = {}) => [
305
- {
306
- type: "spending-limit",
307
- limits: [
308
- {
309
- token: NATIVE_TOKEN,
310
- limit: params.weeklyEthLimit ?? (0, import_viem.parseEther)("5"),
311
- window: WINDOW_1_WEEK
312
- }
313
- ]
314
- },
315
- {
316
- type: "emergency-pause",
317
- guardian: params.guardian ?? owner,
318
- autoUnpauseAfter: 0
319
- }
320
- ],
321
- /**
322
- * Payment Agent preset:
323
- * - Strict spending limits
324
- * - Allowlist of approved recipients only
325
- * - Emergency pause
326
- */
327
- "payment-agent": (owner, params = {}) => [
328
- {
329
- type: "spending-limit",
330
- limits: [
331
- {
332
- token: NATIVE_TOKEN,
333
- limit: params.dailyLimit ?? (0, import_viem.parseEther)("0.1"),
334
- window: WINDOW_1_DAY
335
- }
336
- ]
337
- },
338
- // Only include allowlist if specific recipients are provided;
339
- // an empty allowlist in "allow" mode would block all transactions.
340
- ...params.approvedRecipients?.length ? [
341
- {
342
- type: "allowlist",
343
- mode: "allow",
344
- targets: params.approvedRecipients.map(
345
- (addr) => ({
346
- address: addr
347
- })
348
- )
349
- }
350
- ] : [],
351
- {
352
- type: "emergency-pause",
353
- guardian: params.guardian ?? owner,
354
- autoUnpauseAfter: 3600
355
- }
356
- ],
357
- /**
358
- * Minimal preset:
359
- * - Just emergency pause
360
- * - For agents that need maximum flexibility with a kill switch
361
- */
362
- minimal: (owner, params = {}) => [
363
- {
364
- type: "emergency-pause",
365
- guardian: params.guardian ?? owner,
366
- autoUnpauseAfter: 0
367
- }
368
- ]
369
- };
370
-
371
- // src/policies.ts
372
- var import_viem2 = require("viem");
373
-
374
253
  // src/errors.ts
375
254
  var SmartAgentKitError = class extends Error {
376
255
  constructor(message, options) {
@@ -421,7 +300,174 @@ var SessionError = class extends SmartAgentKitError {
421
300
  }
422
301
  };
423
302
 
303
+ // src/presets.ts
304
+ function validatePresetParams(presetName, params, spec) {
305
+ for (const [key, expectedType] of Object.entries(spec)) {
306
+ if (params[key] === void 0) continue;
307
+ const value = params[key];
308
+ switch (expectedType) {
309
+ case "bigint":
310
+ if (typeof value !== "bigint") {
311
+ throw new PolicyConfigError(
312
+ `Preset "${presetName}": parameter "${key}" must be a bigint, got ${typeof value}`
313
+ );
314
+ }
315
+ break;
316
+ case "Address":
317
+ if (typeof value !== "string" || !(0, import_viem.isAddress)(value)) {
318
+ throw new PolicyConfigError(
319
+ `Preset "${presetName}": parameter "${key}" must be a valid Ethereum address`
320
+ );
321
+ }
322
+ break;
323
+ case "Address[]":
324
+ if (!Array.isArray(value) || !value.every((v) => typeof v === "string" && (0, import_viem.isAddress)(v))) {
325
+ throw new PolicyConfigError(
326
+ `Preset "${presetName}": parameter "${key}" must be an array of valid Ethereum addresses`
327
+ );
328
+ }
329
+ break;
330
+ }
331
+ }
332
+ }
333
+ var PRESETS = {
334
+ /**
335
+ * DeFi Trader preset:
336
+ * - Daily spending limit on ETH and stablecoins
337
+ * - Allowlist of approved DEX contracts
338
+ * - Emergency pause with owner as guardian
339
+ */
340
+ "defi-trader": (owner, params = {}) => {
341
+ validatePresetParams("defi-trader", params, {
342
+ dailyEthLimit: "bigint",
343
+ guardian: "Address",
344
+ allowedDexes: "Address[]"
345
+ });
346
+ return [
347
+ {
348
+ type: "spending-limit",
349
+ limits: [
350
+ {
351
+ token: NATIVE_TOKEN,
352
+ limit: params.dailyEthLimit ?? (0, import_viem.parseEther)("1"),
353
+ window: WINDOW_1_DAY
354
+ },
355
+ ...params.stablecoinLimits ?? []
356
+ ]
357
+ },
358
+ // Only include allowlist if specific DEXes are provided;
359
+ // an empty allowlist in "allow" mode would block all transactions.
360
+ ...params.allowedDexes?.length ? [
361
+ {
362
+ type: "allowlist",
363
+ mode: "allow",
364
+ targets: params.allowedDexes.map((addr) => ({
365
+ address: addr
366
+ // Omit selector to use the wildcard (0x431e2cf5) — allows all
367
+ // function calls, not just ETH transfers. 0x00000000 is NOT a
368
+ // wildcard; it only matches empty calldata.
369
+ }))
370
+ }
371
+ ] : [],
372
+ {
373
+ type: "emergency-pause",
374
+ guardian: params.guardian ?? owner,
375
+ autoUnpauseAfter: WINDOW_1_DAY
376
+ }
377
+ ];
378
+ },
379
+ /**
380
+ * Treasury Agent preset:
381
+ * - Lower spending limits with longer windows
382
+ * - Emergency pause (manual only)
383
+ */
384
+ "treasury-agent": (owner, params = {}) => {
385
+ validatePresetParams("treasury-agent", params, {
386
+ weeklyEthLimit: "bigint",
387
+ guardian: "Address"
388
+ });
389
+ return [
390
+ {
391
+ type: "spending-limit",
392
+ limits: [
393
+ {
394
+ token: NATIVE_TOKEN,
395
+ limit: params.weeklyEthLimit ?? (0, import_viem.parseEther)("5"),
396
+ window: WINDOW_1_WEEK
397
+ }
398
+ ]
399
+ },
400
+ {
401
+ type: "emergency-pause",
402
+ guardian: params.guardian ?? owner,
403
+ autoUnpauseAfter: 0
404
+ }
405
+ ];
406
+ },
407
+ /**
408
+ * Payment Agent preset:
409
+ * - Strict spending limits
410
+ * - Allowlist of approved recipients only
411
+ * - Emergency pause
412
+ */
413
+ "payment-agent": (owner, params = {}) => {
414
+ validatePresetParams("payment-agent", params, {
415
+ dailyLimit: "bigint",
416
+ guardian: "Address",
417
+ approvedRecipients: "Address[]"
418
+ });
419
+ return [
420
+ {
421
+ type: "spending-limit",
422
+ limits: [
423
+ {
424
+ token: NATIVE_TOKEN,
425
+ limit: params.dailyLimit ?? (0, import_viem.parseEther)("0.1"),
426
+ window: WINDOW_1_DAY
427
+ }
428
+ ]
429
+ },
430
+ // Only include allowlist if specific recipients are provided;
431
+ // an empty allowlist in "allow" mode would block all transactions.
432
+ ...params.approvedRecipients?.length ? [
433
+ {
434
+ type: "allowlist",
435
+ mode: "allow",
436
+ targets: params.approvedRecipients.map(
437
+ (addr) => ({
438
+ address: addr
439
+ })
440
+ )
441
+ }
442
+ ] : [],
443
+ {
444
+ type: "emergency-pause",
445
+ guardian: params.guardian ?? owner,
446
+ autoUnpauseAfter: 3600
447
+ }
448
+ ];
449
+ },
450
+ /**
451
+ * Minimal preset:
452
+ * - Just emergency pause
453
+ * - For agents that need maximum flexibility with a kill switch
454
+ */
455
+ minimal: (owner, params = {}) => {
456
+ validatePresetParams("minimal", params, {
457
+ guardian: "Address"
458
+ });
459
+ return [
460
+ {
461
+ type: "emergency-pause",
462
+ guardian: params.guardian ?? owner,
463
+ autoUnpauseAfter: 0
464
+ }
465
+ ];
466
+ }
467
+ };
468
+
424
469
  // src/policies.ts
470
+ var import_viem2 = require("viem");
425
471
  function encodePolicyInitData(policy, moduleAddresses, trustedForwarder = "0x0000000000000000000000000000000000000000") {
426
472
  const zeroAddress = "0x0000000000000000000000000000000000000000";
427
473
  switch (policy.type) {
@@ -536,11 +582,11 @@ var base_sepolia_default = {
536
582
  safe7579Launchpad: "0x7579011aB74c46090561ea277Ba79D510c6C00ff",
537
583
  rhinestoneAttester: "0x000000333034E9f539ce08819E12c1b8Cb29084d",
538
584
  hookMultiPlexer: "0xF6782ed057F95f334D04F0Af1Af4D14fb84DE549",
539
- spendingLimitHook: "0x0ea97ef2fc52700d1628110a8f411fefb0c0aa8b",
540
- allowlistHook: "0x61a2100072d03f66de6f7dd0dfc2f7aa5c91e777",
541
- emergencyPauseHook: "0xb8fdc9ee56cfb4077e132eff631b546fe6e79fec",
542
- automationExecutor: "0x729c29b35c396b907ed118f00fbe4d4bcc3a7f46",
543
- moduleSetupHelper: "0x4f1555baf4b3221c373094d47419596118828e41"
585
+ spendingLimitHook: "0xd67a5E6784A66Ddf4C09EA7bbf81Ab89532624E4",
586
+ allowlistHook: "0x7899b03386A3874393A3769D637977d947A9Fc66",
587
+ emergencyPauseHook: "0xAc0cE5672aED1Bfe5549b885f883a770Acd8cAE3",
588
+ automationExecutor: "0x795DB663b70bAe110C10694DF3f5D801b76E2b20",
589
+ moduleSetupHelper: "0xcBb12Eb2CF324B1C34160F72E037589CEEC35Fa0"
544
590
  };
545
591
 
546
592
  // src/deployments/sepolia.json
@@ -701,6 +747,11 @@ function getRemoveAction(permissionId) {
701
747
  // src/client.ts
702
748
  function resolveAccount(key) {
703
749
  if (typeof key === "string") {
750
+ if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
751
+ throw new WalletCreationError(
752
+ "Invalid private key format. Expected a 0x-prefixed 32-byte hex string."
753
+ );
754
+ }
704
755
  return (0, import_accounts.privateKeyToAccount)(key);
705
756
  }
706
757
  return (0, import_accounts.mnemonicToAccount)(key.mnemonic, {
@@ -751,7 +802,7 @@ var SmartAgentKitClient = class {
751
802
  const ownerAccount = resolveAccount(ownerKey);
752
803
  if (ownerAccount.address.toLowerCase() !== params.owner.toLowerCase()) {
753
804
  throw new WalletCreationError(
754
- `Owner address mismatch: key derives ${ownerAccount.address} but params.owner is ${params.owner}`
805
+ "Owner address does not match the provided signing key. Verify that the private key or mnemonic corresponds to the specified owner address."
755
806
  );
756
807
  }
757
808
  const hookModule = (0, import_module_sdk3.getHookMultiPlexer)({
@@ -808,7 +859,7 @@ var SmartAgentKitClient = class {
808
859
  } catch (error) {
809
860
  if (error instanceof WalletCreationError) throw error;
810
861
  throw new WalletCreationError(
811
- error instanceof Error ? error.message : String(error),
862
+ "Wallet deployment failed. Check your RPC/bundler configuration and that the owner key is correct.",
812
863
  error
813
864
  );
814
865
  }
@@ -862,7 +913,13 @@ var SmartAgentKitClient = class {
862
913
  * the smart account via Smart Sessions. The session is scoped to
863
914
  * specific target contracts, function selectors, and time window.
864
915
  *
865
- * @returns The session key address, private key, and permission ID.
916
+ * @returns The session key address and permission ID.
917
+ *
918
+ * SECURITY: The session private key is intentionally NOT returned or stored
919
+ * by the SDK. The caller should use the `sessionKey` address to identify
920
+ * the session on-chain, and manage key material externally via a secure
921
+ * key management system. To use a pre-generated key pair, provide the
922
+ * session key address in `params.sessionKey`.
866
923
  */
867
924
  async createSession(wallet, params, ownerKey) {
868
925
  const client = this.getWalletClient(wallet.address);
@@ -915,7 +972,6 @@ var SmartAgentKitClient = class {
915
972
  walletSessions.push({
916
973
  permissionId,
917
974
  sessionKeyAddress: sessionAccount.address,
918
- sessionKeyPrivateKey: sessionPrivateKey,
919
975
  expiresAt: params.expiresAt,
920
976
  actions: params.actions.map((a) => ({
921
977
  target: a.target,
@@ -925,13 +981,12 @@ var SmartAgentKitClient = class {
925
981
  this.sessions.set(wallet.address, walletSessions);
926
982
  return {
927
983
  sessionKey: sessionAccount.address,
928
- privateKey: sessionPrivateKey,
929
984
  permissionId
930
985
  };
931
986
  } catch (error) {
932
987
  if (error instanceof SessionError) throw error;
933
988
  throw new SessionError(
934
- error instanceof Error ? error.message : String(error)
989
+ "Session creation failed. Check that the wallet is deployed and the owner key is correct."
935
990
  );
936
991
  }
937
992
  }
@@ -952,7 +1007,7 @@ var SmartAgentKitClient = class {
952
1007
  );
953
1008
  } catch (error) {
954
1009
  throw new SessionError(
955
- error instanceof Error ? error.message : String(error)
1010
+ "Session revocation failed. Check the permission ID and wallet connection."
956
1011
  );
957
1012
  }
958
1013
  }
@@ -976,6 +1031,7 @@ var SmartAgentKitClient = class {
976
1031
  * Hooks (spending limits, allowlist, pause) are enforced on-chain.
977
1032
  */
978
1033
  async execute(wallet, params) {
1034
+ this.validateTransaction(params, wallet.address);
979
1035
  const client = this.getWalletClient(wallet.address);
980
1036
  try {
981
1037
  const hash = await client.sendTransaction({
@@ -989,8 +1045,9 @@ var SmartAgentKitClient = class {
989
1045
  });
990
1046
  return hash;
991
1047
  } catch (error) {
1048
+ if (error instanceof ExecutionError) throw error;
992
1049
  throw new ExecutionError(
993
- error instanceof Error ? error.message : String(error),
1050
+ "Transaction failed. Check that the target, value, and calldata are correct.",
994
1051
  error
995
1052
  );
996
1053
  }
@@ -1000,6 +1057,9 @@ var SmartAgentKitClient = class {
1000
1057
  * All calls are encoded into a single UserOperation with batch mode.
1001
1058
  */
1002
1059
  async executeBatch(wallet, params) {
1060
+ for (const call of params.calls) {
1061
+ this.validateTransaction(call, wallet.address);
1062
+ }
1003
1063
  const client = this.getWalletClient(wallet.address);
1004
1064
  try {
1005
1065
  const calls = params.calls.map((call) => ({
@@ -1012,8 +1072,9 @@ var SmartAgentKitClient = class {
1012
1072
  });
1013
1073
  return hash;
1014
1074
  } catch (error) {
1075
+ if (error instanceof ExecutionError) throw error;
1015
1076
  throw new ExecutionError(
1016
- error instanceof Error ? error.message : String(error),
1077
+ "Batch transaction failed. Check that all targets, values, and calldata are correct.",
1017
1078
  error
1018
1079
  );
1019
1080
  }
@@ -1116,10 +1177,58 @@ var SmartAgentKitClient = class {
1116
1177
  }
1117
1178
  // ─── Private Helpers ──────────────────────────────────────────
1118
1179
  resolvePolicies(params) {
1180
+ let policies;
1119
1181
  if (params.preset) {
1120
- return PRESETS[params.preset](params.owner, params.presetParams);
1182
+ policies = PRESETS[params.preset](params.owner, params.presetParams);
1183
+ } else {
1184
+ policies = params.policies ?? [];
1121
1185
  }
1122
- return params.policies ?? [];
1186
+ if (policies.length > 0 && this.config.moduleAddresses) {
1187
+ const moduleAddresses = this.config.moduleAddresses;
1188
+ const infrastructureAddresses = [];
1189
+ if (moduleAddresses.spendingLimitHook) {
1190
+ infrastructureAddresses.push(moduleAddresses.spendingLimitHook);
1191
+ }
1192
+ if (moduleAddresses.allowlistHook) {
1193
+ infrastructureAddresses.push(moduleAddresses.allowlistHook);
1194
+ }
1195
+ if (moduleAddresses.emergencyPauseHook) {
1196
+ infrastructureAddresses.push(moduleAddresses.emergencyPauseHook);
1197
+ }
1198
+ if (moduleAddresses.automationExecutor) {
1199
+ infrastructureAddresses.push(moduleAddresses.automationExecutor);
1200
+ }
1201
+ infrastructureAddresses.push(HOOK_MULTIPLEXER_ADDRESS);
1202
+ infrastructureAddresses.push(SMART_SESSIONS_VALIDATOR);
1203
+ let hasAllowlist = false;
1204
+ for (const policy of policies) {
1205
+ if (policy.type === "allowlist") {
1206
+ hasAllowlist = true;
1207
+ const existing = new Set(
1208
+ (policy.protectedAddresses ?? []).map((a) => a.toLowerCase())
1209
+ );
1210
+ const merged = [...policy.protectedAddresses ?? []];
1211
+ for (const addr of infrastructureAddresses) {
1212
+ if (!existing.has(addr.toLowerCase())) {
1213
+ merged.push(addr);
1214
+ }
1215
+ }
1216
+ policy.protectedAddresses = merged;
1217
+ }
1218
+ }
1219
+ const hasHooks = policies.some(
1220
+ (p) => p.type === "spending-limit" || p.type === "emergency-pause"
1221
+ );
1222
+ if (hasHooks && !hasAllowlist) {
1223
+ policies.push({
1224
+ type: "allowlist",
1225
+ mode: "block",
1226
+ targets: [],
1227
+ protectedAddresses: infrastructureAddresses
1228
+ });
1229
+ }
1230
+ }
1231
+ return policies;
1123
1232
  }
1124
1233
  requireModuleAddresses(policies) {
1125
1234
  if (policies.length === 0) return void 0;
@@ -1177,7 +1286,7 @@ var SmartAgentKitClient = class {
1177
1286
  switch (policy.type) {
1178
1287
  case "spending-limit": {
1179
1288
  const hookAddress = moduleAddresses.spendingLimitHook;
1180
- const initData = encodeSpendingLimitInitData(policy);
1289
+ const initData = encodeSpendingLimitInitData(policy, hookMultiPlexerAddress);
1181
1290
  this.pushSubHookInitCalls(
1182
1291
  calls,
1183
1292
  hookAddress,
@@ -1188,7 +1297,7 @@ var SmartAgentKitClient = class {
1188
1297
  }
1189
1298
  case "allowlist": {
1190
1299
  const hookAddress = moduleAddresses.allowlistHook;
1191
- const initData = encodeAllowlistInitData(policy);
1300
+ const initData = encodeAllowlistInitData(policy, hookMultiPlexerAddress);
1192
1301
  this.pushSubHookInitCalls(
1193
1302
  calls,
1194
1303
  hookAddress,
@@ -1199,7 +1308,7 @@ var SmartAgentKitClient = class {
1199
1308
  }
1200
1309
  case "emergency-pause": {
1201
1310
  const hookAddress = moduleAddresses.emergencyPauseHook;
1202
- const initData = encodeEmergencyPauseInitData(policy);
1311
+ const initData = encodeEmergencyPauseInitData(policy, hookMultiPlexerAddress);
1203
1312
  this.pushSubHookInitCalls(
1204
1313
  calls,
1205
1314
  hookAddress,
@@ -1218,10 +1327,13 @@ var SmartAgentKitClient = class {
1218
1327
  });
1219
1328
  }
1220
1329
  /**
1221
- * Push the 3 calls needed to initialize a sub-hook:
1222
- * 1. onInstall(initData) on the sub-hook
1223
- * 2. setTrustedForwarder(multiplexer) on the sub-hook
1224
- * 3. addHook(hookAddr, GLOBAL) on the HookMultiPlexer
1330
+ * Push the 2 calls needed to initialize a sub-hook:
1331
+ * 1. onInstall(initData) on the sub-hook — sets trusted forwarder from init data
1332
+ * 2. addHook(hookAddr, GLOBAL) on the HookMultiPlexer
1333
+ *
1334
+ * Note: The trusted forwarder is now set during onInstall via the encoded init data
1335
+ * (passed as the first parameter). A separate setTrustedForwarder call is no longer
1336
+ * needed, reducing gas cost and batch size.
1225
1337
  */
1226
1338
  pushSubHookInitCalls(calls, hookAddress, initData, hookMultiPlexerAddress) {
1227
1339
  calls.push({
@@ -1233,15 +1345,6 @@ var SmartAgentKitClient = class {
1233
1345
  args: [initData]
1234
1346
  })
1235
1347
  });
1236
- calls.push({
1237
- to: hookAddress,
1238
- value: 0n,
1239
- data: (0, import_viem4.encodeFunctionData)({
1240
- abi: SET_TRUSTED_FORWARDER_ABI,
1241
- functionName: "setTrustedForwarder",
1242
- args: [hookMultiPlexerAddress]
1243
- })
1244
- });
1245
1348
  calls.push({
1246
1349
  to: hookMultiPlexerAddress,
1247
1350
  value: 0n,
@@ -1296,6 +1399,69 @@ var SmartAgentKitClient = class {
1296
1399
  }
1297
1400
  });
1298
1401
  }
1402
+ /**
1403
+ * Collect all known infrastructure addresses that must never be
1404
+ * targeted by agent-initiated transactions. This prevents an AI agent
1405
+ * from calling hook admin functions (setGuardian, clearTrustedForwarder,
1406
+ * removeSpendingLimit, removeHook, etc.) to weaken its own policy constraints.
1407
+ */
1408
+ getProtectedAddresses() {
1409
+ const addresses = /* @__PURE__ */ new Set();
1410
+ addresses.add(ENTRYPOINT_V07.toLowerCase());
1411
+ addresses.add(HOOK_MULTIPLEXER_ADDRESS.toLowerCase());
1412
+ addresses.add(SAFE_7579_MODULE.toLowerCase());
1413
+ addresses.add(SAFE_7579_LAUNCHPAD.toLowerCase());
1414
+ addresses.add(SMART_SESSIONS_VALIDATOR.toLowerCase());
1415
+ const moduleAddresses = this.config.moduleAddresses;
1416
+ if (moduleAddresses) {
1417
+ if (moduleAddresses.spendingLimitHook) {
1418
+ addresses.add(moduleAddresses.spendingLimitHook.toLowerCase());
1419
+ }
1420
+ if (moduleAddresses.allowlistHook) {
1421
+ addresses.add(moduleAddresses.allowlistHook.toLowerCase());
1422
+ }
1423
+ if (moduleAddresses.emergencyPauseHook) {
1424
+ addresses.add(moduleAddresses.emergencyPauseHook.toLowerCase());
1425
+ }
1426
+ if (moduleAddresses.automationExecutor) {
1427
+ addresses.add(moduleAddresses.automationExecutor.toLowerCase());
1428
+ }
1429
+ }
1430
+ return addresses;
1431
+ }
1432
+ /**
1433
+ * Validate a transaction before submission. Blocks calls to infrastructure
1434
+ * addresses and validates input parameters.
1435
+ *
1436
+ * @throws ExecutionError if the transaction targets a protected address
1437
+ * or has invalid parameters.
1438
+ */
1439
+ validateTransaction(params, walletAddress) {
1440
+ if (!(0, import_viem4.isAddress)(params.target)) {
1441
+ throw new ExecutionError(
1442
+ `Invalid target address: "${params.target}". Expected a 0x-prefixed 20-byte hex address.`
1443
+ );
1444
+ }
1445
+ const protectedAddresses = this.getProtectedAddresses();
1446
+ if (protectedAddresses.has(params.target.toLowerCase())) {
1447
+ throw new ExecutionError(
1448
+ `Transaction blocked: target ${params.target} is a protected infrastructure contract. Agent wallets cannot call hook, multiplexer, or EntryPoint contracts directly.`
1449
+ );
1450
+ }
1451
+ if (walletAddress && params.target.toLowerCase() === walletAddress.toLowerCase()) {
1452
+ throw new ExecutionError(
1453
+ `Transaction blocked: target ${params.target} is the wallet's own address. Self-calls could be used to uninstall security modules.`
1454
+ );
1455
+ }
1456
+ if (params.value !== void 0 && params.value < 0n) {
1457
+ throw new ExecutionError("Transaction value cannot be negative.");
1458
+ }
1459
+ if (params.data && params.data !== "0x" && !(0, import_viem4.isHex)(params.data)) {
1460
+ throw new ExecutionError(
1461
+ `Invalid calldata: "${params.data}". Expected a 0x-prefixed hex string.`
1462
+ );
1463
+ }
1464
+ }
1299
1465
  getWalletClient(walletAddress) {
1300
1466
  const client = this.walletClients.get(walletAddress);
1301
1467
  if (!client) {
@@ -1351,4 +1517,3 @@ var SmartAgentKitClient = class {
1351
1517
  getRemoveSessionAction,
1352
1518
  getSmartSessionsModule
1353
1519
  });
1354
- //# sourceMappingURL=index.js.map