@agirails/sdk 2.3.0 → 2.3.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.
Files changed (153) hide show
  1. package/README.md +45 -8
  2. package/dist/ACTPClient.d.ts +35 -1
  3. package/dist/ACTPClient.d.ts.map +1 -1
  4. package/dist/ACTPClient.js +156 -26
  5. package/dist/ACTPClient.js.map +1 -1
  6. package/dist/adapters/AdapterRouter.d.ts.map +1 -1
  7. package/dist/adapters/AdapterRouter.js.map +1 -1
  8. package/dist/adapters/BasicAdapter.d.ts +10 -1
  9. package/dist/adapters/BasicAdapter.d.ts.map +1 -1
  10. package/dist/adapters/BasicAdapter.js +36 -1
  11. package/dist/adapters/BasicAdapter.js.map +1 -1
  12. package/dist/cli/commands/init.d.ts +2 -1
  13. package/dist/cli/commands/init.d.ts.map +1 -1
  14. package/dist/cli/commands/init.js +345 -25
  15. package/dist/cli/commands/init.js.map +1 -1
  16. package/dist/cli/commands/publish.d.ts.map +1 -1
  17. package/dist/cli/commands/publish.js.map +1 -1
  18. package/dist/cli/commands/register.d.ts +16 -0
  19. package/dist/cli/commands/register.d.ts.map +1 -0
  20. package/dist/cli/commands/register.js +211 -0
  21. package/dist/cli/commands/register.js.map +1 -0
  22. package/dist/cli/index.js +3 -0
  23. package/dist/cli/index.js.map +1 -1
  24. package/dist/cli/utils/config.d.ts +20 -0
  25. package/dist/cli/utils/config.d.ts.map +1 -1
  26. package/dist/cli/utils/config.js.map +1 -1
  27. package/dist/config/networks.d.ts +20 -4
  28. package/dist/config/networks.d.ts.map +1 -1
  29. package/dist/config/networks.js +59 -27
  30. package/dist/config/networks.js.map +1 -1
  31. package/dist/config/publishPipeline.d.ts +14 -0
  32. package/dist/config/publishPipeline.d.ts.map +1 -1
  33. package/dist/config/publishPipeline.js +2 -1
  34. package/dist/config/publishPipeline.js.map +1 -1
  35. package/dist/erc8004/ERC8004Bridge.d.ts.map +1 -1
  36. package/dist/erc8004/ERC8004Bridge.js +6 -5
  37. package/dist/erc8004/ERC8004Bridge.js.map +1 -1
  38. package/dist/erc8004/ReputationReporter.d.ts.map +1 -1
  39. package/dist/erc8004/ReputationReporter.js +9 -12
  40. package/dist/erc8004/ReputationReporter.js.map +1 -1
  41. package/dist/index.d.ts +4 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +7 -3
  44. package/dist/index.js.map +1 -1
  45. package/dist/level1/Agent.js +4 -4
  46. package/dist/level1/Agent.js.map +1 -1
  47. package/dist/protocol/ACTPKernel.d.ts +7 -1
  48. package/dist/protocol/ACTPKernel.d.ts.map +1 -1
  49. package/dist/protocol/ACTPKernel.js +13 -10
  50. package/dist/protocol/ACTPKernel.js.map +1 -1
  51. package/dist/protocol/EventMonitor.d.ts +14 -0
  52. package/dist/protocol/EventMonitor.d.ts.map +1 -1
  53. package/dist/protocol/EventMonitor.js +14 -0
  54. package/dist/protocol/EventMonitor.js.map +1 -1
  55. package/dist/runtime/BlockchainRuntime.d.ts +5 -0
  56. package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
  57. package/dist/runtime/BlockchainRuntime.js +1 -1
  58. package/dist/runtime/BlockchainRuntime.js.map +1 -1
  59. package/dist/storage/ArchiveBundleBuilder.d.ts.map +1 -1
  60. package/dist/storage/ArchiveBundleBuilder.js.map +1 -1
  61. package/dist/storage/ArweaveClient.d.ts.map +1 -1
  62. package/dist/storage/ArweaveClient.js +2 -0
  63. package/dist/storage/ArweaveClient.js.map +1 -1
  64. package/dist/storage/FilebaseClient.d.ts.map +1 -1
  65. package/dist/storage/FilebaseClient.js +2 -0
  66. package/dist/storage/FilebaseClient.js.map +1 -1
  67. package/dist/utils/ErrorRecoveryGuide.d.ts.map +1 -1
  68. package/dist/utils/ErrorRecoveryGuide.js +3 -2
  69. package/dist/utils/ErrorRecoveryGuide.js.map +1 -1
  70. package/dist/utils/IPFSClient.d.ts +3 -2
  71. package/dist/utils/IPFSClient.d.ts.map +1 -1
  72. package/dist/utils/IPFSClient.js +7 -5
  73. package/dist/utils/IPFSClient.js.map +1 -1
  74. package/dist/utils/computeTypeHash.js +1 -3
  75. package/dist/utils/computeTypeHash.js.map +1 -1
  76. package/dist/utils/retry.d.ts.map +1 -1
  77. package/dist/utils/retry.js +0 -1
  78. package/dist/utils/retry.js.map +1 -1
  79. package/dist/utils/validation.d.ts +2 -2
  80. package/dist/utils/validation.d.ts.map +1 -1
  81. package/dist/utils/validation.js +2 -2
  82. package/dist/utils/validation.js.map +1 -1
  83. package/dist/wallet/AutoWalletProvider.d.ts +77 -0
  84. package/dist/wallet/AutoWalletProvider.d.ts.map +1 -0
  85. package/dist/wallet/AutoWalletProvider.js +197 -0
  86. package/dist/wallet/AutoWalletProvider.js.map +1 -0
  87. package/dist/wallet/EOAWalletProvider.d.ts +21 -0
  88. package/dist/wallet/EOAWalletProvider.d.ts.map +1 -0
  89. package/dist/wallet/EOAWalletProvider.js +57 -0
  90. package/dist/wallet/EOAWalletProvider.js.map +1 -0
  91. package/dist/wallet/IWalletProvider.d.ts +115 -0
  92. package/dist/wallet/IWalletProvider.d.ts.map +1 -0
  93. package/dist/wallet/IWalletProvider.js +12 -0
  94. package/dist/wallet/IWalletProvider.js.map +1 -0
  95. package/dist/wallet/aa/BundlerClient.d.ts +70 -0
  96. package/dist/wallet/aa/BundlerClient.d.ts.map +1 -0
  97. package/dist/wallet/aa/BundlerClient.js +184 -0
  98. package/dist/wallet/aa/BundlerClient.js.map +1 -0
  99. package/dist/wallet/aa/DualNonceManager.d.ts +56 -0
  100. package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -0
  101. package/dist/wallet/aa/DualNonceManager.js +142 -0
  102. package/dist/wallet/aa/DualNonceManager.js.map +1 -0
  103. package/dist/wallet/aa/PaymasterClient.d.ts +52 -0
  104. package/dist/wallet/aa/PaymasterClient.d.ts.map +1 -0
  105. package/dist/wallet/aa/PaymasterClient.js +116 -0
  106. package/dist/wallet/aa/PaymasterClient.js.map +1 -0
  107. package/dist/wallet/aa/TransactionBatcher.d.ts +87 -0
  108. package/dist/wallet/aa/TransactionBatcher.d.ts.map +1 -0
  109. package/dist/wallet/aa/TransactionBatcher.js +148 -0
  110. package/dist/wallet/aa/TransactionBatcher.js.map +1 -0
  111. package/dist/wallet/aa/UserOpBuilder.d.ts +71 -0
  112. package/dist/wallet/aa/UserOpBuilder.d.ts.map +1 -0
  113. package/dist/wallet/aa/UserOpBuilder.js +196 -0
  114. package/dist/wallet/aa/UserOpBuilder.js.map +1 -0
  115. package/dist/wallet/aa/constants.d.ts +54 -0
  116. package/dist/wallet/aa/constants.d.ts.map +1 -0
  117. package/dist/wallet/aa/constants.js +18 -0
  118. package/dist/wallet/aa/constants.js.map +1 -0
  119. package/package.json +4 -2
  120. package/src/ACTPClient.ts +217 -31
  121. package/src/adapters/AdapterRouter.ts +0 -1
  122. package/src/adapters/BasicAdapter.ts +41 -1
  123. package/src/cli/commands/init.ts +394 -25
  124. package/src/cli/commands/publish.ts +1 -2
  125. package/src/cli/commands/register.ts +233 -0
  126. package/src/cli/index.ts +4 -0
  127. package/src/cli/utils/config.ts +30 -0
  128. package/src/config/networks.ts +82 -27
  129. package/src/config/publishPipeline.ts +2 -2
  130. package/src/erc8004/ERC8004Bridge.ts +6 -5
  131. package/src/erc8004/ReputationReporter.ts +14 -18
  132. package/src/index.ts +12 -0
  133. package/src/level1/Agent.ts +5 -5
  134. package/src/protocol/ACTPKernel.ts +20 -10
  135. package/src/protocol/EventMonitor.ts +14 -0
  136. package/src/runtime/BlockchainRuntime.ts +7 -1
  137. package/src/storage/ArchiveBundleBuilder.ts +0 -2
  138. package/src/storage/ArweaveClient.ts +2 -1
  139. package/src/storage/FilebaseClient.ts +3 -3
  140. package/src/utils/ErrorRecoveryGuide.ts +4 -2
  141. package/src/utils/IPFSClient.ts +9 -7
  142. package/src/utils/computeTypeHash.ts +1 -3
  143. package/src/utils/retry.ts +0 -1
  144. package/src/utils/validation.ts +2 -2
  145. package/src/wallet/AutoWalletProvider.ts +294 -0
  146. package/src/wallet/EOAWalletProvider.ts +69 -0
  147. package/src/wallet/IWalletProvider.ts +133 -0
  148. package/src/wallet/aa/BundlerClient.ts +274 -0
  149. package/src/wallet/aa/DualNonceManager.ts +173 -0
  150. package/src/wallet/aa/PaymasterClient.ts +174 -0
  151. package/src/wallet/aa/TransactionBatcher.ts +240 -0
  152. package/src/wallet/aa/UserOpBuilder.ts +246 -0
  153. package/src/wallet/aa/constants.ts +60 -0
