cronos-agent-wallet 1.2.2 → 1.2.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/README.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  The official SDK for building AI agents that can pay for resources on the Cronos blockchain using the x402 protocol.
4
4
 
5
+ ## Architecture
6
+
7
+ This SDK employs a **Hybrid "Exoskeleton" Architecture**:
8
+ - **Off-Chain**: Fast, free logic enforcement and state tracking (MongoDB).
9
+ - **On-Chain**: Immutable security anchors (Registry & Policy) to prevent tampering.
10
+
11
+ ```mermaid
12
+ graph TD
13
+ subgraph Agent SDK
14
+ Local[Local Policy Engine]
15
+ Anchor[On-Chain Policy Anchor (read-only)]
16
+ Executor[x402 Payment Executor]
17
+ end
18
+
19
+ subgraph Merchant Middleware
20
+ MRegistry[Merchant Registry (read-only)]
21
+ Verifier[x402 Verification]
22
+ end
23
+
24
+ Local -->|Checks Hash| Anchor
25
+ Local -->|Approves| Executor
26
+ Executor -->|Signed Claim| Verifier
27
+ Verifier -->|Verifies Identity| MRegistry
28
+ Verifier -->|Payment Tx| Cronos[Cronos EVM]
29
+ ```
30
+
5
31
  ## 🛡️ Security Features (v1.1.1)
6
32
  - **Zero Trust Payer:** Derives identity strictly from chain data.
7
33
  - **Strong Replay Protection:** Enforces cryptographic binding of `merchantId + route + nonce`.
