@pincerpay/agent 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PincerPay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # @pincerpay/agent
2
+
3
+ Agent SDK for AI agents to pay for APIs using on-chain USDC via the x402 protocol.
4
+
5
+ > **ESM Required:** Your project must have `"type": "module"` in package.json. This package is ESM-only.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @pincerpay/agent
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```typescript
16
+ import { PincerPayAgent } from "@pincerpay/agent";
17
+
18
+ const agent = await PincerPayAgent.create({
19
+ chains: ["solana"],
20
+ solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
21
+ });
22
+
23
+ // Automatic 402 handling — pays and retries transparently
24
+ const response = await agent.fetch("https://api.example.com/weather");
25
+ const data = await response.json();
26
+ ```
27
+
28
+ ## API Reference
29
+
30
+ ### `PincerPayAgent`
31
+
32
+ Wraps `fetch` with automatic x402 payment handling. When a request returns HTTP 402, the agent signs a USDC transfer and retries.
33
+
34
+ ```typescript
35
+ class PincerPayAgent {
36
+ static async create(config: AgentConfig): Promise<PincerPayAgent>;
37
+
38
+ fetch(url: string | URL, init?: RequestInit): Promise<Response>;
39
+
40
+ checkPolicy(amountBaseUnits: string): { allowed: boolean; reason?: string };
41
+ setPolicy(policy: Partial<SpendingPolicy>): void;
42
+ getDailySpend(): { date: string; amount: string };
43
+ recordSpend(amountBaseUnits: string): void;
44
+
45
+ get evmAddress(): string | undefined;
46
+ get solanaAddress(): string | undefined;
47
+ get chains(): string[];
48
+ }
49
+ ```
50
+
51
+ ### `SolanaSmartAgent`
52
+
53
+ Extended agent with Squads SPN smart account support and on-chain spending policies.
54
+
55
+ ```typescript
56
+ class SolanaSmartAgent extends PincerPayAgent {
57
+ static override async create(
58
+ config: SolanaSmartAgentConfig
59
+ ): Promise<SolanaSmartAgent>;
60
+
61
+ get smartAccountPda(): string | undefined;
62
+ get settingsPda(): string | undefined;
63
+ get spendingLimitPda(): string | undefined;
64
+
65
+ async settleDirectly(
66
+ merchantId: string,
67
+ amountBaseUnits: string,
68
+ options?: { facilitatorUrl?: string; apiKey?: string; network?: string }
69
+ ): Promise<{ success: boolean; transactionId?: string; error?: string }>;
70
+
71
+ async checkOnChainPolicy(
72
+ amountBaseUnits: string,
73
+ rpcUrl?: string
74
+ ): Promise<{ allowed: boolean; reason?: string; remainingAmount?: bigint }>;
75
+ }
76
+ ```
77
+
78
+ ### Config
79
+
80
+ ```typescript
81
+ interface AgentConfig {
82
+ chains: string[]; // ["solana", "base", "polygon"]
83
+ evmPrivateKey?: string; // Hex-encoded EVM key
84
+ solanaPrivateKey?: string; // Base58-encoded Solana keypair
85
+ policies?: SpendingPolicy[]; // Client-side spending limits
86
+ facilitatorUrl?: string; // Default: https://facilitator.pincerpay.com
87
+ }
88
+
89
+ interface SpendingPolicy {
90
+ maxPerTransaction?: string; // Max USDC per transaction (base units)
91
+ maxPerDay?: string; // Max USDC per day (base units)
92
+ allowedMerchants?: string[]; // Whitelist merchant addresses
93
+ allowedChains?: string[]; // Whitelist chain shorthands
94
+ }
95
+
96
+ // USDC base units (6 decimals): $0.01 = "10000", $0.10 = "100000", $1.00 = "1000000"
97
+ // WARNING: Do NOT use human-readable amounts like "0.10" — BigInt("0.10") throws at runtime.
98
+ ```
99
+
100
+ ## Common Patterns
101
+
102
+ ### Solana agent with spending limits
103
+
104
+ ```typescript
105
+ const agent = await PincerPayAgent.create({
106
+ chains: ["solana"],
107
+ solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
108
+ policies: [
109
+ {
110
+ maxPerTransaction: "1000000", // 1 USDC max per tx
111
+ maxPerDay: "10000000", // 10 USDC max per day
112
+ },
113
+ ],
114
+ });
115
+ ```
116
+
117
+ ### Multi-chain agent (Solana + EVM)
118
+
119
+ ```typescript
120
+ const agent = await PincerPayAgent.create({
121
+ chains: ["solana", "base"],
122
+ solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
123
+ evmPrivateKey: process.env.AGENT_EVM_KEY!,
124
+ });
125
+ ```
126
+
127
+ ### Direct settlement via Anchor program
128
+
129
+ ```typescript
130
+ import { SolanaSmartAgent } from "@pincerpay/agent";
131
+
132
+ const agent = await SolanaSmartAgent.create({
133
+ chains: ["solana"],
134
+ solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
135
+ smartAccountIndex: 0,
136
+ spendingLimitIndex: 0,
137
+ });
138
+
139
+ const result = await agent.settleDirectly("merchant-uuid", "500000", {
140
+ apiKey: process.env.PINCERPAY_API_KEY!,
141
+ });
142
+ ```
143
+
144
+ ### Runtime policy management
145
+
146
+ ```typescript
147
+ // Pre-check if a payment would be allowed
148
+ const check = agent.checkPolicy("500000"); // 0.50 USDC
149
+ if (!check.allowed) console.log(check.reason);
150
+
151
+ // Update spending limits dynamically
152
+ agent.setPolicy({ maxPerTransaction: "5000000", maxPerDay: "50000000" });
153
+
154
+ // Monitor daily spending
155
+ const { date, amount } = agent.getDailySpend();
156
+ console.log(`Spent ${amount} base units on ${date}`);
157
+ ```
158
+
159
+ ## Anti-Patterns
160
+
161
+ ### Don't expose agent private keys in client-side code
162
+
163
+ Agent keys should only be used in server-side or backend agent processes, never in browser environments.
164
+
165
+ ### Don't skip spending policies in production
166
+
167
+ Without policies, an agent can spend unlimited USDC. Always set `maxPerDay` at minimum.
168
+
169
+ ```typescript
170
+ // Bad — no limits
171
+ const agent = await PincerPayAgent.create({
172
+ chains: ["solana"],
173
+ solanaPrivateKey: key,
174
+ });
175
+
176
+ // Good — bounded spending
177
+ const agent = await PincerPayAgent.create({
178
+ chains: ["solana"],
179
+ solanaPrivateKey: key,
180
+ policies: [{ maxPerDay: "10000000" }], // 10 USDC/day
181
+ });
182
+ ```
183
+
184
+ ### Don't use `PincerPayAgent` for merchant-side logic
185
+
186
+ The agent SDK is for making payments. Use `@pincerpay/merchant` for accepting payments.
@@ -0,0 +1,74 @@
1
+ import { x402Client } from "@x402/core/client";
2
+ import type { AgentConfig, SpendingPolicy } from "@pincerpay/core";
3
+ /**
4
+ * PincerPayAgent — wraps x402/fetch with EVM + Solana wallet support and spending policies.
5
+ *
6
+ * ```ts
7
+ * const agent = await PincerPayAgent.create({
8
+ * chains: ["base-sepolia"],
9
+ * evmPrivateKey: process.env.AGENT_EVM_KEY!,
10
+ * });
11
+ *
12
+ * const response = await agent.fetch("https://api.example.com/weather");
13
+ * ```
14
+ */
15
+ export declare class PincerPayAgent {
16
+ private config;
17
+ private x402Fetch;
18
+ private dailySpend;
19
+ private dailyResetAt;
20
+ private _solanaAddress?;
21
+ /**
22
+ * Create a new PincerPayAgent. Use `PincerPayAgent.create()` for async initialization
23
+ * (required when using Solana wallets).
24
+ */
25
+ constructor(config: AgentConfig, client?: x402Client);
26
+ /**
27
+ * Async factory — use this when Solana wallets are needed.
28
+ * Also works for EVM-only agents.
29
+ */
30
+ static create(config: AgentConfig): Promise<PincerPayAgent>;
31
+ /**
32
+ * Payment-enabled fetch — automatically handles 402 challenges.
33
+ */
34
+ fetch(url: string | URL, init?: RequestInit): Promise<Response>;
35
+ /**
36
+ * Check if a transaction amount is within spending policy limits.
37
+ */
38
+ checkPolicy(amountBaseUnits: string): {
39
+ allowed: boolean;
40
+ reason?: string;
41
+ };
42
+ /**
43
+ * Record a successful spend for daily tracking.
44
+ */
45
+ recordSpend(amountBaseUnits: string): void;
46
+ /** Get the agent's EVM address */
47
+ get evmAddress(): string | undefined;
48
+ /** Get the agent's Solana address (only available via PincerPayAgent.create()) */
49
+ get solanaAddress(): string | undefined;
50
+ /** Get configured chain shorthands */
51
+ get chains(): string[];
52
+ /**
53
+ * Replace the agent's spending policies and reset daily tracking.
54
+ */
55
+ setPolicy(policy: SpendingPolicy): void;
56
+ /**
57
+ * Get the first active spending policy, if any.
58
+ */
59
+ getPolicy(): SpendingPolicy | undefined;
60
+ /**
61
+ * Get today's tracked spend total and date.
62
+ */
63
+ getDailySpend(): {
64
+ date: string;
65
+ amount: bigint;
66
+ };
67
+ /**
68
+ * Register x402 hooks to enforce spending policies before payment
69
+ * and record spend after successful payment creation.
70
+ */
71
+ private registerPolicyHooks;
72
+ private resetDailyIfNeeded;
73
+ }
74
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAK/C,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,cAAc,CAAC,CAAS;IAEhC;;;OAGG;gBACS,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,UAAU;IAsBpD;;;OAGG;WACU,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC;IAuBjE;;OAEG;IACG,KAAK,CACT,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,QAAQ,CAAC;IAIpB;;OAEG;IACH,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAuC3E;;OAEG;IACH,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI;IAO1C,kCAAkC;IAClC,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAGnC;IAED,kFAAkF;IAClF,IAAI,aAAa,IAAI,MAAM,GAAG,SAAS,CAEtC;IAED,sCAAsC;IACtC,IAAI,MAAM,IAAI,MAAM,EAAE,CAErB;IAED;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAMvC;;OAEG;IACH,SAAS,IAAI,cAAc,GAAG,SAAS;IAIvC;;OAEG;IACH,aAAa,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;IASjD;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,kBAAkB;CAU3B"}
package/dist/client.js ADDED
@@ -0,0 +1,217 @@
1
+ import { privateKeyToAccount } from "viem/accounts";
2
+ import { x402Client } from "@x402/core/client";
3
+ import { wrapFetchWithPayment } from "@x402/fetch";
4
+ import { registerExactEvmScheme } from "@x402/evm/exact/client";
5
+ import { registerExactSvmScheme } from "@x402/svm/exact/client";
6
+ import { createKeyPairSignerFromBytes } from "@solana/kit";
7
+ /**
8
+ * PincerPayAgent — wraps x402/fetch with EVM + Solana wallet support and spending policies.
9
+ *
10
+ * ```ts
11
+ * const agent = await PincerPayAgent.create({
12
+ * chains: ["base-sepolia"],
13
+ * evmPrivateKey: process.env.AGENT_EVM_KEY!,
14
+ * });
15
+ *
16
+ * const response = await agent.fetch("https://api.example.com/weather");
17
+ * ```
18
+ */
19
+ export class PincerPayAgent {
20
+ config;
21
+ x402Fetch;
22
+ dailySpend = new Map();
23
+ dailyResetAt = 0;
24
+ _solanaAddress;
25
+ /**
26
+ * Create a new PincerPayAgent. Use `PincerPayAgent.create()` for async initialization
27
+ * (required when using Solana wallets).
28
+ */
29
+ constructor(config, client) {
30
+ this.config = config;
31
+ if (!config.evmPrivateKey && !config.solanaPrivateKey) {
32
+ throw new Error("At least one wallet key (evmPrivateKey or solanaPrivateKey) is required");
33
+ }
34
+ const x402 = client ?? new x402Client();
35
+ // Register EVM scheme synchronously
36
+ if (config.evmPrivateKey && !client) {
37
+ const account = privateKeyToAccount(config.evmPrivateKey);
38
+ registerExactEvmScheme(x402, { signer: account });
39
+ }
40
+ // Register spending policy hooks
41
+ this.registerPolicyHooks(x402);
42
+ // Wrap global fetch with x402 payment handling
43
+ this.x402Fetch = wrapFetchWithPayment(globalThis.fetch, x402);
44
+ }
45
+ /**
46
+ * Async factory — use this when Solana wallets are needed.
47
+ * Also works for EVM-only agents.
48
+ */
49
+ static async create(config) {
50
+ const client = new x402Client();
51
+ // Register EVM scheme
52
+ if (config.evmPrivateKey) {
53
+ const account = privateKeyToAccount(config.evmPrivateKey);
54
+ registerExactEvmScheme(client, { signer: account });
55
+ }
56
+ // Register Solana scheme (async — needs key derivation)
57
+ let solanaAddress;
58
+ if (config.solanaPrivateKey) {
59
+ const keyBytes = base58Decode(config.solanaPrivateKey);
60
+ const keypairSigner = await createKeyPairSignerFromBytes(keyBytes);
61
+ registerExactSvmScheme(client, { signer: keypairSigner });
62
+ solanaAddress = keypairSigner.address;
63
+ }
64
+ const agent = new PincerPayAgent(config, client);
65
+ agent._solanaAddress = solanaAddress;
66
+ return agent;
67
+ }
68
+ /**
69
+ * Payment-enabled fetch — automatically handles 402 challenges.
70
+ */
71
+ async fetch(url, init) {
72
+ return this.x402Fetch(url.toString(), init);
73
+ }
74
+ /**
75
+ * Check if a transaction amount is within spending policy limits.
76
+ */
77
+ checkPolicy(amountBaseUnits) {
78
+ const policies = this.config.policies;
79
+ if (!policies || policies.length === 0) {
80
+ return { allowed: true };
81
+ }
82
+ const amount = BigInt(amountBaseUnits);
83
+ for (const policy of policies) {
84
+ // Per-transaction limit
85
+ if (policy.maxPerTransaction) {
86
+ const max = BigInt(policy.maxPerTransaction);
87
+ if (amount > max) {
88
+ return {
89
+ allowed: false,
90
+ reason: `Exceeds per-transaction limit: ${amountBaseUnits} > ${policy.maxPerTransaction}`,
91
+ };
92
+ }
93
+ }
94
+ // Daily limit
95
+ if (policy.maxPerDay) {
96
+ this.resetDailyIfNeeded();
97
+ const todayKey = new Date().toISOString().slice(0, 10);
98
+ const currentSpend = this.dailySpend.get(todayKey) ?? 0n;
99
+ const max = BigInt(policy.maxPerDay);
100
+ if (currentSpend + amount > max) {
101
+ return {
102
+ allowed: false,
103
+ reason: `Exceeds daily limit: ${currentSpend + amount} > ${policy.maxPerDay}`,
104
+ };
105
+ }
106
+ }
107
+ }
108
+ return { allowed: true };
109
+ }
110
+ /**
111
+ * Record a successful spend for daily tracking.
112
+ */
113
+ recordSpend(amountBaseUnits) {
114
+ this.resetDailyIfNeeded();
115
+ const todayKey = new Date().toISOString().slice(0, 10);
116
+ const current = this.dailySpend.get(todayKey) ?? 0n;
117
+ this.dailySpend.set(todayKey, current + BigInt(amountBaseUnits));
118
+ }
119
+ /** Get the agent's EVM address */
120
+ get evmAddress() {
121
+ if (!this.config.evmPrivateKey)
122
+ return undefined;
123
+ return privateKeyToAccount(this.config.evmPrivateKey).address;
124
+ }
125
+ /** Get the agent's Solana address (only available via PincerPayAgent.create()) */
126
+ get solanaAddress() {
127
+ return this._solanaAddress;
128
+ }
129
+ /** Get configured chain shorthands */
130
+ get chains() {
131
+ return this.config.chains;
132
+ }
133
+ /**
134
+ * Replace the agent's spending policies and reset daily tracking.
135
+ */
136
+ setPolicy(policy) {
137
+ this.config.policies = [policy];
138
+ this.dailySpend.clear();
139
+ this.dailyResetAt = 0;
140
+ }
141
+ /**
142
+ * Get the first active spending policy, if any.
143
+ */
144
+ getPolicy() {
145
+ return this.config.policies?.[0];
146
+ }
147
+ /**
148
+ * Get today's tracked spend total and date.
149
+ */
150
+ getDailySpend() {
151
+ this.resetDailyIfNeeded();
152
+ const todayKey = new Date().toISOString().slice(0, 10);
153
+ return {
154
+ date: todayKey,
155
+ amount: this.dailySpend.get(todayKey) ?? 0n,
156
+ };
157
+ }
158
+ /**
159
+ * Register x402 hooks to enforce spending policies before payment
160
+ * and record spend after successful payment creation.
161
+ */
162
+ registerPolicyHooks(client) {
163
+ if (!this.config.policies || this.config.policies.length === 0)
164
+ return;
165
+ // Before payment: enforce spending limits
166
+ client.onBeforePaymentCreation(async (ctx) => {
167
+ const amount = String(ctx.selectedRequirements.maxAmountRequired ?? ctx.selectedRequirements.amount ?? "0");
168
+ const check = this.checkPolicy(amount);
169
+ if (!check.allowed) {
170
+ return { abort: true, reason: check.reason };
171
+ }
172
+ });
173
+ // After payment: track spend for daily limits
174
+ client.onAfterPaymentCreation(async (ctx) => {
175
+ const amount = String(ctx.selectedRequirements.maxAmountRequired ?? ctx.selectedRequirements.amount ?? "0");
176
+ this.recordSpend(amount);
177
+ });
178
+ }
179
+ resetDailyIfNeeded() {
180
+ const now = Date.now();
181
+ if (now > this.dailyResetAt) {
182
+ this.dailySpend.clear();
183
+ // Reset at midnight UTC
184
+ const tomorrow = new Date();
185
+ tomorrow.setUTCHours(24, 0, 0, 0);
186
+ this.dailyResetAt = tomorrow.getTime();
187
+ }
188
+ }
189
+ }
190
+ /**
191
+ * Minimal base58 decoder for Solana private keys.
192
+ * Avoids pulling in @scure/base as a dependency for the agent SDK.
193
+ */
194
+ function base58Decode(input) {
195
+ const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
196
+ const BASE = BigInt(58);
197
+ let num = 0n;
198
+ for (const char of input) {
199
+ const idx = ALPHABET.indexOf(char);
200
+ if (idx === -1)
201
+ throw new Error(`Invalid base58 character: ${char}`);
202
+ num = num * BASE + BigInt(idx);
203
+ }
204
+ // Count leading zeros
205
+ let leadingZeros = 0;
206
+ for (const char of input) {
207
+ if (char !== "1")
208
+ break;
209
+ leadingZeros++;
210
+ }
211
+ // Convert to bytes (pad hex to even length so .match(/.{2}/g) doesn't drop a nibble)
212
+ const rawHex = num.toString(16);
213
+ const hex = rawHex.length % 2 ? "0" + rawHex : rawHex;
214
+ const bytes = hex.match(/.{2}/g)?.map((b) => parseInt(b, 16)) ?? [];
215
+ return new Uint8Array([...new Array(leadingZeros).fill(0), ...bytes]);
216
+ }
217
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { PincerPayAgent } from "./client.js";
2
+ export { SolanaSmartAgent } from "./solana-agent.js";
3
+ export type { AgentConfig, SpendingPolicy, SolanaSmartAgentConfig, AgentStatus, AgentProfile } from "@pincerpay/core";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,sBAAsB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { PincerPayAgent } from "./client.js";
2
+ export { SolanaSmartAgent } from "./solana-agent.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,95 @@
1
+ import type { Instruction } from "@solana/kit";
2
+ import { type SolanaSmartAgentConfig } from "@pincerpay/core";
3
+ import { SpendingLimitPeriod } from "@pincerpay/solana/squads";
4
+ import { PincerPayAgent } from "./client.js";
5
+ /**
6
+ * SolanaSmartAgent — extends PincerPayAgent with Squads Smart Account support.
7
+ *
8
+ * Spending limits are enforced on-chain via the Squads program, not in-memory.
9
+ * This agent performs an optimistic pre-check against the on-chain spending limit
10
+ * before each payment, but the real enforcement happens at the transaction level.
11
+ *
12
+ * ```ts
13
+ * const agent = await SolanaSmartAgent.create({
14
+ * chains: ["solana"],
15
+ * solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
16
+ * smartAccountIndex: 0,
17
+ * spendingLimitIndex: 0,
18
+ * });
19
+ *
20
+ * const response = await agent.fetch("https://api.example.com/weather");
21
+ * ```
22
+ */
23
+ export declare class SolanaSmartAgent extends PincerPayAgent {
24
+ private smartConfig;
25
+ private _smartAccountPda?;
26
+ private _settingsPda?;
27
+ private _spendingLimitPda?;
28
+ private constructor();
29
+ /**
30
+ * Async factory — initializes the Solana wallet, derives Squads PDAs,
31
+ * and optionally validates on-chain state.
32
+ */
33
+ static create(config: SolanaSmartAgentConfig): Promise<SolanaSmartAgent>;
34
+ /** Get the Squads Smart Account PDA */
35
+ get smartAccountPda(): string | undefined;
36
+ /** Get the Squads Settings PDA */
37
+ get settingsPda(): string | undefined;
38
+ /** Get the Squads Spending Limit PDA */
39
+ get spendingLimitPda(): string | undefined;
40
+ /**
41
+ * Settle a payment directly via the Anchor program (bypassing x402).
42
+ * Calls POST /v1/settle-direct on the facilitator.
43
+ *
44
+ * Returns the settlement response including the on-chain accounts needed
45
+ * for the agent to construct and sign the settle_payment instruction.
46
+ */
47
+ settleDirectly(merchantId: string, amountBaseUnits: string, options?: {
48
+ facilitatorUrl?: string;
49
+ apiKey?: string;
50
+ network?: string;
51
+ }): Promise<{
52
+ success: boolean;
53
+ transactionId?: string;
54
+ accounts?: Record<string, string>;
55
+ error?: string;
56
+ }>;
57
+ /**
58
+ * Build a createSmartAccount instruction using this agent's config.
59
+ * The caller is responsible for signing and sending.
60
+ */
61
+ buildCreateSmartAccountInstruction(params?: {
62
+ members?: string[];
63
+ threshold?: number;
64
+ }): Promise<Instruction>;
65
+ /**
66
+ * Build an addSpendingLimit instruction for this agent's Smart Account.
67
+ * Requires a Smart Account to be configured.
68
+ */
69
+ buildAddSpendingLimitInstruction(params: {
70
+ mint: string;
71
+ amount: bigint;
72
+ period: SpendingLimitPeriod;
73
+ members?: string[];
74
+ destinations?: string[];
75
+ authority: string;
76
+ }): Promise<Instruction>;
77
+ /**
78
+ * Build a removeSpendingLimit instruction for this agent's Smart Account.
79
+ * Requires a Smart Account to be configured.
80
+ */
81
+ buildRevokeSpendingLimitInstruction(params: {
82
+ authority: string;
83
+ rentCollector?: string;
84
+ }): Promise<Instruction>;
85
+ /**
86
+ * Check on-chain spending limit before payment.
87
+ * This is an optimistic pre-check — the real enforcement is on-chain.
88
+ */
89
+ checkOnChainPolicy(amountBaseUnits: string, rpcUrl?: string): Promise<{
90
+ allowed: boolean;
91
+ reason?: string;
92
+ remainingAmount?: bigint;
93
+ }>;
94
+ }
95
+ //# sourceMappingURL=solana-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana-agent.d.ts","sourceRoot":"","sources":["../src/solana-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAA2B,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACvF,OAAO,EAQL,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,gBAAiB,SAAQ,cAAc;IAClD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAClC,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,iBAAiB,CAAC,CAAS;IAEnC,OAAO;IAKP;;;OAGG;WACmB,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoCvF,uCAAuC;IACvC,IAAI,eAAe,IAAI,MAAM,GAAG,SAAS,CAExC;IAED,kCAAkC;IAClC,IAAI,WAAW,IAAI,MAAM,GAAG,SAAS,CAEpC;IAED,wCAAwC;IACxC,IAAI,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAEzC;IAED;;;;;;OAMG;IACG,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GACvE,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAClC,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IAmCF;;;OAGG;IACG,kCAAkC,CAAC,MAAM,CAAC,EAAE;QAChD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBxB;;;OAGG;IACG,gCAAgC,CAAC,MAAM,EAAE;QAC7C,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,mBAAmB,CAAC;QAC5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,WAAW,CAAC;IAqBxB;;;OAGG;IACG,mCAAmC,CAAC,MAAM,EAAE;QAChD,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,GAAG,OAAO,CAAC,WAAW,CAAC;IAaxB;;;OAGG;IACG,kBAAkB,CACtB,eAAe,EAAE,MAAM,EACvB,MAAM,SAAkC,GACvC,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CA8B5E"}
@@ -0,0 +1,190 @@
1
+ import { createSolanaRpc } from "@solana/kit";
2
+ import { DEFAULT_FACILITATOR_URL } from "@pincerpay/core";
3
+ import { deriveSmartAccountPda, deriveSettingsPda, deriveSpendingLimitPda, checkSpendingLimit, createSmartAccountInstruction, addSpendingLimitInstruction, removeSpendingLimitInstruction, SpendingLimitPeriod, } from "@pincerpay/solana/squads";
4
+ import { PincerPayAgent } from "./client.js";
5
+ /**
6
+ * SolanaSmartAgent — extends PincerPayAgent with Squads Smart Account support.
7
+ *
8
+ * Spending limits are enforced on-chain via the Squads program, not in-memory.
9
+ * This agent performs an optimistic pre-check against the on-chain spending limit
10
+ * before each payment, but the real enforcement happens at the transaction level.
11
+ *
12
+ * ```ts
13
+ * const agent = await SolanaSmartAgent.create({
14
+ * chains: ["solana"],
15
+ * solanaPrivateKey: process.env.AGENT_SOLANA_KEY!,
16
+ * smartAccountIndex: 0,
17
+ * spendingLimitIndex: 0,
18
+ * });
19
+ *
20
+ * const response = await agent.fetch("https://api.example.com/weather");
21
+ * ```
22
+ */
23
+ export class SolanaSmartAgent extends PincerPayAgent {
24
+ smartConfig;
25
+ _smartAccountPda;
26
+ _settingsPda;
27
+ _spendingLimitPda;
28
+ constructor(config) {
29
+ super(config);
30
+ this.smartConfig = config;
31
+ }
32
+ /**
33
+ * Async factory — initializes the Solana wallet, derives Squads PDAs,
34
+ * and optionally validates on-chain state.
35
+ */
36
+ static async create(config) {
37
+ // Create the base agent (registers Solana x402 scheme)
38
+ const baseAgent = await PincerPayAgent.create(config);
39
+ // Create SolanaSmartAgent and transfer state
40
+ const agent = new SolanaSmartAgent(config);
41
+ // Copy over the Solana address from base agent
42
+ Object.defineProperty(agent, "_solanaAddress", {
43
+ value: baseAgent.solanaAddress,
44
+ writable: true,
45
+ });
46
+ // Derive Squads PDAs if configured
47
+ const solanaAddr = baseAgent.solanaAddress;
48
+ if (solanaAddr && config.smartAccountIndex !== undefined) {
49
+ const [smartPda] = await deriveSmartAccountPda(solanaAddr, config.smartAccountIndex);
50
+ agent._smartAccountPda = smartPda;
51
+ const [settingsPda] = await deriveSettingsPda(smartPda);
52
+ agent._settingsPda = config.settingsPda ?? settingsPda;
53
+ if (config.spendingLimitIndex !== undefined) {
54
+ const [limitPda] = await deriveSpendingLimitPda(smartPda, config.spendingLimitIndex);
55
+ agent._spendingLimitPda = limitPda;
56
+ }
57
+ }
58
+ return agent;
59
+ }
60
+ /** Get the Squads Smart Account PDA */
61
+ get smartAccountPda() {
62
+ return this._smartAccountPda;
63
+ }
64
+ /** Get the Squads Settings PDA */
65
+ get settingsPda() {
66
+ return this._settingsPda;
67
+ }
68
+ /** Get the Squads Spending Limit PDA */
69
+ get spendingLimitPda() {
70
+ return this._spendingLimitPda;
71
+ }
72
+ /**
73
+ * Settle a payment directly via the Anchor program (bypassing x402).
74
+ * Calls POST /v1/settle-direct on the facilitator.
75
+ *
76
+ * Returns the settlement response including the on-chain accounts needed
77
+ * for the agent to construct and sign the settle_payment instruction.
78
+ */
79
+ async settleDirectly(merchantId, amountBaseUnits, options) {
80
+ const facilitatorUrl = options?.facilitatorUrl
81
+ ?? this.smartConfig.facilitatorUrl
82
+ ?? DEFAULT_FACILITATOR_URL;
83
+ const solanaAddr = this.solanaAddress;
84
+ if (!solanaAddr) {
85
+ return { success: false, error: "No Solana address configured" };
86
+ }
87
+ try {
88
+ const response = await globalThis.fetch(`${facilitatorUrl}/v1/settle-direct`, {
89
+ method: "POST",
90
+ headers: {
91
+ "Content-Type": "application/json",
92
+ ...(options?.apiKey ? { "x-pincerpay-api-key": options.apiKey } : {}),
93
+ },
94
+ body: JSON.stringify({
95
+ agentAddress: solanaAddr,
96
+ merchantId,
97
+ amount: amountBaseUnits,
98
+ network: options?.network ?? "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
99
+ }),
100
+ });
101
+ const result = await response.json();
102
+ return result;
103
+ }
104
+ catch (err) {
105
+ return {
106
+ success: false,
107
+ error: err instanceof Error ? err.message : String(err),
108
+ };
109
+ }
110
+ }
111
+ /**
112
+ * Build a createSmartAccount instruction using this agent's config.
113
+ * The caller is responsible for signing and sending.
114
+ */
115
+ async buildCreateSmartAccountInstruction(params) {
116
+ const solanaAddr = this.solanaAddress;
117
+ if (!solanaAddr)
118
+ throw new Error("No Solana address configured");
119
+ const accountIndex = this.smartConfig.smartAccountIndex ?? 0;
120
+ const members = params?.members?.map((m) => m) ?? [solanaAddr];
121
+ const threshold = params?.threshold ?? 1;
122
+ return createSmartAccountInstruction({
123
+ creator: solanaAddr,
124
+ accountIndex,
125
+ members,
126
+ threshold,
127
+ });
128
+ }
129
+ /**
130
+ * Build an addSpendingLimit instruction for this agent's Smart Account.
131
+ * Requires a Smart Account to be configured.
132
+ */
133
+ async buildAddSpendingLimitInstruction(params) {
134
+ if (!this._smartAccountPda)
135
+ throw new Error("No Smart Account PDA configured");
136
+ const solanaAddr = this.solanaAddress;
137
+ const spendingLimitIndex = this.smartConfig.spendingLimitIndex ?? 0;
138
+ const members = params.members?.map((m) => m) ?? (solanaAddr ? [solanaAddr] : []);
139
+ return addSpendingLimitInstruction({
140
+ smartAccountPda: this._smartAccountPda,
141
+ mint: params.mint,
142
+ amount: params.amount,
143
+ period: params.period,
144
+ members,
145
+ destinations: params.destinations?.map((d) => d) ?? [],
146
+ }, spendingLimitIndex, params.authority);
147
+ }
148
+ /**
149
+ * Build a removeSpendingLimit instruction for this agent's Smart Account.
150
+ * Requires a Smart Account to be configured.
151
+ */
152
+ async buildRevokeSpendingLimitInstruction(params) {
153
+ if (!this._smartAccountPda)
154
+ throw new Error("No Smart Account PDA configured");
155
+ const spendingLimitIndex = this.smartConfig.spendingLimitIndex ?? 0;
156
+ return removeSpendingLimitInstruction({
157
+ smartAccountPda: this._smartAccountPda,
158
+ spendingLimitIndex,
159
+ authority: params.authority,
160
+ rentCollector: (params.rentCollector ?? params.authority),
161
+ });
162
+ }
163
+ /**
164
+ * Check on-chain spending limit before payment.
165
+ * This is an optimistic pre-check — the real enforcement is on-chain.
166
+ */
167
+ async checkOnChainPolicy(amountBaseUnits, rpcUrl = "https://api.devnet.solana.com") {
168
+ if (!this._smartAccountPda || this.smartConfig.spendingLimitIndex === undefined) {
169
+ // No Squads spending limit configured — fall back to in-memory policy
170
+ return this.checkPolicy(amountBaseUnits);
171
+ }
172
+ const result = await checkSpendingLimit(this._smartAccountPda, this.smartConfig.spendingLimitIndex, rpcUrl);
173
+ if (!result) {
174
+ return {
175
+ allowed: false,
176
+ reason: "Spending limit account not found on-chain",
177
+ };
178
+ }
179
+ const amount = BigInt(amountBaseUnits);
180
+ if (result.remainingAmount !== undefined && amount > result.remainingAmount) {
181
+ return {
182
+ allowed: false,
183
+ reason: `Exceeds on-chain spending limit: ${amountBaseUnits} > ${result.remainingAmount}`,
184
+ remainingAmount: result.remainingAmount,
185
+ };
186
+ }
187
+ return { allowed: true, remainingAmount: result.remainingAmount };
188
+ }
189
+ }
190
+ //# sourceMappingURL=solana-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana-agent.js","sourceRoot":"","sources":["../src/solana-agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAA+B,MAAM,iBAAiB,CAAC;AACvF,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EAClB,6BAA6B,EAC7B,2BAA2B,EAC3B,8BAA8B,EAC9B,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,gBAAiB,SAAQ,cAAc;IAC1C,WAAW,CAAyB;IACpC,gBAAgB,CAAU;IAC1B,YAAY,CAAU;IACtB,iBAAiB,CAAU;IAEnC,YAAoB,MAA8B;QAChD,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACH,MAAM,CAAU,KAAK,CAAC,MAAM,CAAC,MAA8B;QACzD,uDAAuD;QACvD,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAEtD,6CAA6C;QAC7C,MAAM,KAAK,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC3C,+CAA+C;QAC/C,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,gBAAgB,EAAE;YAC7C,KAAK,EAAE,SAAS,CAAC,aAAa;YAC9B,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QAEH,mCAAmC;QACnC,MAAM,UAAU,GAAG,SAAS,CAAC,aAAa,CAAC;QAC3C,IAAI,UAAU,IAAI,MAAM,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACzD,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,qBAAqB,CAC5C,UAAqB,EACrB,MAAM,CAAC,iBAAiB,CACzB,CAAC;YACF,KAAK,CAAC,gBAAgB,GAAG,QAAQ,CAAC;YAElC,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YACxD,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,WAAW,IAAI,WAAW,CAAC;YAEvD,IAAI,MAAM,CAAC,kBAAkB,KAAK,SAAS,EAAE,CAAC;gBAC5C,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,sBAAsB,CAC7C,QAAQ,EACR,MAAM,CAAC,kBAAkB,CAC1B,CAAC;gBACF,KAAK,CAAC,iBAAiB,GAAG,QAAQ,CAAC;YACrC,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED,uCAAuC;IACvC,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED,kCAAkC;IAClC,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,wCAAwC;IACxC,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,cAAc,CAClB,UAAkB,EAClB,eAAuB,EACvB,OAAwE;QAOxE,MAAM,cAAc,GAAG,OAAO,EAAE,cAAc;eACzC,IAAI,CAAC,WAAW,CAAC,cAAc;eAC/B,uBAAuB,CAAC;QAE7B,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC;QACtC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC;QACnE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,GAAG,cAAc,mBAAmB,EAAE;gBAC5E,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACtE;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,YAAY,EAAE,UAAU;oBACxB,UAAU;oBACV,MAAM,EAAE,eAAe;oBACvB,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,yCAAyC;iBACvE,CAAC;aACH,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACrC,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,kCAAkC,CAAC,MAGxC;QACC,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC;QACtC,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAEjE,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,IAAI,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAY,CAAC,IAAI,CAAC,UAAqB,CAAC,CAAC;QACrF,MAAM,SAAS,GAAG,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC;QAEzC,OAAO,6BAA6B,CAAC;YACnC,OAAO,EAAE,UAAqB;YAC9B,YAAY;YACZ,OAAO;YACP,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,gCAAgC,CAAC,MAOtC;QACC,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QAE/E,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC;QACtC,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,CAAC,kBAAkB,IAAI,CAAC,CAAC;QACpE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAqB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAExG,OAAO,2BAA2B,CAChC;YACE,eAAe,EAAE,IAAI,CAAC,gBAA2B;YACjD,IAAI,EAAE,MAAM,CAAC,IAAe;YAC5B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,OAAO;YACP,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAY,CAAC,IAAI,EAAE;SAClE,EACD,kBAAkB,EAClB,MAAM,CAAC,SAAoB,CAC5B,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,mCAAmC,CAAC,MAGzC;QACC,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QAE/E,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,CAAC,kBAAkB,IAAI,CAAC,CAAC;QAEpE,OAAO,8BAA8B,CAAC;YACpC,eAAe,EAAE,IAAI,CAAC,gBAA2B;YACjD,kBAAkB;YAClB,SAAS,EAAE,MAAM,CAAC,SAAoB;YACtC,aAAa,EAAE,CAAC,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,SAAS,CAAY;SACrE,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,kBAAkB,CACtB,eAAuB,EACvB,MAAM,GAAG,+BAA+B;QAExC,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,WAAW,CAAC,kBAAkB,KAAK,SAAS,EAAE,CAAC;YAChF,sEAAsE;YACtE,OAAO,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,IAAI,CAAC,gBAA2B,EAChC,IAAI,CAAC,WAAW,CAAC,kBAAkB,EACnC,MAAM,CACP,CAAC;QAEF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,2CAA2C;aACpD,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;QACvC,IAAI,MAAM,CAAC,eAAe,KAAK,SAAS,IAAI,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;YAC5E,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,oCAAoC,eAAe,MAAM,MAAM,CAAC,eAAe,EAAE;gBACzF,eAAe,EAAE,MAAM,CAAC,eAAe;aACxC,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC;IACpE,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@pincerpay/agent",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Agent SDK for PincerPay. Drop-in fetch wrapper that handles x402 payment flows automatically.",
6
+ "license": "MIT",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "homepage": "https://pincerpay.com",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/ds1/pincerpay.git",
14
+ "directory": "packages/agent"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/ds1/pincerpay/issues"
18
+ },
19
+ "keywords": [
20
+ "pincerpay",
21
+ "x402",
22
+ "usdc",
23
+ "payments",
24
+ "ai-agents",
25
+ "solana",
26
+ "agent-sdk",
27
+ "payment-gateway",
28
+ "stablecoin"
29
+ ],
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "main": "dist/index.js",
36
+ "types": "dist/index.d.ts",
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "import": "./dist/index.js"
41
+ }
42
+ },
43
+ "dependencies": {
44
+ "@solana/kit": "^5.5.1",
45
+ "@x402/core": "^2.3",
46
+ "@x402/evm": "^2.3",
47
+ "@x402/fetch": "^2.3",
48
+ "@x402/svm": "^2.3.0",
49
+ "viem": "^2",
50
+ "zod": "^3.24",
51
+ "@pincerpay/core": "0.1.0",
52
+ "@pincerpay/solana": "0.1.0"
53
+ },
54
+ "devDependencies": {
55
+ "@scure/base": "^1.2.6",
56
+ "typescript": "^5.7"
57
+ },
58
+ "scripts": {
59
+ "build": "tsc",
60
+ "test": "vitest run",
61
+ "typecheck": "tsc --noEmit",
62
+ "clean": "rm -rf dist"
63
+ }
64
+ }