package/src/ACTPClient.ts CHANGED
@@ -54,6 +54,10 @@ import { ERC8004Bridge } from './erc8004/ERC8004Bridge';
54
54
  import { ReputationReporter } from './erc8004/ReputationReporter';
55
55
  import { ERC8004Network } from './types/erc8004';
56
56
  import { getNetwork } from './config/networks';
57
+ import { IWalletProvider } from './wallet/IWalletProvider';
58
+ import { EOAWalletProvider } from './wallet/EOAWalletProvider';
59
+ import { AutoWalletProvider } from './wallet/AutoWalletProvider';
60
+ import { sdkLogger } from './utils/Logger';
57
61
 
58
62
  // ============================================================================
59
63
  // Security: Path Validation
@@ -70,6 +74,33 @@ import { getNetwork } from './config/networks';
70
74
  * @param stateDirectory - The directory path to validate
71
75
  * @throws Error if path is unsafe
72
76
  */
77
+ /**
78
+ * Check if an agent is registered on AgentRegistry.
79
+ * Lightweight read-only check — no signer needed.
80
+ *
81
+ * Uses minimal ABI fragment to avoid importing the full AgentRegistry class.
82
+ * Checks registeredAt field of AgentProfile struct (> 0 means registered).
83
+ */
84
+ async function checkRegistration(
85
+ provider: ethers.JsonRpcProvider,
86
+ registryAddress: string,
87
+ agentAddress: string
88
+ ): Promise<boolean> {
89
+ const contract = new ethers.Contract(
90
+ registryAddress,
91
+ [
92
+ 'function getAgent(address agentAddress) view returns ' +
93
+ '(tuple(address agentAddress, string did, string endpoint, bytes32[] serviceTypes, ' +
94
+ 'uint256 stakedAmount, uint256 reputationScore, uint256 totalTransactions, ' +
95
+ 'uint256 disputedTransactions, uint256 totalVolumeUSDC, uint256 registeredAt, ' +
96
+ 'uint256 updatedAt, bool isActive, bytes32 configHash, string configCID, bool listed))',
97
+ ],
98
+ provider
99
+ );
100
+ const profile = await contract.getAgent(agentAddress);
101
+ return profile.registeredAt > 0n;
102
+ }
103
+
73
104
  function validateStateDirectory(stateDirectory: string): void {
74
105
  // Check for path traversal characters
75
106
  if (stateDirectory.includes('..')) {
@@ -174,9 +205,24 @@ export interface ACTPClientConfig {
174
205
  * This address is used as the "from" address for all transactions
175
206
  * created through this client instance.
176
207
  *
208
+ * When wallet is 'auto', this is auto-derived from the Smart Wallet
209
+ * and does NOT need to be provided.
210
+ *
177
211
  * @example '0x1111111111111111111111111111111111111111'
178
212
  */
179
- requesterAddress: string;
213
+ requesterAddress?: string;
214
+
215
+ /**
216
+ * AIP-12: Wallet mode.
217
+ *
218
+ * - 'auto': CoinbaseSmartWallet + gas sponsorship (Tier 1, recommended).
219
+ * Requires CDP_API_KEY env var. Agent address = Smart Wallet address.
220
+ * - undefined: EOA wallet from privateKey (Tier 2, backward compatible).
221
+ *
222
+ * When 'auto', requesterAddress is derived from the Smart Wallet
223
+ * and does not need to be provided.
224
+ */
225
+ wallet?: 'auto';
180
226
 
181
227
  /**
182
228
  * Optional: Project root directory for mock state file storage.
@@ -263,6 +309,7 @@ export interface ACTPClientConfig {
263
309
  actpKernel?: string;
264
310
  escrowVault?: string;
265
311
  usdc?: string;
312
+ agentRegistry?: string;
266
313
  };
267
314
 
268
315
  /**
@@ -319,6 +366,8 @@ export interface ACTPClientInfo {
319
366
  address: string;
320
367
  /** State directory (mock mode only) */
321
368
  stateDirectory?: string;
369
+ /** Wallet tier ('auto' = Smart Wallet, 'eoa' = EOA, undefined = mock) */
370
+ walletTier?: 'auto' | 'eoa';
322
371
  }
323
372
 
324
373
  // ============================================================================
@@ -463,6 +512,13 @@ export class ACTPClient {
463
512
  */
464
513
  private readonly reputationReporter?: ReputationReporter;
465
514
 
515
+ /**
516
+ * AIP-12: Wallet provider (Tier 1 Auto or Tier 2 EOA).
517
+ * Only set in testnet/mainnet modes.
518
+ * @internal
519
+ */
520
+ private readonly walletProvider?: IWalletProvider;
521
+
466
522
  /**
467
523
  * Private constructor - use ACTPClient.create() factory method.
468
524
  */
@@ -472,13 +528,16 @@ export class ACTPClient {
472
528
  info: ACTPClientInfo,
473
529
  easHelper?: EASHelper,
474
530
  erc8004Bridge?: ERC8004Bridge,
475
- reputationReporter?: ReputationReporter
531
+ reputationReporter?: ReputationReporter,
532
+ walletProvider?: IWalletProvider,
533
+ contractAddresses?: { usdc: string; actpKernel: string; escrowVault: string }
476
534
  ) {
477
535
  this.runtime = runtime;
478
536
  this.info = info;
479
537
  this.easHelper = easHelper;
480
538
  this.reputationReporter = reputationReporter;
481
- this.basic = new BasicAdapter(runtime, requesterAddress, easHelper);
539
+ this.walletProvider = walletProvider;
540
+ this.basic = new BasicAdapter(runtime, requesterAddress, easHelper, walletProvider, contractAddresses);
482
541
  this.standard = new StandardAdapter(runtime, requesterAddress, easHelper);
483
542
 
484
543
  // Initialize registry and router
@@ -527,31 +586,45 @@ export class ACTPClient {
527
586
  * ```
528
587
  */
529
588
  static async create(config: ACTPClientConfig): Promise<ACTPClient> {
530
- // Validate requester address
531
- if (!config.requesterAddress) {
532
- throw new Error('requesterAddress is required');
533
- }
534
-
535
- if (!/^0x[a-fA-F0-9]{40}$/.test(config.requesterAddress)) {
536
- throw new Error(
537
- `Invalid requesterAddress: "${config.requesterAddress}". ` +
538
- 'Must be a valid Ethereum address (0x-prefixed, 40 hex chars)'
539
- );
540
- }
541
-
542
589
  let runtime: IACTPRuntime;
543
590
  let stateDirectory: string | undefined;
544
591
  let easHelper: EASHelper | undefined;
545
592
  let erc8004Bridge: ERC8004Bridge | undefined;
546
593
  let reputationReporter: ReputationReporter | undefined;
594
+ let walletProvider: IWalletProvider | undefined;
595
+ let requesterAddress: string;
596
+ let contractAddresses: { usdc: string; actpKernel: string; escrowVault: string } | undefined;
547
597
 
548
598
  // If custom runtime provided, use it directly
549
599
  if (config.runtime) {
600
+ // Custom runtime: requesterAddress is mandatory
601
+ if (!config.requesterAddress) {
602
+ throw new Error('requesterAddress is required when providing a custom runtime');
603
+ }
604
+ if (!/^0x[a-fA-F0-9]{40}$/.test(config.requesterAddress)) {
605
+ throw new Error(
606
+ `Invalid requesterAddress: "${config.requesterAddress}". ` +
607
+ 'Must be a valid Ethereum address (0x-prefixed, 40 hex chars)'
608
+ );
609
+ }
610
+ requesterAddress = config.requesterAddress;
550
611
  runtime = config.runtime;
551
612
  } else {
552
613
  // Initialize runtime based on mode
553
614
  switch (config.mode) {
554
615
  case 'mock': {
616
+ // Mock mode: requesterAddress is mandatory
617
+ if (!config.requesterAddress) {
618
+ throw new Error('requesterAddress is required for mock mode');
619
+ }
620
+ if (!/^0x[a-fA-F0-9]{40}$/.test(config.requesterAddress)) {
621
+ throw new Error(
622
+ `Invalid requesterAddress: "${config.requesterAddress}". ` +
623
+ 'Must be a valid Ethereum address (0x-prefixed, 40 hex chars)'
624
+ );
625
+ }
626
+ requesterAddress = config.requesterAddress;
627
+
555
628
  // SECURITY FIX: Enhanced path validation to prevent path traversal attacks
556
629
  if (config.stateDirectory) {
557
630
  validateStateDirectory(config.stateDirectory);
@@ -576,14 +649,12 @@ export class ACTPClient {
576
649
 
577
650
  // Map mode to network config
578
651
  const network = config.mode === 'testnet' ? 'base-sepolia' : 'base-mainnet';
652
+ const networkConfig = getNetwork(network);
579
653
 
580
654
  // Default RPC URL from network config if not provided
581
- // This makes Level0/Agent usable on testnet without forcing users to pass rpcUrl explicitly.
582
- const rpcUrl = config.rpcUrl ?? getNetwork(network).rpcUrl;
655
+ const rpcUrl = config.rpcUrl ?? networkConfig.rpcUrl;
583
656
 
584
- // Optional persistent state directory can be used for:
585
- // - mock mode state (mock-state.json)
586
- // - blockchain mode safety state (e.g., used-attestation replay protection)
657
+ // Optional persistent state directory
587
658
  if (config.stateDirectory) {
588
659
  validateStateDirectory(config.stateDirectory);
589
660
  }
@@ -592,6 +663,100 @@ export class ACTPClient {
592
663
  const provider = new ethers.JsonRpcProvider(rpcUrl);
593
664
  const signer = new ethers.Wallet(config.privateKey, provider);
594
665
 
666
+ // ====================================================================
667
+ // AIP-12: Wallet Provider Selection
668
+ // ====================================================================
669
+ if (config.wallet === 'auto') {
670
+ // Tier 1: CoinbaseSmartWallet + gasless transactions
671
+ if (!networkConfig.aa) {
672
+ throw new Error(
673
+ `AA configuration not available for ${config.mode} mode. ` +
674
+ 'Check that networks.ts has aa config for this network.'
675
+ );
676
+ }
677
+
678
+ // Validate that bundler/paymaster URLs have actual API keys
679
+ const cdpBundlerUrl = networkConfig.aa.bundlerUrls.coinbase;
680
+ const hasPimlico = !!networkConfig.aa.bundlerUrls.pimlico;
681
+ if (cdpBundlerUrl.endsWith('/') && !hasPimlico) {
682
+ throw new Error(
683
+ 'CDP_API_KEY is required for gas-sponsored transactions.\n\n' +
684
+ 'Set up your API key:\n' +
685
+ ' 1. Visit https://portal.cdp.coinbase.com/\n' +
686
+ ' 2. Create a new API key\n' +
687
+ ' 3. export CDP_API_KEY="your-key-here"\n\n' +
688
+ 'Or set PIMLICO_API_KEY as an alternative bundler/paymaster.\n' +
689
+ 'Or use wallet: undefined for traditional EOA transactions (requires ETH for gas).'
690
+ );
691
+ }
692
+
693
+ const autoWallet = await AutoWalletProvider.create({
694
+ signer,
695
+ provider,
696
+ chainId: networkConfig.chainId,
697
+ actpKernelAddress: config.contracts?.actpKernel ?? networkConfig.contracts.actpKernel,
698
+ bundler: {
699
+ primaryUrl: networkConfig.aa.bundlerUrls.coinbase,
700
+ backupUrl: networkConfig.aa.bundlerUrls.pimlico,
701
+ },
702
+ paymaster: {
703
+ primaryUrl: networkConfig.aa.paymasterUrls.coinbase,
704
+ backupUrl: networkConfig.aa.paymasterUrls.pimlico,
705
+ },
706
+ });
707
+
708
+ // Check AgentRegistry — gasless only for registered agents
709
+ const smartWalletAddress = autoWallet.getAddress();
710
+ const agentRegistryAddress = config.contracts?.agentRegistry
711
+ ?? networkConfig.contracts.agentRegistry;
712
+
713
+ let isRegistered = false;
714
+ if (agentRegistryAddress) {
715
+ try {
716
+ isRegistered = await checkRegistration(
717
+ provider, agentRegistryAddress, smartWalletAddress
718
+ );
719
+ } catch {
720
+ // Registry check failed (e.g. RPC down) — allow AA anyway.
721
+ // Rationale: don't punish legit registered agents for infra issues.
722
+ // Paymaster contract allowlist + rate limits prevent abuse.
723
+ isRegistered = true;
724
+ sdkLogger.warn('AgentRegistry check failed, proceeding with AA wallet');
725
+ }
726
+ } else {
727
+ // No registry deployed — skip check (early testnet)
728
+ isRegistered = true;
729
+ }
730
+
731
+ if (isRegistered) {
732
+ walletProvider = autoWallet;
733
+ requesterAddress = smartWalletAddress;
734
+ } else {
735
+ // Not registered — fall back to EOA with warning
736
+ sdkLogger.warn(
737
+ 'Agent not registered on AgentRegistry. ' +
738
+ 'Falling back to EOA wallet (gas not sponsored). ' +
739
+ 'Run "actp register" for gas-free transactions.'
740
+ );
741
+ walletProvider = new EOAWalletProvider(signer, networkConfig.chainId);
742
+ // Force signer.address — config.requesterAddress may be the Smart Wallet
743
+ // address (set by `actp init --wallet auto`), which would be wrong for EOA.
744
+ requesterAddress = signer.address;
745
+ }
746
+ } else {
747
+ // Tier 2: EOA Wallet (backward compatible)
748
+ walletProvider = new EOAWalletProvider(signer, networkConfig.chainId);
749
+ requesterAddress = config.requesterAddress ?? signer.address;
750
+ }
751
+
752
+ // Validate derived/provided address
753
+ if (!/^0x[a-fA-F0-9]{40}$/.test(requesterAddress)) {
754
+ throw new Error(
755
+ `Invalid requesterAddress: "${requesterAddress}". ` +
756
+ 'Must be a valid Ethereum address (0x-prefixed, 40 hex chars)'
757
+ );
758
+ }
759
+
595
760
  const requireAttestation = config.requireAttestation ?? Boolean(config.easConfig);
596
761
 
597
762
  // Create BlockchainRuntime
@@ -618,7 +783,6 @@ export class ACTPClient {
618
783
  }
619
784
 
620
785
  // ERC-8004 INTEGRATION: Create bridge for agent ID resolution
621
- // Maps network to ERC8004Network ('base-sepolia' or 'base')
622
786
  const erc8004Network: ERC8004Network =
623
787
  config.mode === 'testnet' ? 'base-sepolia' : 'base';
624
788
  erc8004Bridge = new ERC8004Bridge({
@@ -627,12 +791,18 @@ export class ACTPClient {
627
791
  });
628
792
 
629
793
  // ERC-8004 REPUTATION: Create reporter for settlement outcome reporting
630
- // Reports successful settlements and dispute outcomes to Reputation Registry
631
794
  reputationReporter = new ReputationReporter({
632
795
  network: erc8004Network,
633
796
  signer,
634
797
  });
635
798
 
799
+ // AIP-12: Contract addresses for AA batched payments
800
+ contractAddresses = {
801
+ usdc: config.contracts?.usdc ?? networkConfig.contracts.usdc,
802
+ actpKernel: config.contracts?.actpKernel ?? networkConfig.contracts.actpKernel,
803
+ escrowVault: config.contracts?.escrowVault ?? networkConfig.contracts.escrowVault,
804
+ };
805
+
636
806
  break;
637
807
  }
638
808
 
@@ -645,17 +815,20 @@ export class ACTPClient {
645
815
  }
646
816
 
647
817
  // Normalize address to lowercase for consistency
648
- const normalizedAddress = config.requesterAddress.toLowerCase();
818
+ const normalizedAddress = requesterAddress.toLowerCase();
649
819
 
650
820
  const info: ACTPClientInfo = {
651
821
  mode: config.mode,
652
822
  address: normalizedAddress,
653
823
  stateDirectory,
824
+ walletTier: walletProvider?.getWalletInfo().tier,
654
825
  };
655
826
 
656
- // SECURITY FIX (C-4): Pass EASHelper to adapters for attestation verification
657
- // ERC-8004: Pass bridge for agent ID resolution, reporter for settlement outcomes
658
- const client = new ACTPClient(runtime, normalizedAddress, info, easHelper, erc8004Bridge, reputationReporter);
827
+ // Pass wallet provider and contract addresses to constructor
828
+ const client = new ACTPClient(
829
+ runtime, normalizedAddress, info, easHelper,
830
+ erc8004Bridge, reputationReporter, walletProvider, contractAddresses
831
+ );
659
832
 
660
833
  // Drift detection: non-blocking check for AGIRAILS.md sync status
661
834
  if (config.mode !== 'mock') {
@@ -1044,7 +1217,7 @@ export class ACTPClient {
1044
1217
  })
1045
1218
  .then((result) => {
1046
1219
  if (result) {
1047
- console.log(
1220
+ sdkLogger.info(
1048
1221
  `[ERC8004] Settlement reported for agent ${agentId}: ${result.txHash}`
1049
1222
  );
1050
1223
  }
@@ -1113,6 +1286,19 @@ export class ACTPClient {
1113
1286
  return this.reputationReporter;
1114
1287
  }
1115
1288
 
1289
+ /**
1290
+ * AIP-12: Get the wallet provider instance.
1291
+ *
1292
+ * Only available in testnet/mainnet modes.
1293
+ * Returns undefined in mock mode.
1294
+ *
1295
+ * Use this for advanced operations like checking wallet info,
1296
+ * or sending custom batched transactions.
1297
+ */
1298
+ getWalletProvider(): IWalletProvider | undefined {
1299
+ return this.walletProvider;
1300
+ }
1301
+
1116
1302
  /**
1117
1303
  * Non-blocking drift detection for AGIRAILS.md config.
1118
1304
  * Checks if local AGIRAILS.md matches on-chain config hash.
@@ -1149,17 +1335,17 @@ export class ACTPClient {
1149
1335
  const { frontmatter } = parseMd(content);
1150
1336
  const isTemplate = !frontmatter.config_hash;
1151
1337
 
1152
- const onChainState = await registryClient.getConfig(config.requesterAddress);
1338
+ const onChainState = await registryClient.getConfig(config.requesterAddress ?? this.info.address);
1153
1339
  const ZERO_HASH = '0x' + '0'.repeat(64);
1154
1340
 
1155
1341
  if (onChainState.configHash === ZERO_HASH) {
1156
1342
  if (isTemplate) {
1157
- console.info('[AGIRAILS] AGIRAILS.md loaded (template mode). Run "actp publish" to register and sync on-chain.');
1343
+ sdkLogger.info('[AGIRAILS] AGIRAILS.md loaded (template mode). Run "actp publish" to register and sync on-chain.');
1158
1344
  } else {
1159
- console.warn('[AGIRAILS] Config not published on-chain. Run: actp publish');
1345
+ sdkLogger.warn('[AGIRAILS] Config not published on-chain. Run: actp publish');
1160
1346
  }
1161
1347
  } else if (onChainState.configHash !== localHash) {
1162
- console.warn('[AGIRAILS] Local AGIRAILS.md differs from on-chain. Run: actp diff');
1348
+ sdkLogger.warn('[AGIRAILS] Local AGIRAILS.md differs from on-chain. Run: actp diff');
1163
1349
  }
1164
1350
  } catch {
1165
1351
  // Silently ignore — drift detection is best-effort
@@ -17,7 +17,6 @@ import { AdapterRegistry } from './AdapterRegistry';
17
17
  import { IAdapter } from './IAdapter';
18
18
  import {
19
19
  UnifiedPayParams,
20
- UnifiedPayParamsSchema,
21
20
  safeValidatePayParams,
22
21
  } from '../types/adapter';
23
22
  import { ValidationError } from './BaseAdapter';
@@ -22,6 +22,8 @@ import {
22
22
  UnifiedPayParams,
23
23
  UnifiedPayResult,
24
24
  } from '../types/adapter';
25
+ import { IWalletProvider } from '../wallet/IWalletProvider';
26
+ import { ethers } from 'ethers';
25
27
 
26
28
  /**
27
29
  * Parameters for creating a simple payment.
@@ -116,11 +118,15 @@ export class BasicAdapter extends BaseAdapter implements IAdapter {
116
118
  * @param runtime - ACTP runtime implementation (MockRuntime or BlockchainRuntime)
117
119
  * @param requesterAddress - The requester's Ethereum address
118
120
  * @param easHelper - Optional EAS helper for attestation verification (SECURITY FIX C-4)
121
+ * @param walletProvider - Optional wallet provider for AA batched payments
122
+ * @param contractAddresses - Optional contract addresses for batched payment encoding
119
123
  */
120
124
  constructor(
121
125
  private runtime: IACTPRuntime,
122
126
  requesterAddress: string,
123
- private easHelper?: EASHelper
127
+ private easHelper?: EASHelper,
128
+ private walletProvider?: IWalletProvider,
129
+ private contractAddresses?: { usdc: string; actpKernel: string; escrowVault: string }
124
130
  ) {
125
131
  super(requesterAddress);
126
132
  }
@@ -187,6 +193,40 @@ export class BasicAdapter extends BaseAdapter implements IAdapter {
187
193
  );
188
194
  }
189
195
 
196
+ // ====================================================================
197
+ // AIP-12: Batched payment via AA wallet (1 UserOp = 3 on-chain calls)
198
+ // ====================================================================
199
+ if (this.walletProvider?.payACTPBatched && this.contractAddresses) {
200
+ const serviceHash = ethers.ZeroHash;
201
+ const result = await this.walletProvider.payACTPBatched({
202
+ provider,
203
+ requester,
204
+ amount: amount.toString(),
205
+ deadline,
206
+ disputeWindow,
207
+ serviceHash,
208
+ agentId: agentId || '0',
209
+ contracts: this.contractAddresses,
210
+ });
211
+
212
+ if (!result.success) {
213
+ throw new Error(`Batched payment UserOp failed: ${result.hash}`);
214
+ }
215
+
216
+ return {
217
+ txId: result.txId,
218
+ provider,
219
+ requester,
220
+ amount: this.formatAmount(amount),
221
+ deadline: new Date(deadline * 1000).toISOString(),
222
+ state: 'COMMITTED',
223
+ };
224
+ }
225
+
226
+ // ====================================================================
227
+ // Legacy flow: sequential on-chain calls (EOA / mock)
228
+ // ====================================================================
229
+
190
230
  // Create transaction
191
231
  const txId = await this.runtime.createTransaction({
192
232
  provider,