@pincerpay/agent 0.1.1 → 0.2.0

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 (2) hide show
  1. package/README.md +96 -26
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![license](https://img.shields.io/npm/l/@pincerpay/agent?style=flat-square)](https://github.com/ds1/pincerpay/blob/master/LICENSE)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
7
 
8
- Agent SDK for AI agents to pay for APIs using on-chain USDC via the x402 protocol.
8
+ Agent SDK for AI agents to pay for APIs using on-chain USDC via the [x402 protocol](https://x402.org).
9
9
 
10
10
  > **ESM Required:** Your project must have `"type": "module"` in package.json. This package is ESM-only.
11
11
 
@@ -25,7 +25,7 @@ const agent = await PincerPayAgent.create({
25
25
  solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
26
26
  });
27
27
 
28
- // Automatic 402 handling pays and retries transparently
28
+ // Automatic 402 handling -- pays and retries transparently
29
29
  const response = await agent.fetch("https://api.example.com/weather");
30
30
  const data = await response.json();
31
31
  ```
@@ -34,7 +34,7 @@ const data = await response.json();
34
34
 
35
35
  ### `PincerPayAgent`
36
36
 
37
- Wraps `fetch` with automatic x402 payment handling. When a request returns HTTP 402, the agent signs a USDC transfer and retries.
37
+ Wraps `fetch` with automatic x402 payment handling. When a request returns HTTP 402, the agent signs a USDC transfer and retries. Spending policies are enforced at the x402 protocol layer via `onBeforePaymentCreation` and `onAfterPaymentCreation` hooks.
38
38
 
39
39
  ```typescript
40
40
  class PincerPayAgent {
@@ -42,11 +42,14 @@ class PincerPayAgent {
42
42
 
43
43
  fetch(url: string | URL, init?: RequestInit): Promise<Response>;
44
44
 
45
+ // Policy enforcement
45
46
  checkPolicy(amountBaseUnits: string): { allowed: boolean; reason?: string };
46
- setPolicy(policy: Partial<SpendingPolicy>): void;
47
- getDailySpend(): { date: string; amount: string };
47
+ setPolicy(policy: SpendingPolicy): void;
48
+ getPolicy(): SpendingPolicy | undefined;
48
49
  recordSpend(amountBaseUnits: string): void;
50
+ getDailySpend(): { date: string; amount: bigint };
49
51
 
52
+ // Wallet info
50
53
  get evmAddress(): string | undefined;
51
54
  get solanaAddress(): string | undefined;
52
55
  get chains(): string[];
@@ -55,28 +58,49 @@ class PincerPayAgent {
55
58
 
56
59
  ### `SolanaSmartAgent`
57
60
 
58
- Extended agent with Squads SPN smart account support and on-chain spending policies.
61
+ Extended agent with Squads SPN smart account support, on-chain spending policies, and direct settlement via the Anchor program.
59
62
 
60
63
  ```typescript
61
64
  class SolanaSmartAgent extends PincerPayAgent {
62
- static override async create(
63
- config: SolanaSmartAgentConfig
64
- ): Promise<SolanaSmartAgent>;
65
+ static override async create(config: SolanaSmartAgentConfig): Promise<SolanaSmartAgent>;
65
66
 
67
+ // Squads PDAs (derived automatically from config)
66
68
  get smartAccountPda(): string | undefined;
67
69
  get settingsPda(): string | undefined;
68
70
  get spendingLimitPda(): string | undefined;
69
71
 
72
+ // Direct settlement (bypasses x402, settles via Anchor program)
70
73
  async settleDirectly(
71
74
  merchantId: string,
72
75
  amountBaseUnits: string,
73
76
  options?: { facilitatorUrl?: string; apiKey?: string; network?: string }
74
- ): Promise<{ success: boolean; transactionId?: string; error?: string }>;
77
+ ): Promise<{ success: boolean; transactionId?: string; accounts?: Record<string, string>; error?: string }>;
75
78
 
79
+ // On-chain policy check (optimistic pre-check against Squads spending limit)
76
80
  async checkOnChainPolicy(
77
81
  amountBaseUnits: string,
78
82
  rpcUrl?: string
79
83
  ): Promise<{ allowed: boolean; reason?: string; remainingAmount?: bigint }>;
84
+
85
+ // Instruction builders (returns Instruction, caller signs and sends)
86
+ async buildCreateSmartAccountInstruction(params?: {
87
+ members?: string[];
88
+ threshold?: number;
89
+ }): Promise<Instruction>;
90
+
91
+ async buildAddSpendingLimitInstruction(params: {
92
+ mint: string;
93
+ amount: bigint;
94
+ period: SpendingLimitPeriod;
95
+ members?: string[];
96
+ destinations?: string[];
97
+ authority: string;
98
+ }): Promise<Instruction>;
99
+
100
+ async buildRevokeSpendingLimitInstruction(params: {
101
+ authority: string;
102
+ rentCollector?: string;
103
+ }): Promise<Instruction>;
80
104
  }
81
105
  ```
82
106
 
@@ -91,6 +115,12 @@ interface AgentConfig {
91
115
  facilitatorUrl?: string; // Default: https://facilitator.pincerpay.com
92
116
  }
93
117
 
118
+ interface SolanaSmartAgentConfig extends AgentConfig {
119
+ settingsPda?: string; // Override Squads Settings PDA
120
+ smartAccountIndex?: number; // For PDA derivation (default: 0)
121
+ spendingLimitIndex?: number; // For PDA derivation (default: 0)
122
+ }
123
+
94
124
  interface SpendingPolicy {
95
125
  maxPerTransaction?: string; // Max USDC per transaction (base units)
96
126
  maxPerDay?: string; // Max USDC per day (base units)
@@ -99,7 +129,7 @@ interface SpendingPolicy {
99
129
  }
100
130
 
101
131
  // USDC base units (6 decimals): $0.01 = "10000", $0.10 = "100000", $1.00 = "1000000"
102
- // WARNING: Do NOT use human-readable amounts like "0.10" BigInt("0.10") throws at runtime.
132
+ // WARNING: Do NOT use human-readable amounts like "0.10" -- BigInt("0.10") throws at runtime.
103
133
  ```
104
134
 
105
135
  ## Common Patterns
@@ -129,6 +159,25 @@ const agent = await PincerPayAgent.create({
129
159
  });
130
160
  ```
131
161
 
162
+ ### Runtime policy management
163
+
164
+ ```typescript
165
+ // Pre-check if a payment would be allowed
166
+ const check = agent.checkPolicy("500000"); // 0.50 USDC
167
+ if (!check.allowed) console.log(check.reason);
168
+
169
+ // Get current policy
170
+ const policy = agent.getPolicy();
171
+ // { maxPerTransaction: "1000000", maxPerDay: "10000000" }
172
+
173
+ // Update spending limits dynamically (resets daily tracking)
174
+ agent.setPolicy({ maxPerTransaction: "5000000", maxPerDay: "50000000" });
175
+
176
+ // Monitor daily spending
177
+ const { date, amount } = agent.getDailySpend();
178
+ console.log(`Spent ${amount} base units on ${date}`); // amount is bigint
179
+ ```
180
+
132
181
  ### Direct settlement via Anchor program
133
182
 
134
183
  ```typescript
@@ -141,24 +190,35 @@ const agent = await SolanaSmartAgent.create({
141
190
  spendingLimitIndex: 0,
142
191
  });
143
192
 
144
- const result = await agent.settleDirectly("merchant-uuid", "500000", {
145
- apiKey: process.env.PINCERPAY_API_KEY!,
146
- });
193
+ // Check on-chain spending limit before payment
194
+ const check = await agent.checkOnChainPolicy("500000");
195
+ if (check.allowed) {
196
+ const result = await agent.settleDirectly("merchant-uuid", "500000", {
197
+ apiKey: process.env.PINCERPAY_API_KEY!,
198
+ });
199
+ }
147
200
  ```
148
201
 
149
- ### Runtime policy management
202
+ ### Build Squads instructions for wallet signing
150
203
 
151
204
  ```typescript
152
- // Pre-check if a payment would be allowed
153
- const check = agent.checkPolicy("500000"); // 0.50 USDC
154
- if (!check.allowed) console.log(check.reason);
155
-
156
- // Update spending limits dynamically
157
- agent.setPolicy({ maxPerTransaction: "5000000", maxPerDay: "50000000" });
205
+ const agent = await SolanaSmartAgent.create({
206
+ chains: ["solana"],
207
+ solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
208
+ smartAccountIndex: 0,
209
+ });
158
210
 
159
- // Monitor daily spending
160
- const { date, amount } = agent.getDailySpend();
161
- console.log(`Spent ${amount} base units on ${date}`);
211
+ // Build instructions -- sign and send with your wallet adapter
212
+ const createIx = await agent.buildCreateSmartAccountInstruction({ threshold: 1 });
213
+ const limitIx = await agent.buildAddSpendingLimitInstruction({
214
+ mint: usdcMintAddress,
215
+ amount: 10_000_000n, // 10 USDC
216
+ period: SpendingLimitPeriod.Day,
217
+ authority: walletAddress,
218
+ });
219
+ const revokeIx = await agent.buildRevokeSpendingLimitInstruction({
220
+ authority: walletAddress,
221
+ });
162
222
  ```
163
223
 
164
224
  ## Anti-Patterns
@@ -172,13 +232,13 @@ Agent keys should only be used in server-side or backend agent processes, never
172
232
  Without policies, an agent can spend unlimited USDC. Always set `maxPerDay` at minimum.
173
233
 
174
234
  ```typescript
175
- // Bad no limits
235
+ // Bad -- no limits
176
236
  const agent = await PincerPayAgent.create({
177
237
  chains: ["solana"],
178
238
  solanaPrivateKey: key,
179
239
  });
180
240
 
181
- // Good bounded spending
241
+ // Good -- bounded spending
182
242
  const agent = await PincerPayAgent.create({
183
243
  chains: ["solana"],
184
244
  solanaPrivateKey: key,
@@ -189,3 +249,13 @@ const agent = await PincerPayAgent.create({
189
249
  ### Don't use `PincerPayAgent` for merchant-side logic
190
250
 
191
251
  The agent SDK is for making payments. Use `@pincerpay/merchant` for accepting payments.
252
+
253
+ ### Don't use human-readable amounts in policies
254
+
255
+ ```typescript
256
+ // Bad -- BigInt("0.10") throws SyntaxError at runtime
257
+ policies: [{ maxPerTransaction: "0.10" }]
258
+
259
+ // Good -- use base units (6 decimals)
260
+ policies: [{ maxPerTransaction: "100000" }] // 0.10 USDC
261
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pincerpay/agent",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "description": "Agent SDK for PincerPay. Drop-in fetch wrapper that handles x402 payment flows automatically.",
6
6
  "license": "MIT",
@@ -57,8 +57,8 @@
57
57
  "@x402/svm": "^2.3.0",
58
58
  "viem": "^2",
59
59
  "zod": "^3.24",
60
- "@pincerpay/core": "0.1.1",
61
- "@pincerpay/solana": "0.1.1"
60
+ "@pincerpay/solana": "0.2.0",
61
+ "@pincerpay/core": "0.2.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@scure/base": "^1.2.6",