@ziongateway/sdk 0.1.0 → 0.1.2
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 +102 -29
- package/dist/Universal.d.ts +36 -9
- package/dist/Universal.js +10 -0
- package/dist/ZionGate.d.ts +55 -14
- package/dist/ZionGate.js +87 -32
- package/dist/index.d.ts +60 -4
- package/dist/index.js +49 -3
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
The **Zion SDK** allows AI Agents and developers to easily monetize their APIs using the **Zion X-402 Facilitator**. It handles the **HTTP 402 Payment Required** protocol, standardizing payment requests, verification, and settlement on the Solana blockchain.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
6
|
+
- **Middleware Protection**: Automatically blocks unpaid requests with a `402` status.
|
|
7
|
+
- **Flexible Pricing**: Set prices in USDC (or other assets).
|
|
8
|
+
- **Instant Settlement**: Verifies and settles payments via the Facilitator.
|
|
9
|
+
- **Framework Agnostic**: Works with Express, Next.js, NestJS, etc.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npm install @
|
|
16
|
+
npm install @ziongateway/sdk
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
---
|
|
@@ -25,7 +25,7 @@ Protect your API routes by adding `ZionGate` middleware.
|
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
27
|
import express from "express";
|
|
28
|
-
import { ZionGate } from "@
|
|
28
|
+
import { ZionGate } from "@ziongateway/sdk";
|
|
29
29
|
|
|
30
30
|
const app = express();
|
|
31
31
|
|
|
@@ -54,7 +54,7 @@ app.listen(3000, () => console.log("Server running on port 3000"));
|
|
|
54
54
|
Use the `nextServer` helper in your route handlers.
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
|
-
import { ZionGate } from "@
|
|
57
|
+
import { ZionGate } from "@ziongateway/sdk";
|
|
58
58
|
|
|
59
59
|
const zion = new ZionGate({ /* config */ });
|
|
60
60
|
|
|
@@ -70,49 +70,122 @@ export async function GET(req: Request) {
|
|
|
70
70
|
|
|
71
71
|
---
|
|
72
72
|
|
|
73
|
-
## Usage (Client-Side)
|
|
73
|
+
## Usage (Client-Side / AI Agent)
|
|
74
74
|
|
|
75
|
-
When a client receives a `402 Payment Required` response, they must
|
|
75
|
+
When a client receives a `402 Payment Required` response, they must:
|
|
76
|
+
1. Create an **atomic split transaction** (99% to developer, 1% to treasury)
|
|
77
|
+
2. Sign and send the transaction
|
|
78
|
+
3. Build the payment header with the signature
|
|
79
|
+
4. Retry the request with the `Authorization` header
|
|
76
80
|
|
|
77
81
|
### 1. Handling the 402 Response
|
|
78
|
-
The server returns payment requirements:
|
|
82
|
+
The server returns all payment requirements (including the correct USDC mint for the network):
|
|
79
83
|
|
|
80
84
|
```json
|
|
81
85
|
{
|
|
82
|
-
"recipient": "FjK...", // Developer's Wallet
|
|
86
|
+
"recipient": "FjK...", // Developer's Wallet (auto-fetched)
|
|
83
87
|
"amount": "100000", // Atomic units (0.1 USDC)
|
|
84
|
-
"asset": "EPj...", // USDC Mint
|
|
85
|
-
"treasury": "AgH...", // Zion Treasury
|
|
86
|
-
"
|
|
88
|
+
"asset": "EPj...", // USDC Mint (automatic based on network)
|
|
89
|
+
"treasury": "AgH...", // Zion Treasury
|
|
90
|
+
"network": "solana-devnet"
|
|
87
91
|
}
|
|
88
92
|
```
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
> **Note:** You don't need to know the USDC mint address - it's provided in the response automatically based on the network (mainnet or devnet).
|
|
95
|
+
|
|
96
|
+
### 2. Creating the Atomic Split Transaction
|
|
97
|
+
|
|
98
|
+
The payment **must be split atomically** in a single transaction:
|
|
99
|
+
- **99%** goes to the `recipient` (developer)
|
|
100
|
+
- **1%** goes to the `treasury` (Zion fee)
|
|
101
|
+
|
|
102
|
+
Use `PaymentBuilder.createAtomicSplitInstructions()` to generate the transfer instructions:
|
|
92
103
|
|
|
93
104
|
```typescript
|
|
94
|
-
import { PaymentBuilder } from "@
|
|
105
|
+
import { PaymentBuilder } from "@ziongateway/sdk";
|
|
106
|
+
import { Connection, Transaction, PublicKey } from "@solana/web3.js";
|
|
107
|
+
import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction } from "@solana/spl-token";
|
|
108
|
+
|
|
109
|
+
// 1. Receive 402 response with payment requirements
|
|
110
|
+
const res = await fetch("/api/protected");
|
|
111
|
+
if (res.status !== 402) return;
|
|
112
|
+
const requirements = await res.json();
|
|
113
|
+
|
|
114
|
+
// 2. Create atomic split transfer instructions
|
|
115
|
+
const connection = new Connection("https://api.devnet.solana.com");
|
|
116
|
+
const instructions = await PaymentBuilder.createAtomicSplitInstructions({
|
|
117
|
+
sender: wallet.publicKey.toBase58(),
|
|
118
|
+
recipient: requirements.recipient, // Developer wallet
|
|
119
|
+
treasury: requirements.treasury, // Zion treasury
|
|
120
|
+
amount: requirements.amount, // Total amount (fee split handled automatically)
|
|
121
|
+
asset: requirements.asset, // USDC mint
|
|
122
|
+
connection
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// 3. Build transaction (create ATAs if needed)
|
|
126
|
+
const tx = new Transaction();
|
|
127
|
+
const assetMint = new PublicKey(requirements.asset);
|
|
128
|
+
|
|
129
|
+
// Check if recipient/treasury ATAs exist, create if not
|
|
130
|
+
const recipientAta = await getAssociatedTokenAddress(assetMint, new PublicKey(requirements.recipient));
|
|
131
|
+
const treasuryAta = await getAssociatedTokenAddress(assetMint, new PublicKey(requirements.treasury));
|
|
132
|
+
|
|
133
|
+
const recipientInfo = await connection.getAccountInfo(recipientAta);
|
|
134
|
+
if (!recipientInfo) {
|
|
135
|
+
tx.add(createAssociatedTokenAccountInstruction(
|
|
136
|
+
wallet.publicKey, recipientAta, new PublicKey(requirements.recipient), assetMint
|
|
137
|
+
));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const treasuryInfo = await connection.getAccountInfo(treasuryAta);
|
|
141
|
+
if (!treasuryInfo) {
|
|
142
|
+
tx.add(createAssociatedTokenAccountInstruction(
|
|
143
|
+
wallet.publicKey, treasuryAta, new PublicKey(requirements.treasury), assetMint
|
|
144
|
+
));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Add the split transfer instructions
|
|
148
|
+
tx.add(...instructions);
|
|
95
149
|
|
|
96
|
-
//
|
|
150
|
+
// 4. Sign and send
|
|
151
|
+
const { blockhash } = await connection.getLatestBlockhash();
|
|
152
|
+
tx.recentBlockhash = blockhash;
|
|
153
|
+
tx.feePayer = wallet.publicKey;
|
|
97
154
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
155
|
+
const signature = await wallet.sendTransaction(tx, connection);
|
|
156
|
+
await connection.confirmTransaction(signature, "confirmed");
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 3. Creating the Payment Header
|
|
160
|
+
|
|
161
|
+
After the transaction is confirmed, create the payment header:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
const paymentHeader = PaymentBuilder.createHeader({
|
|
165
|
+
signature, // Transaction signature
|
|
166
|
+
sender: wallet.publicKey.toBase58(),
|
|
167
|
+
recipient: requirements.recipient,
|
|
168
|
+
amount: requirements.amount,
|
|
169
|
+
asset: requirements.asset,
|
|
104
170
|
timestamp: Math.floor(Date.now() / 1000),
|
|
105
|
-
nonce:
|
|
106
|
-
signature: "TRANSACTION_SIGNATURE", // From Solana Web3.js
|
|
171
|
+
nonce: crypto.randomUUID(), // Unique per request
|
|
107
172
|
network: "solana-devnet"
|
|
108
173
|
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 4. Retry with Authorization Header
|
|
109
177
|
|
|
110
|
-
|
|
111
|
-
const response = await fetch("
|
|
178
|
+
```typescript
|
|
179
|
+
const response = await fetch("/api/protected", {
|
|
112
180
|
headers: {
|
|
113
|
-
"Authorization": `Bearer ${
|
|
181
|
+
"Authorization": `Bearer ${paymentHeader}`
|
|
114
182
|
}
|
|
115
183
|
});
|
|
184
|
+
|
|
185
|
+
if (response.ok) {
|
|
186
|
+
const data = await response.json();
|
|
187
|
+
console.log("Success!", data);
|
|
188
|
+
}
|
|
116
189
|
```
|
|
117
190
|
|
|
118
191
|
---
|
package/dist/Universal.d.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration options for ZionGate.
|
|
3
|
+
*/
|
|
1
4
|
export interface ZionConfig {
|
|
5
|
+
/** Your API key from the Zion Dashboard */
|
|
2
6
|
apiKey: string;
|
|
7
|
+
/** Price per request in USD (e.g., 0.01 for 1 cent) */
|
|
3
8
|
price: number;
|
|
9
|
+
/** Solana network to use */
|
|
4
10
|
network?: "solana-mainnet" | "solana-devnet";
|
|
5
|
-
|
|
11
|
+
/** Resource identifier for analytics (default: "api-access") */
|
|
6
12
|
resource?: string;
|
|
7
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Result from the payment check.
|
|
16
|
+
*/
|
|
8
17
|
export interface CheckResult {
|
|
9
18
|
authorized: boolean;
|
|
10
19
|
error?: {
|
|
@@ -14,6 +23,9 @@ export interface CheckResult {
|
|
|
14
23
|
success?: boolean;
|
|
15
24
|
verification?: VerifyResponse;
|
|
16
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Response from the Facilitator's verify endpoint.
|
|
28
|
+
*/
|
|
17
29
|
export interface VerifyResponse {
|
|
18
30
|
valid: boolean;
|
|
19
31
|
invalidReason?: {
|
|
@@ -26,6 +38,9 @@ export interface VerifyResponse {
|
|
|
26
38
|
confirmedAt: string;
|
|
27
39
|
};
|
|
28
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Response from the Facilitator's settle endpoint.
|
|
43
|
+
*/
|
|
29
44
|
export interface SettleResponse {
|
|
30
45
|
success: boolean;
|
|
31
46
|
error?: {
|
|
@@ -45,15 +60,27 @@ export interface SettleResponse {
|
|
|
45
60
|
settledAt: string;
|
|
46
61
|
};
|
|
47
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Network configuration for Solana mainnet and devnet.
|
|
65
|
+
* Contains treasury addresses, USDC mint addresses, and facilitator URLs.
|
|
66
|
+
*/
|
|
48
67
|
export declare const NETWORKS: {
|
|
49
|
-
"solana-mainnet": {
|
|
50
|
-
treasury
|
|
51
|
-
|
|
52
|
-
|
|
68
|
+
readonly "solana-mainnet": {
|
|
69
|
+
/** Zion treasury wallet for fee collection */
|
|
70
|
+
readonly treasury: "AgH4Eq3JYBpEt5aPgCnZsygf9tnQ5D2qMKH3eJxB5rm8";
|
|
71
|
+
/** USDC SPL Token mint on mainnet */
|
|
72
|
+
readonly usdcMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
73
|
+
/** Zion Facilitator API URL */
|
|
74
|
+
readonly facilitator: "https://zion-x402-facilitator-production.up.railway.app/v1";
|
|
53
75
|
};
|
|
54
|
-
"solana-devnet": {
|
|
55
|
-
treasury
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
readonly "solana-devnet": {
|
|
77
|
+
/** Zion treasury wallet for fee collection */
|
|
78
|
+
readonly treasury: "AgH4Eq3JYBpEt5aPgCnZsygf9tnQ5D2qMKH3eJxB5rm8";
|
|
79
|
+
/** USDC SPL Token mint on devnet */
|
|
80
|
+
readonly usdcMint: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU";
|
|
81
|
+
/** Zion Facilitator API URL */
|
|
82
|
+
readonly facilitator: "https://zion-x402-facilitator-production.up.railway.app/v1";
|
|
58
83
|
};
|
|
59
84
|
};
|
|
85
|
+
/** Type for supported network names */
|
|
86
|
+
export type NetworkName = keyof typeof NETWORKS;
|
package/dist/Universal.js
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NETWORKS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Network configuration for Solana mainnet and devnet.
|
|
6
|
+
* Contains treasury addresses, USDC mint addresses, and facilitator URLs.
|
|
7
|
+
*/
|
|
4
8
|
exports.NETWORKS = {
|
|
5
9
|
"solana-mainnet": {
|
|
10
|
+
/** Zion treasury wallet for fee collection */
|
|
6
11
|
treasury: "AgH4Eq3JYBpEt5aPgCnZsygf9tnQ5D2qMKH3eJxB5rm8",
|
|
12
|
+
/** USDC SPL Token mint on mainnet */
|
|
7
13
|
usdcMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
14
|
+
/** Zion Facilitator API URL */
|
|
8
15
|
facilitator: "https://zion-x402-facilitator-production.up.railway.app/v1"
|
|
9
16
|
},
|
|
10
17
|
"solana-devnet": {
|
|
18
|
+
/** Zion treasury wallet for fee collection */
|
|
11
19
|
treasury: "AgH4Eq3JYBpEt5aPgCnZsygf9tnQ5D2qMKH3eJxB5rm8",
|
|
20
|
+
/** USDC SPL Token mint on devnet */
|
|
12
21
|
usdcMint: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
|
|
22
|
+
/** Zion Facilitator API URL */
|
|
13
23
|
facilitator: "https://zion-x402-facilitator-production.up.railway.app/v1"
|
|
14
24
|
}
|
|
15
25
|
};
|
package/dist/ZionGate.d.ts
CHANGED
|
@@ -1,35 +1,76 @@
|
|
|
1
1
|
import { ZionConfig, CheckResult } from "./Universal";
|
|
2
|
+
/**
|
|
3
|
+
* ZionGate - Server-side SDK for protecting API routes with x402 payments.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* const zion = new ZionGate({
|
|
8
|
+
* apiKey: "your_api_key",
|
|
9
|
+
* price: 0.01,
|
|
10
|
+
* network: "solana-devnet"
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* // Express
|
|
14
|
+
* app.get("/api", zion.express(), (req, res) => res.json({ data: "paid content" }));
|
|
15
|
+
*
|
|
16
|
+
* // Next.js
|
|
17
|
+
* const auth = await zion.nextServer(req);
|
|
18
|
+
* if (auth !== true) return auth;
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
2
21
|
export declare class ZionGate {
|
|
3
|
-
private static instance;
|
|
4
22
|
private config;
|
|
5
23
|
private api;
|
|
6
24
|
private developerWallet;
|
|
7
25
|
private isInitialized;
|
|
26
|
+
/**
|
|
27
|
+
* Create a new ZionGate instance.
|
|
28
|
+
* @param config - Configuration options
|
|
29
|
+
* @throws Error if price is not positive
|
|
30
|
+
*/
|
|
8
31
|
constructor(config: ZionConfig);
|
|
9
32
|
/**
|
|
10
33
|
* Initialize the SDK by fetching the developer's wallet address from the Facilitator.
|
|
11
|
-
* This is
|
|
12
|
-
*
|
|
34
|
+
* This is called automatically on first request, but can be called manually.
|
|
35
|
+
* Includes retry logic for transient failures.
|
|
36
|
+
*
|
|
37
|
+
* @param retries - Number of retry attempts (default: 3)
|
|
38
|
+
* @param delayMs - Delay between retries in ms (default: 1000)
|
|
13
39
|
*/
|
|
14
|
-
init(): Promise<void>;
|
|
40
|
+
init(retries?: number, delayMs?: number): Promise<void>;
|
|
15
41
|
/**
|
|
16
|
-
* Core
|
|
42
|
+
* Core payment verification logic. Framework-agnostic.
|
|
43
|
+
* @param headers - Request headers object
|
|
44
|
+
* @returns CheckResult indicating if request is authorized
|
|
17
45
|
*/
|
|
18
46
|
check(headers: Record<string, string | undefined>): Promise<CheckResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Generate a 402 Payment Required response with all payment details.
|
|
49
|
+
*/
|
|
19
50
|
private create402Response;
|
|
20
51
|
/**
|
|
21
|
-
* Express
|
|
52
|
+
* Express.js middleware adapter.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* app.get("/api/premium", zion.express(), (req, res) => {
|
|
57
|
+
* res.json({ data: "Premium content" });
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
22
60
|
*/
|
|
23
61
|
express(): (req: any, res: any, next: any) => Promise<any>;
|
|
24
62
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
63
|
+
* Next.js App Router helper.
|
|
64
|
+
* Returns `true` if authorized, or a Response object to return if not.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* export async function GET(req: Request) {
|
|
69
|
+
* const auth = await zion.nextServer(req);
|
|
70
|
+
* if (auth !== true) return auth;
|
|
71
|
+
* return Response.json({ data: "Premium content" });
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
33
74
|
*/
|
|
34
75
|
nextServer(req: Request): Promise<true | Response>;
|
|
35
76
|
}
|
package/dist/ZionGate.js
CHANGED
|
@@ -6,45 +6,87 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.ZionGate = void 0;
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const Universal_1 = require("./Universal");
|
|
9
|
+
/**
|
|
10
|
+
* ZionGate - Server-side SDK for protecting API routes with x402 payments.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const zion = new ZionGate({
|
|
15
|
+
* apiKey: "your_api_key",
|
|
16
|
+
* price: 0.01,
|
|
17
|
+
* network: "solana-devnet"
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Express
|
|
21
|
+
* app.get("/api", zion.express(), (req, res) => res.json({ data: "paid content" }));
|
|
22
|
+
*
|
|
23
|
+
* // Next.js
|
|
24
|
+
* const auth = await zion.nextServer(req);
|
|
25
|
+
* if (auth !== true) return auth;
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
9
28
|
class ZionGate {
|
|
29
|
+
/**
|
|
30
|
+
* Create a new ZionGate instance.
|
|
31
|
+
* @param config - Configuration options
|
|
32
|
+
* @throws Error if price is not positive
|
|
33
|
+
*/
|
|
10
34
|
constructor(config) {
|
|
11
35
|
this.developerWallet = null;
|
|
12
36
|
this.isInitialized = false;
|
|
37
|
+
// Validate price
|
|
38
|
+
if (!config.price || config.price <= 0) {
|
|
39
|
+
throw new Error("ZionGate: Price must be a positive number");
|
|
40
|
+
}
|
|
13
41
|
this.config = config;
|
|
14
42
|
const defaults = Universal_1.NETWORKS[config.network || "solana-mainnet"];
|
|
15
43
|
this.api = axios_1.default.create({
|
|
16
|
-
baseURL:
|
|
44
|
+
baseURL: defaults.facilitator,
|
|
17
45
|
headers: {
|
|
18
46
|
"X-API-KEY": config.apiKey,
|
|
19
47
|
"Content-Type": "application/json"
|
|
20
|
-
}
|
|
48
|
+
},
|
|
49
|
+
timeout: 10000 // 10 second timeout
|
|
21
50
|
});
|
|
22
51
|
}
|
|
23
52
|
/**
|
|
24
53
|
* Initialize the SDK by fetching the developer's wallet address from the Facilitator.
|
|
25
|
-
* This is
|
|
26
|
-
*
|
|
54
|
+
* This is called automatically on first request, but can be called manually.
|
|
55
|
+
* Includes retry logic for transient failures.
|
|
56
|
+
*
|
|
57
|
+
* @param retries - Number of retry attempts (default: 3)
|
|
58
|
+
* @param delayMs - Delay between retries in ms (default: 1000)
|
|
27
59
|
*/
|
|
28
|
-
async init() {
|
|
60
|
+
async init(retries = 3, delayMs = 1000) {
|
|
29
61
|
if (this.isInitialized)
|
|
30
62
|
return;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
63
|
+
let lastError = null;
|
|
64
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
65
|
+
try {
|
|
66
|
+
const res = await this.api.get("/wallet");
|
|
67
|
+
if (res.data && res.data.address) {
|
|
68
|
+
this.developerWallet = res.data.address;
|
|
69
|
+
this.isInitialized = true;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new Error("Invalid response from Facilitator wallet endpoint");
|
|
74
|
+
}
|
|
36
75
|
}
|
|
37
|
-
|
|
38
|
-
|
|
76
|
+
catch (error) {
|
|
77
|
+
lastError = error;
|
|
78
|
+
console.warn(`ZionGate init attempt ${attempt}/${retries} failed:`, error.message);
|
|
79
|
+
if (attempt < retries) {
|
|
80
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
81
|
+
}
|
|
39
82
|
}
|
|
40
83
|
}
|
|
41
|
-
|
|
42
|
-
console.error("ZionGate Init Failed:", error.message);
|
|
43
|
-
throw new Error("Failed to initialize ZionGate: Could not fetch developer wallet.");
|
|
44
|
-
}
|
|
84
|
+
throw new Error(`ZionGate: Failed to initialize after ${retries} attempts. ${lastError?.message}`);
|
|
45
85
|
}
|
|
46
86
|
/**
|
|
47
|
-
* Core
|
|
87
|
+
* Core payment verification logic. Framework-agnostic.
|
|
88
|
+
* @param headers - Request headers object
|
|
89
|
+
* @returns CheckResult indicating if request is authorized
|
|
48
90
|
*/
|
|
49
91
|
async check(headers) {
|
|
50
92
|
if (!this.isInitialized) {
|
|
@@ -60,7 +102,7 @@ class ZionGate {
|
|
|
60
102
|
try {
|
|
61
103
|
const atomicAmount = BigInt(Math.floor(this.config.price * 1000000)).toString();
|
|
62
104
|
const defaults = Universal_1.NETWORKS[this.config.network || "solana-mainnet"];
|
|
63
|
-
const verification = await this.api.post("/
|
|
105
|
+
const verification = await this.api.post("/verify", {
|
|
64
106
|
paymentHeader: token,
|
|
65
107
|
paymentRequirements: {
|
|
66
108
|
recipient: this.developerWallet,
|
|
@@ -83,14 +125,14 @@ class ZionGate {
|
|
|
83
125
|
};
|
|
84
126
|
}
|
|
85
127
|
// 3. Settle
|
|
86
|
-
const settlement = await this.api.post("/
|
|
128
|
+
const settlement = await this.api.post("/settle", {
|
|
87
129
|
paymentHeader: token,
|
|
88
130
|
paymentRequirements: {
|
|
89
131
|
recipient: this.developerWallet,
|
|
90
132
|
amount: atomicAmount,
|
|
91
133
|
asset: defaults.usdcMint,
|
|
92
134
|
network: this.config.network || "solana-mainnet",
|
|
93
|
-
resource: "api-access"
|
|
135
|
+
resource: this.config.resource || "api-access"
|
|
94
136
|
}
|
|
95
137
|
});
|
|
96
138
|
if (!settlement.data || !settlement.data.success) {
|
|
@@ -109,7 +151,7 @@ class ZionGate {
|
|
|
109
151
|
return {
|
|
110
152
|
authorized: false,
|
|
111
153
|
error: {
|
|
112
|
-
status: err.response.status === 400 ? 402 : err.response.status,
|
|
154
|
+
status: err.response.status === 400 ? 402 : err.response.status,
|
|
113
155
|
body: err.response.data || { error: "Payment Validation Failed" }
|
|
114
156
|
}
|
|
115
157
|
};
|
|
@@ -123,6 +165,9 @@ class ZionGate {
|
|
|
123
165
|
};
|
|
124
166
|
}
|
|
125
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Generate a 402 Payment Required response with all payment details.
|
|
170
|
+
*/
|
|
126
171
|
create402Response() {
|
|
127
172
|
const defaults = Universal_1.NETWORKS[this.config.network || "solana-mainnet"];
|
|
128
173
|
const atomicAmount = BigInt(Math.floor(this.config.price * 1000000)).toString();
|
|
@@ -135,15 +180,23 @@ class ZionGate {
|
|
|
135
180
|
amount: atomicAmount,
|
|
136
181
|
asset: defaults.usdcMint,
|
|
137
182
|
treasury: defaults.treasury,
|
|
183
|
+
network: this.config.network || "solana-mainnet",
|
|
138
184
|
feeBps: 100, // 1%
|
|
139
185
|
message: "Payment Required. Split transaction: 99% to recipient, 1% to treasury."
|
|
140
186
|
}
|
|
141
187
|
}
|
|
142
188
|
};
|
|
143
189
|
}
|
|
144
|
-
// Adapters
|
|
190
|
+
// ==================== Framework Adapters ====================
|
|
145
191
|
/**
|
|
146
|
-
* Express
|
|
192
|
+
* Express.js middleware adapter.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* app.get("/api/premium", zion.express(), (req, res) => {
|
|
197
|
+
* res.json({ data: "Premium content" });
|
|
198
|
+
* });
|
|
199
|
+
* ```
|
|
147
200
|
*/
|
|
148
201
|
express() {
|
|
149
202
|
return async (req, res, next) => {
|
|
@@ -155,17 +208,19 @@ class ZionGate {
|
|
|
155
208
|
};
|
|
156
209
|
}
|
|
157
210
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
211
|
+
* Next.js App Router helper.
|
|
212
|
+
* Returns `true` if authorized, or a Response object to return if not.
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* export async function GET(req: Request) {
|
|
217
|
+
* const auth = await zion.nextServer(req);
|
|
218
|
+
* if (auth !== true) return auth;
|
|
219
|
+
* return Response.json({ data: "Premium content" });
|
|
220
|
+
* }
|
|
221
|
+
* ```
|
|
166
222
|
*/
|
|
167
223
|
async nextServer(req) {
|
|
168
|
-
// Convert Request headers to Record<string, string>
|
|
169
224
|
const headers = {};
|
|
170
225
|
req.headers.forEach((v, k) => (headers[k] = v));
|
|
171
226
|
const result = await this.check(headers);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,48 @@
|
|
|
1
1
|
export * from "./Universal";
|
|
2
2
|
export * from "./ZionGate";
|
|
3
3
|
import { Connection } from "@solana/web3.js";
|
|
4
|
+
/**
|
|
5
|
+
* Payment requirements returned in a 402 response.
|
|
6
|
+
*/
|
|
4
7
|
export interface PaymentRequirements {
|
|
5
8
|
recipient: string;
|
|
6
9
|
amount: string;
|
|
7
10
|
asset: string;
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
treasury: string;
|
|
12
|
+
network: string;
|
|
13
|
+
feeBps: number;
|
|
10
14
|
}
|
|
11
15
|
/**
|
|
12
|
-
*
|
|
16
|
+
* PaymentBuilder - Client-side utilities for AI Agents and wallets.
|
|
17
|
+
* Provides methods to create payment transactions and headers.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Create atomic split instructions
|
|
22
|
+
* const instructions = await PaymentBuilder.createAtomicSplitInstructions({
|
|
23
|
+
* sender: wallet.publicKey.toBase58(),
|
|
24
|
+
* recipient: requirements.recipient,
|
|
25
|
+
* treasury: requirements.treasury,
|
|
26
|
+
* amount: requirements.amount,
|
|
27
|
+
* asset: requirements.asset,
|
|
28
|
+
* connection
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* // Create payment header after transaction
|
|
32
|
+
* const header = PaymentBuilder.createHeader({
|
|
33
|
+
* signature: txSignature,
|
|
34
|
+
* sender: wallet.publicKey.toBase58(),
|
|
35
|
+
* ...requirements
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
13
38
|
*/
|
|
14
39
|
export declare class PaymentBuilder {
|
|
40
|
+
/**
|
|
41
|
+
* Create the Base64-encoded payment header for the Authorization header.
|
|
42
|
+
*
|
|
43
|
+
* @param payload - Payment details including signature and sender info
|
|
44
|
+
* @returns Base64-encoded payment header string
|
|
45
|
+
*/
|
|
15
46
|
static createHeader(payload: {
|
|
16
47
|
signature: string;
|
|
17
48
|
sender: string;
|
|
@@ -23,14 +54,39 @@ export declare class PaymentBuilder {
|
|
|
23
54
|
network?: string;
|
|
24
55
|
}): string;
|
|
25
56
|
/**
|
|
26
|
-
* Create
|
|
57
|
+
* Create transfer instructions for an atomic split payment.
|
|
58
|
+
* Splits the payment: 99% to developer, 1% to Zion treasury.
|
|
59
|
+
*
|
|
60
|
+
* @param config - Configuration for the split transfer
|
|
61
|
+
* @returns Array of transfer instructions to add to a transaction
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* const instructions = await PaymentBuilder.createAtomicSplitInstructions({
|
|
66
|
+
* sender: publicKey.toBase58(),
|
|
67
|
+
* recipient: "DeveloperWalletAddress",
|
|
68
|
+
* treasury: "ZionTreasuryAddress",
|
|
69
|
+
* amount: "100000", // 0.1 USDC in atomic units
|
|
70
|
+
* asset: "USDCMintAddress",
|
|
71
|
+
* connection
|
|
72
|
+
* });
|
|
73
|
+
*
|
|
74
|
+
* const tx = new Transaction();
|
|
75
|
+
* tx.add(...instructions);
|
|
76
|
+
* ```
|
|
27
77
|
*/
|
|
28
78
|
static createAtomicSplitInstructions(config: {
|
|
79
|
+
/** Sender's wallet address */
|
|
29
80
|
sender: string;
|
|
81
|
+
/** Developer's wallet address (receives 99%) */
|
|
30
82
|
recipient: string;
|
|
83
|
+
/** Zion treasury address (receives 1%) */
|
|
31
84
|
treasury: string;
|
|
85
|
+
/** Total amount in atomic units */
|
|
32
86
|
amount: string;
|
|
87
|
+
/** Token mint address (USDC) */
|
|
33
88
|
asset: string;
|
|
89
|
+
/** Solana connection instance */
|
|
34
90
|
connection: Connection;
|
|
35
91
|
}): Promise<import("@solana/web3.js").TransactionInstruction[]>;
|
|
36
92
|
}
|
package/dist/index.js
CHANGED
|
@@ -41,9 +41,36 @@ __exportStar(require("./Universal"), exports);
|
|
|
41
41
|
__exportStar(require("./ZionGate"), exports);
|
|
42
42
|
const web3_js_1 = require("@solana/web3.js");
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
44
|
+
* PaymentBuilder - Client-side utilities for AI Agents and wallets.
|
|
45
|
+
* Provides methods to create payment transactions and headers.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* // Create atomic split instructions
|
|
50
|
+
* const instructions = await PaymentBuilder.createAtomicSplitInstructions({
|
|
51
|
+
* sender: wallet.publicKey.toBase58(),
|
|
52
|
+
* recipient: requirements.recipient,
|
|
53
|
+
* treasury: requirements.treasury,
|
|
54
|
+
* amount: requirements.amount,
|
|
55
|
+
* asset: requirements.asset,
|
|
56
|
+
* connection
|
|
57
|
+
* });
|
|
58
|
+
*
|
|
59
|
+
* // Create payment header after transaction
|
|
60
|
+
* const header = PaymentBuilder.createHeader({
|
|
61
|
+
* signature: txSignature,
|
|
62
|
+
* sender: wallet.publicKey.toBase58(),
|
|
63
|
+
* ...requirements
|
|
64
|
+
* });
|
|
65
|
+
* ```
|
|
45
66
|
*/
|
|
46
67
|
class PaymentBuilder {
|
|
68
|
+
/**
|
|
69
|
+
* Create the Base64-encoded payment header for the Authorization header.
|
|
70
|
+
*
|
|
71
|
+
* @param payload - Payment details including signature and sender info
|
|
72
|
+
* @returns Base64-encoded payment header string
|
|
73
|
+
*/
|
|
47
74
|
static createHeader(payload) {
|
|
48
75
|
const json = {
|
|
49
76
|
x402Version: 1,
|
|
@@ -60,7 +87,26 @@ class PaymentBuilder {
|
|
|
60
87
|
}
|
|
61
88
|
}
|
|
62
89
|
/**
|
|
63
|
-
* Create
|
|
90
|
+
* Create transfer instructions for an atomic split payment.
|
|
91
|
+
* Splits the payment: 99% to developer, 1% to Zion treasury.
|
|
92
|
+
*
|
|
93
|
+
* @param config - Configuration for the split transfer
|
|
94
|
+
* @returns Array of transfer instructions to add to a transaction
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const instructions = await PaymentBuilder.createAtomicSplitInstructions({
|
|
99
|
+
* sender: publicKey.toBase58(),
|
|
100
|
+
* recipient: "DeveloperWalletAddress",
|
|
101
|
+
* treasury: "ZionTreasuryAddress",
|
|
102
|
+
* amount: "100000", // 0.1 USDC in atomic units
|
|
103
|
+
* asset: "USDCMintAddress",
|
|
104
|
+
* connection
|
|
105
|
+
* });
|
|
106
|
+
*
|
|
107
|
+
* const tx = new Transaction();
|
|
108
|
+
* tx.add(...instructions);
|
|
109
|
+
* ```
|
|
64
110
|
*/
|
|
65
111
|
static async createAtomicSplitInstructions(config) {
|
|
66
112
|
const { getAssociatedTokenAddress, createTransferInstruction } = await Promise.resolve().then(() => __importStar(require("@solana/spl-token")));
|
|
@@ -71,7 +117,7 @@ class PaymentBuilder {
|
|
|
71
117
|
const recipientPubkey = new web3_js_1.PublicKey(config.recipient);
|
|
72
118
|
const treasuryPubkey = new web3_js_1.PublicKey(config.treasury);
|
|
73
119
|
const mintPubkey = new web3_js_1.PublicKey(config.asset);
|
|
74
|
-
// Get
|
|
120
|
+
// Get Associated Token Addresses
|
|
75
121
|
const senderAta = await getAssociatedTokenAddress(mintPubkey, senderPubkey);
|
|
76
122
|
const recipientAta = await getAssociatedTokenAddress(mintPubkey, recipientPubkey);
|
|
77
123
|
const treasuryAta = await getAssociatedTokenAddress(mintPubkey, treasuryPubkey);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziongateway/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "TypeScript SDK for Zion x402 Facilitator",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
"express": "^5.2.1",
|
|
34
34
|
"typescript": "^5.0.0"
|
|
35
35
|
},
|
|
36
|
-
"files": [
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"README.md"
|
|
39
|
+
],
|
|
37
40
|
"homepage": "https://docs.ziongateway.xyz"
|
|
38
41
|
}
|