@@ -28,12 +28,7 @@ class AgentClient {
28
28
  // 1. Create executor (chain-specific)
29
29
  const executor = new CronosUsdcExecutor_1.CronosUsdcExecutor(config.rpcUrl, config.privateKey, config.usdcAddress, config.chainId);
30
30
  // 2. Create wallet (policy + persistence)
31
- this.wallet = new AgentWallet_1.AgentWallet(executor.getAddress(), executor, {
32
- dailyLimit: config.dailyLimit,
33
- maxPerTransaction: config.maxPerTransaction,
34
- trustedFacilitators: config.trustedFacilitators,
35
- allowedMerchants: config.allowedMerchants,
36
- });
31
+ this.wallet = new AgentWallet_1.AgentWallet(executor.getAddress(), executor, executor.getProvider(), executor.getSigner(), config);
37
32
  // 3. Context passed per request
38
33
  this.context = {
39
34
  chainId: config.chainId,
package/dist/config.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ export interface OnChainAnchors {
2
+ merchantRegistry?: string;
3
+ agentPolicyRegistry?: string;
4
+ policyVerifier?: string;
5
+ }
1
6
  export interface AgentConfig {
2
7
  privateKey: string;
3
8
  rpcUrl: string;
@@ -8,5 +13,14 @@ export interface AgentConfig {
8
13
  allowedMerchants?: string[];
9
14
  trustedFacilitators?: string[];
10
15
  analyticsUrl?: string;
16
+ anchors?: OnChainAnchors;
17
+ strictPolicy?: boolean;
11
18
  merchantId?: string;
12
19
  }
20
+ export declare const AGENT_CONFIG_DEFAULTS: {
21
+ anchors: {
22
+ merchantRegistry: string;
23
+ agentPolicyRegistry: string;
24
+ policyVerifier: string;
25
+ };
26
+ };
package/dist/config.js CHANGED
@@ -1,2 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AGENT_CONFIG_DEFAULTS = void 0;
4
+ exports.AGENT_CONFIG_DEFAULTS = {
5
+ // Cronos Testnet Anchors
6
+ anchors: {
7
+ merchantRegistry: "0x1948175dDB81DA08a4cf17BE4E0C95B97dD11F5c",
8
+ agentPolicyRegistry: "0xce3b58c9ae8CA4724d6FA8684d2Cb89546FF4E43",
9
+ policyVerifier: "0xFCb2D2279256B62A1E4E07BCDed26B6546bBc33b"
10
+ }
11
+ };
@@ -1,5 +1,7 @@
1
- import { PaymentRequest, WalletContext, AgentWalletConfig } from "./types";
1
+ import { PaymentRequest, WalletContext } from "./types";
2
2
  import { PaymentExecutor } from "./executors";
3
+ import { AgentConfig } from "../config";
4
+ import { ethers } from "ethers";
3
5
  /**
4
6
  * AgentWallet
5
7
  * ------------
@@ -12,6 +14,9 @@ import { PaymentExecutor } from "./executors";
12
14
  export declare class AgentWallet {
13
15
  private readonly address;
14
16
  private readonly executor;
17
+ private readonly provider;
18
+ private readonly wallet;
19
+ private readonly config;
15
20
  private dailyLimit;
16
21
  private maxPerTransaction;
17
22
  private spentToday;
@@ -20,16 +25,25 @@ export declare class AgentWallet {
20
25
  private trustedFacilitatorOrigins;
21
26
  private stopped;
22
27
  private isInitialized;
28
+ /**
29
+ * Replay protection
30
+ * key -> timestamp
31
+ */
23
32
  /**
24
33
  * Replay protection
25
34
  * key -> timestamp
26
35
  */
27
36
  private paidRequests;
28
- constructor(address: string, executor: PaymentExecutor, config?: AgentWalletConfig);
37
+ private policyRegistry?;
38
+ constructor(address: string, executor: PaymentExecutor, provider: ethers.Provider, wallet: ethers.Wallet, config: AgentConfig);
29
39
  private getTodayDate;
30
40
  init(): Promise<void>;
31
41
  private loadState;
32
42
  private saveState;
43
+ /**
44
+ * Checks if the local policy matches the on-chain anchor.
45
+ */
46
+ private verifyPolicyAnchor;
33
47
  getAddress(): string;
34
48
  private getHeader;
35
49
  private canonicalOrigin;
@@ -4,6 +4,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.AgentWallet = void 0;
7
+ const PolicyRegistryAdapter_1 = require("./PolicyRegistryAdapter");
8
+ const ethers_1 = require("ethers");
9
+ // Helper to hash policy config
10
+ function hashPolicy(config) {
11
+ const policyData = {
12
+ dailyLimit: config.dailyLimit || 0,
13
+ maxPerTransaction: config.maxPerTransaction || 0
14
+ };
15
+ return ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(JSON.stringify(policyData)));
16
+ }
7
17
  const mongoose_1 = __importDefault(require("mongoose"));
8
18
  const models_1 = require("./models");
9
19
  /**
@@ -18,6 +28,9 @@ const models_1 = require("./models");
18
28
  class AgentWallet {
19
29
  address;
20
30
  executor;
31
+ provider;
32
+ wallet;
33
+ config;
21
34
  // ---------------- CONFIG ----------------
22
35
  // Reduced limit for testing persistence (0.5 USDC)
23
36
  dailyLimit = 0.5;
@@ -33,14 +46,23 @@ class AgentWallet {
33
46
  ]);
34
47
  stopped = false;
35
48
  isInitialized = false;
49
+ /**
50
+ * Replay protection
51
+ * key -> timestamp
52
+ */
36
53
  /**
37
54
  * Replay protection
38
55
  * key -> timestamp
39
56
  */
40
57
  paidRequests = new Map();
41
- constructor(address, executor, config) {
58
+ // On-Chain Adapter
59
+ policyRegistry;
60
+ constructor(address, executor, provider, wallet, config) {
42
61
  this.address = address;
43
62
  this.executor = executor;
63
+ this.provider = provider;
64
+ this.wallet = wallet;
65
+ this.config = config;
44
66
  if (config) {
45
67
  if (config.dailyLimit !== undefined)
46
68
  this.dailyLimit = config.dailyLimit;
@@ -50,6 +72,17 @@ class AgentWallet {
50
72
  this.allowedMerchants = new Set(config.allowedMerchants);
51
73
  if (config.trustedFacilitators)
52
74
  this.trustedFacilitatorOrigins = new Set(config.trustedFacilitators);
75
+ // Initialize On-Chain Adapter if configured
76
+ if (config.anchors?.agentPolicyRegistry) {
77
+ this.policyRegistry = new PolicyRegistryAdapter_1.PolicyRegistryAdapter(config.anchors.agentPolicyRegistry, provider, wallet);
78
+ // Non-blocking check for setup/warning
79
+ this.verifyPolicyAnchor().catch(err => {
80
+ console.error("[AgentWallet] Policy Anchor Warning:", err.message);
81
+ if (config.strictPolicy) {
82
+ process.exit(1); // Strict mode: fail fast
83
+ }
84
+ });
85
+ }
53
86
  }
54
87
  this.lastResetDate = this.getTodayDate();
55
88
  }
@@ -141,6 +174,42 @@ class AgentWallet {
141
174
  console.error("[WALLET] Failed to save state to DB", error);
142
175
  }
143
176
  }
177
+ /**
178
+ * Checks if the local policy matches the on-chain anchor.
179
+ */
180
+ async verifyPolicyAnchor() {
181
+ if (!this.policyRegistry)
182
+ return;
183
+ try {
184
+ console.log("[AgentWallet] Verifying policy against on-chain anchor...");
185
+ const onChain = await this.policyRegistry.getPolicy(this.address);
186
+ // Check 1: Freeze status
187
+ if (onChain.isFrozen) {
188
+ this.stopped = true;
189
+ throw new Error("Agent policy is FROZEN on-chain. Emergency stop activated.");
190
+ }
191
+ // Check 2: Hash mismatch
192
+ const localHash = hashPolicy(this.config);
193
+ // Note: We check if on-chain hash is set (non-zero) before enforcing
194
+ if (onChain.policyHash !== ethers_1.ethers.ZeroHash && onChain.policyHash !== localHash) {
195
+ const msg = `Policy Hash Mismatch! Local: ${localHash}, Chain: ${onChain.policyHash}`;
196
+ if (this.config?.strictPolicy) {
197
+ throw new Error(msg);
198
+ }
199
+ else {
200
+ console.warn(`[AgentWallet] WARN: ${msg}. Running in PERMISSIVE mode.`);
201
+ }
202
+ }
203
+ else {
204
+ console.log("[AgentWallet] ✅ Policy verified on-chain.");
205
+ }
206
+ }
207
+ catch (error) {
208
+ console.error("[AgentWallet] Anchor check failed:", error.message);
209
+ if (this.config?.strictPolicy)
210
+ throw error;
211
+ }
212
+ }
144
213
  // ---------------- PUBLIC ----------------
145
214
  getAddress() {
146
215
  return this.address;
@@ -1,4 +1,5 @@
1
1
  import "dotenv/config";
2
+ import { ethers } from "ethers";
2
3
  import { PaymentExecutor } from "./executors";
3
4
  import { PaymentRequest } from "./types";
4
5
  export declare class CronosUsdcExecutor implements PaymentExecutor {
@@ -11,4 +12,6 @@ export declare class CronosUsdcExecutor implements PaymentExecutor {
11
12
  private withRetry;
12
13
  execute(request: PaymentRequest): Promise<string>;
13
14
  getAddress(): string;
15
+ getProvider(): ethers.JsonRpcProvider;
16
+ getSigner(): ethers.Wallet;
14
17
  }
@@ -114,5 +114,11 @@ nonce = ${request.nonce}`);
114
114
  getAddress() {
115
115
  return this.wallet.address;
116
116
  }
117
+ getProvider() {
118
+ return this.provider;
119
+ }
120
+ getSigner() {
121
+ return this.wallet;
122
+ }
117
123
  }
118
124
  exports.CronosUsdcExecutor = CronosUsdcExecutor;
@@ -0,0 +1,32 @@
1
+ import { ethers, Provider, Wallet } from "ethers";
2
+ export interface OnChainPolicy {
3
+ dailySpendLimit: bigint;
4
+ maxPerTransaction: bigint;
5
+ policyHash: string;
6
+ isFrozen: boolean;
7
+ lastUpdated: bigint;
8
+ }
9
+ export interface PolicyInput {
10
+ dailySpendLimit: bigint;
11
+ maxPerTransaction: bigint;
12
+ policyHash: string;
13
+ }
14
+ export declare class PolicyRegistryAdapter {
15
+ private address;
16
+ private provider;
17
+ private signer?;
18
+ private contract;
19
+ constructor(address: string, provider: Provider, signer?: Wallet | undefined);
20
+ /**
21
+ * Reads the policy for the given agent from the blockchain.
22
+ * @param agentAddress The address to query
23
+ * @returns The policy struct or null if not found
24
+ */
25
+ getPolicy(agentAddress: string): Promise<OnChainPolicy>;
26
+ /**
27
+ * Writes the policy to the blockchain.
28
+ * @warning This is a gas-consuming transaction.
29
+ * @warning Should strictly be used during SETUP or RECOVERY, not during normal agent operation.
30
+ */
31
+ setPolicy(policy: PolicyInput): Promise<ethers.TransactionReceipt>;
32
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PolicyRegistryAdapter = void 0;
4
+ const ethers_1 = require("ethers");
5
+ const ABI = [
6
+ "function getPolicy(address agentAddress) external view returns (uint256 dailySpendLimit, uint256 maxPerTransaction, bytes32 policyHash, bool isFrozen, uint256 lastUpdated)",
7
+ "function setPolicy(uint256 dailySpendLimit, uint256 maxPerTransaction, bytes32 policyHash) external",
8
+ "event PolicySet(address indexed agent, uint256 dailySpendLimit, uint256 maxPerTransaction, bytes32 policyHash, uint256 timestamp)"
9
+ ];
10
+ class PolicyRegistryAdapter {
11
+ address;
12
+ provider;
13
+ signer;
14
+ contract;
15
+ constructor(address, provider, signer) {
16
+ this.address = address;
17
+ this.provider = provider;
18
+ this.signer = signer;
19
+ this.contract = new ethers_1.Contract(address, ABI, signer || provider);
20
+ }
21
+ /**
22
+ * Reads the policy for the given agent from the blockchain.
23
+ * @param agentAddress The address to query
24
+ * @returns The policy struct or null if not found
25
+ */
26
+ async getPolicy(agentAddress) {
27
+ return this.contract.getPolicy(agentAddress);
28
+ }
29
+ /**
30
+ * Writes the policy to the blockchain.
31
+ * @warning This is a gas-consuming transaction.
32
+ * @warning Should strictly be used during SETUP or RECOVERY, not during normal agent operation.
33
+ */
34
+ async setPolicy(policy) {
35
+ if (!this.signer) {
36
+ throw new Error("PolicyRegistryAdapter: No signer available for setPolicy");
37
+ }
38
+ // Runtime Guard: We add a parameter or check logic to prevent accidental usage.
39
+ // For now, explicit naming and documentation is the primary guard, plus the requirement of a signer.
40
+ const tx = await this.contract.setPolicy(policy.dailySpendLimit, policy.maxPerTransaction, policy.policyHash);
41
+ return tx.wait();
42
+ }
43
+ }
44
+ exports.PolicyRegistryAdapter = PolicyRegistryAdapter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cronos-agent-wallet",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [