@agenticocean/x402-stellar 1.0.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/README.md +148 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +46 -0
- package/dist/config.js.map +1 -0
- package/dist/facilitator.d.ts +25 -0
- package/dist/facilitator.d.ts.map +1 -0
- package/dist/facilitator.js +102 -0
- package/dist/facilitator.js.map +1 -0
- package/dist/header-builder.d.ts +27 -0
- package/dist/header-builder.d.ts.map +1 -0
- package/dist/header-builder.js +62 -0
- package/dist/header-builder.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +27 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +77 -0
- package/dist/middleware.js.map +1 -0
- package/dist/stellar-client.d.ts +19 -0
- package/dist/stellar-client.d.ts.map +1 -0
- package/dist/stellar-client.js +27 -0
- package/dist/stellar-client.js.map +1 -0
- package/dist/stellar-tx.d.ts +18 -0
- package/dist/stellar-tx.d.ts.map +1 -0
- package/dist/stellar-tx.js +45 -0
- package/dist/stellar-tx.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# @agentsea/x402-stellar
|
|
2
|
+
|
|
3
|
+
x402 payment protocol for Stellar — header builder, facilitator, and Express middleware for AI agent micropayments.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @agentsea/x402-stellar
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @agentsea/x402-stellar
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### 1. Build an x402 Payment Header (Agent side)
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { buildX402Header } from "@agentsea/x402-stellar";
|
|
19
|
+
|
|
20
|
+
const header = await buildX402Header({
|
|
21
|
+
rpcUrl: "https://soroban-testnet.stellar.org",
|
|
22
|
+
networkPassphrase: "Test SDF Network ; September 2015",
|
|
23
|
+
vaultContract: "CVAULT...",
|
|
24
|
+
agentSigner: "GAGENT...",
|
|
25
|
+
agentSecret: "SAGENT_SECRET...",
|
|
26
|
+
payTo: "GFACILITATOR...",
|
|
27
|
+
amount: "100000", // 0.01 USDC in stroops
|
|
28
|
+
memo: "yield_query_v1",
|
|
29
|
+
agentId: 1,
|
|
30
|
+
usdcAddress: "CUSDC...",
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Use in API request
|
|
34
|
+
const response = await fetch("https://api.example.com/yield/query", {
|
|
35
|
+
headers: { "X-PAYMENT": header },
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Gate your API with x402 Middleware (Vendor side)
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import express from "express";
|
|
43
|
+
import { createX402Middleware } from "@agentsea/x402-stellar";
|
|
44
|
+
|
|
45
|
+
const app = express();
|
|
46
|
+
|
|
47
|
+
const x402 = createX402Middleware({
|
|
48
|
+
rpcUrl: "https://soroban-testnet.stellar.org",
|
|
49
|
+
horizonUrl: "https://horizon-testnet.stellar.org",
|
|
50
|
+
networkPassphrase: "Test SDF Network ; September 2015",
|
|
51
|
+
facilitatorSecret: process.env.FACILITATOR_SECRET!,
|
|
52
|
+
usdcAddress: "CUSDC...",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Gate a route — returns 402 if unpaid, 200 if paid
|
|
56
|
+
app.get("/premium-data", x402({ price: "100000", description: "Premium AI data" }), (req, res) => {
|
|
57
|
+
res.json({ data: "...", payment: req.x402 });
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
app.listen(3001);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 3. Settle a Payment (Facilitator side)
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { settlePayment } from "@agentsea/x402-stellar";
|
|
67
|
+
|
|
68
|
+
const result = await settlePayment(paymentPayload, {
|
|
69
|
+
rpcUrl: "https://soroban-testnet.stellar.org",
|
|
70
|
+
horizonUrl: "https://horizon-testnet.stellar.org",
|
|
71
|
+
networkPassphrase: "Test SDF Network ; September 2015",
|
|
72
|
+
facilitatorSecret: process.env.FACILITATOR_SECRET!,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
console.log(result.success, result.txHash);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## API Reference
|
|
79
|
+
|
|
80
|
+
### `buildX402Header(params)`
|
|
81
|
+
|
|
82
|
+
Builds a base64-encoded x402 payment header. Signs a `vault.agent_pay()` invocation with the agent's key.
|
|
83
|
+
|
|
84
|
+
| Param | Type | Description |
|
|
85
|
+
|-------|------|-------------|
|
|
86
|
+
| `rpcUrl` | `string` | Soroban RPC endpoint |
|
|
87
|
+
| `networkPassphrase` | `string` | Network passphrase |
|
|
88
|
+
| `vaultContract` | `string` | User vault contract address |
|
|
89
|
+
| `agentSigner` | `string` | Agent's public key |
|
|
90
|
+
| `agentSecret` | `string` | Agent's secret key (for signing auth entry) |
|
|
91
|
+
| `payTo` | `string` | Facilitator's public key (payment destination) |
|
|
92
|
+
| `amount` | `string` | Amount in stroops (7 decimals) |
|
|
93
|
+
| `memo` | `string` | Audit memo |
|
|
94
|
+
| `agentId` | `number` | Agent's registry ID |
|
|
95
|
+
| `usdcAddress` | `string` | USDC SAC contract address |
|
|
96
|
+
|
|
97
|
+
### `createX402Middleware(options)`
|
|
98
|
+
|
|
99
|
+
Returns an Express middleware factory. Call with route config to create per-route middleware.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const x402 = createX402Middleware({ ...options });
|
|
103
|
+
|
|
104
|
+
// returns middleware:
|
|
105
|
+
x402({ price: "100000", description: "..." })
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `settlePayment(payload, options)`
|
|
109
|
+
|
|
110
|
+
Verifies and executes payment on-chain. Returns `{ success, txHash?, error? }`.
|
|
111
|
+
|
|
112
|
+
### `formatUsdc(stroops)`
|
|
113
|
+
|
|
114
|
+
Convert stroops to human-readable USDC string.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
formatUsdc("100000") // → "0.01"
|
|
118
|
+
formatUsdc(10_000_000n) // → "1.00"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### `toStroops(usdc)`
|
|
122
|
+
|
|
123
|
+
Convert USDC amount to stroops (bigint).
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
toStroops(0.01) // → 100000n
|
|
127
|
+
toStroops(5) // → 50000000n
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Network Config
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { TESTNET, MAINNET } from "@agentsea/x402-stellar";
|
|
134
|
+
|
|
135
|
+
// TESTNET: soroban-testnet.stellar.org
|
|
136
|
+
// MAINNET: soroban.stellar.org
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Stellar USDC Decimals
|
|
140
|
+
|
|
141
|
+
**Important**: Stellar USDC uses 7 decimal places (not 6 like EVM).
|
|
142
|
+
|
|
143
|
+
- `1 USDC = 10,000,000 stroops`
|
|
144
|
+
- `0.01 USDC = 100,000 stroops`
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT — StellarAgent402
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface StellarNetworkConfig {
|
|
2
|
+
rpcUrl: string;
|
|
3
|
+
horizonUrl: string;
|
|
4
|
+
networkPassphrase: string;
|
|
5
|
+
friendbotUrl?: string;
|
|
6
|
+
explorerUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const TESTNET: StellarNetworkConfig;
|
|
9
|
+
export declare const MAINNET: StellarNetworkConfig;
|
|
10
|
+
export declare const STELLAR_CONFIG: {
|
|
11
|
+
readonly testnet: {
|
|
12
|
+
readonly rpcUrl: string;
|
|
13
|
+
readonly horizonUrl: string;
|
|
14
|
+
readonly networkPassphrase: string;
|
|
15
|
+
readonly friendbotUrl: string;
|
|
16
|
+
readonly explorerUrl: string;
|
|
17
|
+
};
|
|
18
|
+
readonly mainnet: {
|
|
19
|
+
readonly rpcUrl: string;
|
|
20
|
+
readonly horizonUrl: string;
|
|
21
|
+
readonly networkPassphrase: string;
|
|
22
|
+
readonly friendbotUrl: "";
|
|
23
|
+
readonly explorerUrl: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export type StellarNetwork = keyof typeof STELLAR_CONFIG;
|
|
27
|
+
export declare const USDC_DECIMALS = 7;
|
|
28
|
+
export declare const STROOPS_PER_USDC = 10000000;
|
|
29
|
+
export declare function formatUsdc(stroops: string | number | bigint): string;
|
|
30
|
+
export declare function toStroops(usdc: number): bigint;
|
|
31
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,OAAO,EAAE,oBAMrB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,oBAKrB,CAAC;AAEF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;CAejB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,cAAc,CAAC;AAIzD,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,gBAAgB,WAAa,CAAC;AAI3C,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAOpE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// ── Stellar Network Configuration ──
|
|
2
|
+
export const TESTNET = {
|
|
3
|
+
rpcUrl: "https://soroban-testnet.stellar.org",
|
|
4
|
+
horizonUrl: "https://horizon-testnet.stellar.org",
|
|
5
|
+
networkPassphrase: "Test SDF Network ; September 2015",
|
|
6
|
+
friendbotUrl: "https://friendbot.stellar.org",
|
|
7
|
+
explorerUrl: "https://stellar.expert/explorer/testnet",
|
|
8
|
+
};
|
|
9
|
+
export const MAINNET = {
|
|
10
|
+
rpcUrl: "https://soroban.stellar.org",
|
|
11
|
+
horizonUrl: "https://horizon.stellar.org",
|
|
12
|
+
networkPassphrase: "Public Global Stellar Network ; September 2015",
|
|
13
|
+
explorerUrl: "https://stellar.expert/explorer/public",
|
|
14
|
+
};
|
|
15
|
+
export const STELLAR_CONFIG = {
|
|
16
|
+
testnet: {
|
|
17
|
+
rpcUrl: TESTNET.rpcUrl,
|
|
18
|
+
horizonUrl: TESTNET.horizonUrl,
|
|
19
|
+
networkPassphrase: TESTNET.networkPassphrase,
|
|
20
|
+
friendbotUrl: TESTNET.friendbotUrl,
|
|
21
|
+
explorerUrl: TESTNET.explorerUrl,
|
|
22
|
+
},
|
|
23
|
+
mainnet: {
|
|
24
|
+
rpcUrl: MAINNET.rpcUrl,
|
|
25
|
+
horizonUrl: MAINNET.horizonUrl,
|
|
26
|
+
networkPassphrase: MAINNET.networkPassphrase,
|
|
27
|
+
friendbotUrl: "",
|
|
28
|
+
explorerUrl: MAINNET.explorerUrl,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
// ── USDC Constants ──
|
|
32
|
+
export const USDC_DECIMALS = 7;
|
|
33
|
+
export const STROOPS_PER_USDC = 10_000_000;
|
|
34
|
+
// ── Utility Functions ──
|
|
35
|
+
export function formatUsdc(stroops) {
|
|
36
|
+
const amount = typeof stroops === "bigint"
|
|
37
|
+
? Number(stroops)
|
|
38
|
+
: typeof stroops === "string"
|
|
39
|
+
? parseInt(stroops)
|
|
40
|
+
: stroops;
|
|
41
|
+
return (amount / STROOPS_PER_USDC).toFixed(2);
|
|
42
|
+
}
|
|
43
|
+
export function toStroops(usdc) {
|
|
44
|
+
return BigInt(Math.round(usdc * STROOPS_PER_USDC));
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAUtC,MAAM,CAAC,MAAM,OAAO,GAAyB;IAC3C,MAAM,EAAE,qCAAqC;IAC7C,UAAU,EAAE,qCAAqC;IACjD,iBAAiB,EAAE,mCAAmC;IACtD,YAAY,EAAE,+BAA+B;IAC7C,WAAW,EAAE,yCAAyC;CACvD,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAyB;IAC3C,MAAM,EAAE,6BAA6B;IACrC,UAAU,EAAE,6BAA6B;IACzC,iBAAiB,EAAE,gDAAgD;IACnE,WAAW,EAAE,wCAAwC;CACtD,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE;QACP,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,YAAY,EAAE,OAAO,CAAC,YAAa;QACnC,WAAW,EAAE,OAAO,CAAC,WAAY;KAClC;IACD,OAAO,EAAE;QACP,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,YAAY,EAAE,EAAE;QAChB,WAAW,EAAE,OAAO,CAAC,WAAY;KAClC;CACO,CAAC;AAIX,uBAAuB;AAEvB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAE3C,0BAA0B;AAE1B,MAAM,UAAU,UAAU,CAAC,OAAiC;IAC1D,MAAM,MAAM,GAAG,OAAO,OAAO,KAAK,QAAQ;QACxC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QACjB,CAAC,CAAC,OAAO,OAAO,KAAK,QAAQ;YAC3B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;YACnB,CAAC,CAAC,OAAO,CAAC;IACd,OAAO,CAAC,MAAM,GAAG,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,gBAAgB,CAAC,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PaymentPayload, SettlementResult, LoggerLike } from "./types.js";
|
|
2
|
+
export interface SettlementOptions {
|
|
3
|
+
rpcUrl: string;
|
|
4
|
+
horizonUrl: string;
|
|
5
|
+
networkPassphrase: string;
|
|
6
|
+
facilitatorSecret: string;
|
|
7
|
+
logger?: LoggerLike;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Settle an x402 payment by submitting the agent's pre-assembled transaction.
|
|
11
|
+
*
|
|
12
|
+
* Flow:
|
|
13
|
+
* 1. If the header includes assembledTxXdr (recommended):
|
|
14
|
+
* - Deserialize the pre-assembled transaction
|
|
15
|
+
* - Sign as facilitator (pays XLM fees)
|
|
16
|
+
* - Submit directly
|
|
17
|
+
*
|
|
18
|
+
* 2. Fallback (legacy, no assembledTxXdr):
|
|
19
|
+
* - Build and simulate our own transaction
|
|
20
|
+
* - Inject the agent's signed auth entry
|
|
21
|
+
* - Assemble, sign, submit
|
|
22
|
+
* (May fail due to auth nonce/footprint mismatch)
|
|
23
|
+
*/
|
|
24
|
+
export declare function settlePayment(payload: PaymentPayload, options: SettlementOptions): Promise<SettlementResult>;
|
|
25
|
+
//# sourceMappingURL=facilitator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../src/facilitator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE/E,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CAoG3B"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Keypair, TransactionBuilder, Contract, nativeToScVal, xdr, } from "@stellar/stellar-sdk";
|
|
2
|
+
import { Server, assembleTransaction } from "@stellar/stellar-sdk/rpc";
|
|
3
|
+
/**
|
|
4
|
+
* Settle an x402 payment by submitting the agent's pre-assembled transaction.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. If the header includes assembledTxXdr (recommended):
|
|
8
|
+
* - Deserialize the pre-assembled transaction
|
|
9
|
+
* - Sign as facilitator (pays XLM fees)
|
|
10
|
+
* - Submit directly
|
|
11
|
+
*
|
|
12
|
+
* 2. Fallback (legacy, no assembledTxXdr):
|
|
13
|
+
* - Build and simulate our own transaction
|
|
14
|
+
* - Inject the agent's signed auth entry
|
|
15
|
+
* - Assemble, sign, submit
|
|
16
|
+
* (May fail due to auth nonce/footprint mismatch)
|
|
17
|
+
*/
|
|
18
|
+
export async function settlePayment(payload, options) {
|
|
19
|
+
const { payload: p } = payload;
|
|
20
|
+
const log = options.logger ?? console;
|
|
21
|
+
const rpc = new Server(options.rpcUrl);
|
|
22
|
+
if (!options.facilitatorSecret) {
|
|
23
|
+
return { success: false, error: "Facilitator key not configured" };
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const facilitator = Keypair.fromSecret(options.facilitatorSecret);
|
|
27
|
+
let assembled;
|
|
28
|
+
if (p.assembledTxXdr) {
|
|
29
|
+
assembled = TransactionBuilder.fromXDR(p.assembledTxXdr, options.networkPassphrase);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const vault = new Contract(p.vaultContract);
|
|
33
|
+
const account = await rpc.getAccount(facilitator.publicKey());
|
|
34
|
+
const tx = new TransactionBuilder(account, {
|
|
35
|
+
fee: "1000000",
|
|
36
|
+
networkPassphrase: options.networkPassphrase,
|
|
37
|
+
})
|
|
38
|
+
.addOperation(vault.call("agent_pay", nativeToScVal(p.agentSigner, { type: "address" }), nativeToScVal(p.payTo, { type: "address" }), nativeToScVal(BigInt(p.amount), { type: "i128" }), nativeToScVal(p.memo, { type: "symbol" })))
|
|
39
|
+
.setTimeout(60)
|
|
40
|
+
.build();
|
|
41
|
+
const sim = await rpc.simulateTransaction(tx);
|
|
42
|
+
if (!("result" in sim)) {
|
|
43
|
+
return { success: false, error: "simulation failed" };
|
|
44
|
+
}
|
|
45
|
+
const signedAuth = xdr.SorobanAuthorizationEntry.fromXDR(p.signedAuthEntry, "base64");
|
|
46
|
+
if (sim.result?.auth) {
|
|
47
|
+
sim.result.auth = [signedAuth];
|
|
48
|
+
}
|
|
49
|
+
assembled = assembleTransaction(tx, sim).build();
|
|
50
|
+
}
|
|
51
|
+
assembled.sign(facilitator);
|
|
52
|
+
const result = await rpc.sendTransaction(assembled);
|
|
53
|
+
if (result.status !== "PENDING") {
|
|
54
|
+
return { success: false, error: `send: ${result.status}` };
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
let txResult = await rpc.getTransaction(result.hash);
|
|
58
|
+
let waited = 0;
|
|
59
|
+
while (txResult.status === "NOT_FOUND" && waited < 30) {
|
|
60
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
61
|
+
txResult = await rpc.getTransaction(result.hash);
|
|
62
|
+
waited++;
|
|
63
|
+
}
|
|
64
|
+
if (txResult.status === "SUCCESS") {
|
|
65
|
+
log.info("x402 settled", { txHash: result.hash, amount: p.amount });
|
|
66
|
+
return { success: true, txHash: result.hash };
|
|
67
|
+
}
|
|
68
|
+
if (txResult.status === "NOT_FOUND") {
|
|
69
|
+
log.warn("x402 tx still pending after 30s", { txHash: result.hash });
|
|
70
|
+
return { success: true, txHash: result.hash };
|
|
71
|
+
}
|
|
72
|
+
return { success: false, error: `tx: ${txResult.status}` };
|
|
73
|
+
}
|
|
74
|
+
catch (pollErr) {
|
|
75
|
+
log.warn("getTransaction parse error, checking Horizon", {
|
|
76
|
+
txHash: result.hash,
|
|
77
|
+
error: pollErr.message,
|
|
78
|
+
});
|
|
79
|
+
try {
|
|
80
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
81
|
+
const horizonResp = await fetch(`${options.horizonUrl}/transactions/${result.hash}`);
|
|
82
|
+
if (horizonResp.ok) {
|
|
83
|
+
const horizonTx = await horizonResp.json();
|
|
84
|
+
if (horizonTx.successful) {
|
|
85
|
+
log.info("x402 settled (Horizon)", { txHash: result.hash, amount: p.amount });
|
|
86
|
+
return { success: true, txHash: result.hash };
|
|
87
|
+
}
|
|
88
|
+
return { success: false, error: `tx failed: ${horizonTx.result_xdr}` };
|
|
89
|
+
}
|
|
90
|
+
log.info("x402 tx submitted", { txHash: result.hash });
|
|
91
|
+
return { success: true, txHash: result.hash };
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return { success: true, txHash: result.hash };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
return { success: false, error: err.message };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=facilitator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facilitator.js","sourceRoot":"","sources":["../src/facilitator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build an X-PAYMENT header for x402 protocol.
|
|
3
|
+
*
|
|
4
|
+
* This is the agent-side function. It:
|
|
5
|
+
* 1. Simulates vault.agent_pay() to get the required SorobanAuthorizationEntry
|
|
6
|
+
* 2. Signs the auth entry with the agent's private key (authorizeEntry)
|
|
7
|
+
* 3. Assembles the full transaction (to capture the correct footprint + resources)
|
|
8
|
+
* 4. Packages the signed auth entry AND assembled transaction XDR
|
|
9
|
+
*
|
|
10
|
+
* CRITICAL: The assembled transaction XDR is included because it contains the
|
|
11
|
+
* footprint with the correct auth nonce. If the facilitator re-simulates, it
|
|
12
|
+
* gets a DIFFERENT nonce, causing an INVOKE_HOST_FUNCTION_TRAPPED error.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildX402Header(params: {
|
|
15
|
+
rpcUrl: string;
|
|
16
|
+
networkPassphrase: string;
|
|
17
|
+
vaultContract: string;
|
|
18
|
+
agentSigner: string;
|
|
19
|
+
agentSecret: string;
|
|
20
|
+
payTo: string;
|
|
21
|
+
amount: string;
|
|
22
|
+
memo: string;
|
|
23
|
+
agentId: number;
|
|
24
|
+
usdcAddress: string;
|
|
25
|
+
facilitatorPublicKey?: string;
|
|
26
|
+
}): Promise<string>;
|
|
27
|
+
//# sourceMappingURL=header-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header-builder.d.ts","sourceRoot":"","sources":["../src/header-builder.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,MAAM,CAAC,CAkElB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Keypair, TransactionBuilder, Contract, nativeToScVal, authorizeEntry, } from "@stellar/stellar-sdk";
|
|
2
|
+
import { Server, assembleTransaction } from "@stellar/stellar-sdk/rpc";
|
|
3
|
+
/**
|
|
4
|
+
* Build an X-PAYMENT header for x402 protocol.
|
|
5
|
+
*
|
|
6
|
+
* This is the agent-side function. It:
|
|
7
|
+
* 1. Simulates vault.agent_pay() to get the required SorobanAuthorizationEntry
|
|
8
|
+
* 2. Signs the auth entry with the agent's private key (authorizeEntry)
|
|
9
|
+
* 3. Assembles the full transaction (to capture the correct footprint + resources)
|
|
10
|
+
* 4. Packages the signed auth entry AND assembled transaction XDR
|
|
11
|
+
*
|
|
12
|
+
* CRITICAL: The assembled transaction XDR is included because it contains the
|
|
13
|
+
* footprint with the correct auth nonce. If the facilitator re-simulates, it
|
|
14
|
+
* gets a DIFFERENT nonce, causing an INVOKE_HOST_FUNCTION_TRAPPED error.
|
|
15
|
+
*/
|
|
16
|
+
export async function buildX402Header(params) {
|
|
17
|
+
const rpc = new Server(params.rpcUrl);
|
|
18
|
+
const agentKp = Keypair.fromSecret(params.agentSecret);
|
|
19
|
+
const vault = new Contract(params.vaultContract);
|
|
20
|
+
const sourcePub = params.facilitatorPublicKey || agentKp.publicKey();
|
|
21
|
+
const account = await rpc.getAccount(sourcePub);
|
|
22
|
+
const tx = new TransactionBuilder(account, {
|
|
23
|
+
fee: "1000000",
|
|
24
|
+
networkPassphrase: params.networkPassphrase,
|
|
25
|
+
})
|
|
26
|
+
.addOperation(vault.call("agent_pay", nativeToScVal(params.agentSigner, { type: "address" }), nativeToScVal(params.payTo, { type: "address" }), nativeToScVal(BigInt(params.amount), { type: "i128" }), nativeToScVal(params.memo, { type: "symbol" })))
|
|
27
|
+
.setTimeout(60)
|
|
28
|
+
.build();
|
|
29
|
+
const sim = await rpc.simulateTransaction(tx);
|
|
30
|
+
if (!("result" in sim)) {
|
|
31
|
+
const errorMsg = "error" in sim ? `${sim.error}` : "Unknown simulation error";
|
|
32
|
+
console.error("x402 simulation failed:", JSON.stringify(sim, null, 2));
|
|
33
|
+
throw new Error(`Simulation failed: ${errorMsg}`);
|
|
34
|
+
}
|
|
35
|
+
const authEntries = sim.result?.auth || [];
|
|
36
|
+
if (authEntries.length === 0)
|
|
37
|
+
throw new Error("No auth entries from simulation");
|
|
38
|
+
const latestLedger = sim.latestLedger;
|
|
39
|
+
const validUntilLedger = latestLedger + 1000;
|
|
40
|
+
const signedAuth = await authorizeEntry(authEntries[0], agentKp, validUntilLedger, params.networkPassphrase);
|
|
41
|
+
sim.result.auth = [signedAuth];
|
|
42
|
+
const assembled = assembleTransaction(tx, sim).build();
|
|
43
|
+
const payload = {
|
|
44
|
+
x402Version: 1,
|
|
45
|
+
scheme: "stellar-vault",
|
|
46
|
+
network: "stellar:testnet",
|
|
47
|
+
payload: {
|
|
48
|
+
vaultContract: params.vaultContract,
|
|
49
|
+
agentId: params.agentId,
|
|
50
|
+
agentSigner: params.agentSigner,
|
|
51
|
+
payTo: params.payTo,
|
|
52
|
+
amount: params.amount,
|
|
53
|
+
asset: params.usdcAddress,
|
|
54
|
+
memo: params.memo,
|
|
55
|
+
signedAuthEntry: signedAuth.toXDR("base64"),
|
|
56
|
+
assembledTxXdr: assembled.toXDR(),
|
|
57
|
+
expirationLedger: validUntilLedger,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
return Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=header-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header-builder.js","sourceRoot":"","sources":["../src/header-builder.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type { PaymentRequirements, PaymentAccept, PaymentPayload, PaymentResponse, SettlementResult, X402RouteConfig, LoggerLike, } from "./types.js";
|
|
2
|
+
export { ErrorCode, AgentNetError } from "./types.js";
|
|
3
|
+
export { STELLAR_CONFIG, TESTNET, MAINNET, USDC_DECIMALS, STROOPS_PER_USDC, formatUsdc, toStroops, } from "./config.js";
|
|
4
|
+
export type { StellarNetworkConfig, StellarNetwork } from "./config.js";
|
|
5
|
+
export { buildX402Header } from "./header-builder.js";
|
|
6
|
+
export { settlePayment } from "./facilitator.js";
|
|
7
|
+
export type { SettlementOptions } from "./facilitator.js";
|
|
8
|
+
export { createX402Middleware } from "./middleware.js";
|
|
9
|
+
export type { X402MiddlewareOptions } from "./middleware.js";
|
|
10
|
+
export { buildAndSubmitTx, fundAccount } from "./stellar-tx.js";
|
|
11
|
+
export { createRpcClient, getAccount, getLatestLedger, generateKeypair } from "./stellar-client.js";
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGtD,OAAO,EACL,cAAc,EACd,OAAO,EACP,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGxE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG7D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGhE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { ErrorCode, AgentNetError } from "./types.js";
|
|
2
|
+
// ── Config ──
|
|
3
|
+
export { STELLAR_CONFIG, TESTNET, MAINNET, USDC_DECIMALS, STROOPS_PER_USDC, formatUsdc, toStroops, } from "./config.js";
|
|
4
|
+
// ── Header Builder ──
|
|
5
|
+
export { buildX402Header } from "./header-builder.js";
|
|
6
|
+
// ── Facilitator ──
|
|
7
|
+
export { settlePayment } from "./facilitator.js";
|
|
8
|
+
// ── Middleware ──
|
|
9
|
+
export { createX402Middleware } from "./middleware.js";
|
|
10
|
+
// ── Stellar Transaction Helpers ──
|
|
11
|
+
export { buildAndSubmitTx, fundAccount } from "./stellar-tx.js";
|
|
12
|
+
// ── Stellar Client ──
|
|
13
|
+
export { createRpcClient, getAccount, getLatestLedger, generateKeypair } from "./stellar-client.js";
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtD,eAAe;AACf,OAAO,EACL,cAAc,EACd,OAAO,EACP,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,SAAS,GACV,MAAM,aAAa,CAAC;AAGrB,uBAAuB;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,oBAAoB;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,mBAAmB;AACnB,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAGvD,oCAAoC;AACpC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEhE,uBAAuB;AACvB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { X402RouteConfig, LoggerLike } from "./types.js";
|
|
2
|
+
export interface X402MiddlewareOptions {
|
|
3
|
+
rpcUrl: string;
|
|
4
|
+
horizonUrl: string;
|
|
5
|
+
networkPassphrase: string;
|
|
6
|
+
facilitatorSecret: string;
|
|
7
|
+
usdcAddress: string;
|
|
8
|
+
logger?: LoggerLike;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Factory that creates an x402 middleware function for Express.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```ts
|
|
15
|
+
* const x402 = createX402Middleware({
|
|
16
|
+
* rpcUrl: "https://soroban-testnet.stellar.org",
|
|
17
|
+
* horizonUrl: "https://horizon-testnet.stellar.org",
|
|
18
|
+
* networkPassphrase: "Test SDF Network ; September 2015",
|
|
19
|
+
* facilitatorSecret: "S...",
|
|
20
|
+
* usdcAddress: "C...",
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* app.use("/api/paid", x402({ price: "100000", description: "Query" }));
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function createX402Middleware(options: X402MiddlewareOptions): (routeConfig: X402RouteConfig) => (req: any, res: any, next: any) => Promise<any>;
|
|
27
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,IAM5C,aAAa,eAAe,MACjC,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,kBA0D9C"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Keypair } from "@stellar/stellar-sdk";
|
|
2
|
+
import { settlePayment } from "./facilitator.js";
|
|
3
|
+
/**
|
|
4
|
+
* Factory that creates an x402 middleware function for Express.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* ```ts
|
|
8
|
+
* const x402 = createX402Middleware({
|
|
9
|
+
* rpcUrl: "https://soroban-testnet.stellar.org",
|
|
10
|
+
* horizonUrl: "https://horizon-testnet.stellar.org",
|
|
11
|
+
* networkPassphrase: "Test SDF Network ; September 2015",
|
|
12
|
+
* facilitatorSecret: "S...",
|
|
13
|
+
* usdcAddress: "C...",
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* app.use("/api/paid", x402({ price: "100000", description: "Query" }));
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function createX402Middleware(options) {
|
|
20
|
+
const log = options.logger ?? console;
|
|
21
|
+
const facilitatorPubkey = options.facilitatorSecret
|
|
22
|
+
? Keypair.fromSecret(options.facilitatorSecret).publicKey()
|
|
23
|
+
: "GFACILITATOR_PLACEHOLDER";
|
|
24
|
+
return function x402(routeConfig) {
|
|
25
|
+
return async (req, res, next) => {
|
|
26
|
+
const paymentHeader = req.headers["x-payment"];
|
|
27
|
+
if (!paymentHeader) {
|
|
28
|
+
return res.status(402).json({
|
|
29
|
+
x402Version: 1,
|
|
30
|
+
accepts: [{
|
|
31
|
+
scheme: "stellar-vault",
|
|
32
|
+
network: "stellar:testnet",
|
|
33
|
+
asset: options.usdcAddress,
|
|
34
|
+
amount: routeConfig.price,
|
|
35
|
+
payTo: facilitatorPubkey,
|
|
36
|
+
maxTimeoutSeconds: 60,
|
|
37
|
+
description: routeConfig.description,
|
|
38
|
+
}],
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const payload = JSON.parse(Buffer.from(paymentHeader, "base64").toString("utf-8"));
|
|
43
|
+
if (payload.scheme !== "stellar-vault") {
|
|
44
|
+
return res.status(402).json({ error: "unsupported scheme" });
|
|
45
|
+
}
|
|
46
|
+
if (BigInt(payload.payload.amount) < BigInt(routeConfig.price)) {
|
|
47
|
+
return res.status(402).json({ error: "insufficient amount" });
|
|
48
|
+
}
|
|
49
|
+
const result = await settlePayment(payload, {
|
|
50
|
+
rpcUrl: options.rpcUrl,
|
|
51
|
+
horizonUrl: options.horizonUrl,
|
|
52
|
+
networkPassphrase: options.networkPassphrase,
|
|
53
|
+
facilitatorSecret: options.facilitatorSecret,
|
|
54
|
+
logger: log,
|
|
55
|
+
});
|
|
56
|
+
if (result.success) {
|
|
57
|
+
req.x402 = {
|
|
58
|
+
txHash: result.txHash,
|
|
59
|
+
payer: payload.payload.vaultContract,
|
|
60
|
+
agentId: payload.payload.agentId,
|
|
61
|
+
};
|
|
62
|
+
res.setHeader("X-PAYMENT-RESPONSE", JSON.stringify({
|
|
63
|
+
txHash: result.txHash,
|
|
64
|
+
network: "stellar:testnet",
|
|
65
|
+
}));
|
|
66
|
+
return next();
|
|
67
|
+
}
|
|
68
|
+
return res.status(402).json({ error: result.error });
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
log.error("x402 payment failed", { error: err.message });
|
|
72
|
+
return res.status(402).json({ error: err.message });
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Keypair } from "@stellar/stellar-sdk";
|
|
2
|
+
import { Server } from "@stellar/stellar-sdk/rpc";
|
|
3
|
+
/**
|
|
4
|
+
* Create a Soroban RPC client.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createRpcClient(rpcUrl: string): Server;
|
|
7
|
+
/**
|
|
8
|
+
* Get account details from the RPC.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getAccount(rpc: Server, publicKey: string): Promise<import("@stellar/stellar-sdk").Account>;
|
|
11
|
+
/**
|
|
12
|
+
* Get the latest ledger sequence from the RPC.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getLatestLedger(rpc: Server): Promise<import("@stellar/stellar-sdk/rpc").Api.GetLatestLedgerResponse>;
|
|
15
|
+
/**
|
|
16
|
+
* Generate a random Stellar keypair.
|
|
17
|
+
*/
|
|
18
|
+
export declare function generateKeypair(): Keypair;
|
|
19
|
+
//# sourceMappingURL=stellar-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stellar-client.d.ts","sourceRoot":"","sources":["../src/stellar-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAElD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mDAE9D;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,2EAEhD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Keypair } from "@stellar/stellar-sdk";
|
|
2
|
+
import { Server } from "@stellar/stellar-sdk/rpc";
|
|
3
|
+
/**
|
|
4
|
+
* Create a Soroban RPC client.
|
|
5
|
+
*/
|
|
6
|
+
export function createRpcClient(rpcUrl) {
|
|
7
|
+
return new Server(rpcUrl);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Get account details from the RPC.
|
|
11
|
+
*/
|
|
12
|
+
export async function getAccount(rpc, publicKey) {
|
|
13
|
+
return rpc.getAccount(publicKey);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get the latest ledger sequence from the RPC.
|
|
17
|
+
*/
|
|
18
|
+
export async function getLatestLedger(rpc) {
|
|
19
|
+
return rpc.getLatestLedger();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate a random Stellar keypair.
|
|
23
|
+
*/
|
|
24
|
+
export function generateKeypair() {
|
|
25
|
+
return Keypair.random();
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=stellar-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stellar-client.js","sourceRoot":"","sources":["../src/stellar-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAElD;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,SAAiB;IAC7D,OAAO,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW;IAC/C,OAAO,GAAG,CAAC,eAAe,EAAE,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LoggerLike } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Build, simulate, sign, and submit a Soroban transaction.
|
|
4
|
+
*/
|
|
5
|
+
export declare function buildAndSubmitTx(params: {
|
|
6
|
+
rpcUrl: string;
|
|
7
|
+
networkPassphrase: string;
|
|
8
|
+
signerSecret: string;
|
|
9
|
+
operations: any[];
|
|
10
|
+
logger?: LoggerLike;
|
|
11
|
+
}): Promise<{
|
|
12
|
+
txHash: string;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Fund an account on Stellar testnet via friendbot.
|
|
16
|
+
*/
|
|
17
|
+
export declare function fundAccount(publicKey: string, logger?: LoggerLike): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=stellar-tx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stellar-tx.d.ts","sourceRoot":"","sources":["../src/stellar-tx.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,GAAG,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA8B9B;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CAIf"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Keypair, TransactionBuilder } from "@stellar/stellar-sdk";
|
|
2
|
+
import { Server, assembleTransaction } from "@stellar/stellar-sdk/rpc";
|
|
3
|
+
/**
|
|
4
|
+
* Build, simulate, sign, and submit a Soroban transaction.
|
|
5
|
+
*/
|
|
6
|
+
export async function buildAndSubmitTx(params) {
|
|
7
|
+
const rpc = new Server(params.rpcUrl);
|
|
8
|
+
const keypair = Keypair.fromSecret(params.signerSecret);
|
|
9
|
+
const account = await rpc.getAccount(keypair.publicKey());
|
|
10
|
+
const builder = new TransactionBuilder(account, {
|
|
11
|
+
fee: "1000000",
|
|
12
|
+
networkPassphrase: params.networkPassphrase,
|
|
13
|
+
});
|
|
14
|
+
for (const op of params.operations)
|
|
15
|
+
builder.addOperation(op);
|
|
16
|
+
const tx = builder.setTimeout(60).build();
|
|
17
|
+
const sim = await rpc.simulateTransaction(tx);
|
|
18
|
+
if (!("result" in sim))
|
|
19
|
+
throw new Error("Simulation failed");
|
|
20
|
+
const assembled = assembleTransaction(tx, sim).build();
|
|
21
|
+
assembled.sign(keypair);
|
|
22
|
+
const result = await rpc.sendTransaction(assembled);
|
|
23
|
+
if (result.status !== "PENDING")
|
|
24
|
+
throw new Error(`Send: ${result.status}`);
|
|
25
|
+
let txResult = await rpc.getTransaction(result.hash);
|
|
26
|
+
let waited = 0;
|
|
27
|
+
while (txResult.status === "NOT_FOUND" && waited < 30) {
|
|
28
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
29
|
+
txResult = await rpc.getTransaction(result.hash);
|
|
30
|
+
waited++;
|
|
31
|
+
}
|
|
32
|
+
if (txResult.status !== "SUCCESS")
|
|
33
|
+
throw new Error(`Tx: ${txResult.status}`);
|
|
34
|
+
return { txHash: result.hash };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fund an account on Stellar testnet via friendbot.
|
|
38
|
+
*/
|
|
39
|
+
export async function fundAccount(publicKey, logger) {
|
|
40
|
+
const response = await fetch(`https://friendbot.stellar.org/?addr=${publicKey}`);
|
|
41
|
+
if (!response.ok)
|
|
42
|
+
throw new Error(`Friendbot failed: ${response.statusText}`);
|
|
43
|
+
(logger ?? console).info("Account funded via friendbot", { publicKey });
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=stellar-tx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stellar-tx.js","sourceRoot":"","sources":["../src/stellar-tx.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGvE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAMtC;IACC,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAE1D,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,OAAO,EAAE;QAC9C,GAAG,EAAE,SAAS;QACd,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;KAC5C,CAAC,CAAC;IACH,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,UAAU;QAAE,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;IAE1C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;IAC9C,IAAI,CAAC,CAAC,QAAQ,IAAI,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAE7D,MAAM,SAAS,GAAG,mBAAmB,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;IACvD,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAExB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IACpD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAE3E,IAAI,QAAQ,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,OAAO,QAAQ,CAAC,MAAM,KAAK,WAAW,IAAI,MAAM,GAAG,EAAE,EAAE,CAAC;QACtD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QAC5C,QAAQ,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,EAAE,CAAC;IACX,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAiB,EACjB,MAAmB;IAEnB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,uCAAuC,SAAS,EAAE,CAAC,CAAC;IACjF,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAC9E,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,8BAA8B,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;AAC1E,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface PaymentRequirements {
|
|
2
|
+
x402Version: number;
|
|
3
|
+
accepts: PaymentAccept[];
|
|
4
|
+
}
|
|
5
|
+
export interface PaymentAccept {
|
|
6
|
+
scheme: string;
|
|
7
|
+
network: string;
|
|
8
|
+
asset: string;
|
|
9
|
+
amount: string;
|
|
10
|
+
payTo: string;
|
|
11
|
+
maxTimeoutSeconds: number;
|
|
12
|
+
description: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PaymentPayload {
|
|
15
|
+
x402Version: number;
|
|
16
|
+
scheme: string;
|
|
17
|
+
network: string;
|
|
18
|
+
payload: {
|
|
19
|
+
vaultContract: string;
|
|
20
|
+
agentId: number;
|
|
21
|
+
agentSigner: string;
|
|
22
|
+
payTo: string;
|
|
23
|
+
amount: string;
|
|
24
|
+
asset: string;
|
|
25
|
+
memo: string;
|
|
26
|
+
signedAuthEntry: string;
|
|
27
|
+
assembledTxXdr?: string;
|
|
28
|
+
expirationLedger: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export interface PaymentResponse {
|
|
32
|
+
txHash: string;
|
|
33
|
+
network: string;
|
|
34
|
+
}
|
|
35
|
+
export interface SettlementResult {
|
|
36
|
+
success: boolean;
|
|
37
|
+
txHash?: string;
|
|
38
|
+
error?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface X402RouteConfig {
|
|
41
|
+
price: string;
|
|
42
|
+
description: string;
|
|
43
|
+
}
|
|
44
|
+
export declare enum ErrorCode {
|
|
45
|
+
WALLET_NOT_CONNECTED = "WALLET_NOT_CONNECTED",
|
|
46
|
+
VAULT_NOT_FOUND = "VAULT_NOT_FOUND",
|
|
47
|
+
AGENT_NOT_FOUND = "AGENT_NOT_FOUND",
|
|
48
|
+
INSUFFICIENT_BALANCE = "INSUFFICIENT_BALANCE",
|
|
49
|
+
TX_FAILED = "TX_FAILED",
|
|
50
|
+
X402_PAYMENT_REQUIRED = "X402_PAYMENT_REQUIRED",
|
|
51
|
+
X402_SETTLEMENT_FAILED = "X402_SETTLEMENT_FAILED",
|
|
52
|
+
SIMULATION_FAILED = "SIMULATION_FAILED",
|
|
53
|
+
REPUTATION_NOT_FOUND = "REPUTATION_NOT_FOUND",
|
|
54
|
+
INVALID_SCORE = "INVALID_SCORE",
|
|
55
|
+
VALIDATION_NOT_FOUND = "VALIDATION_NOT_FOUND",
|
|
56
|
+
VALIDATION_ALREADY_COMPLETED = "VALIDATION_ALREADY_COMPLETED",
|
|
57
|
+
NOT_VALIDATOR = "NOT_VALIDATOR"
|
|
58
|
+
}
|
|
59
|
+
export declare class AgentNetError extends Error {
|
|
60
|
+
code: ErrorCode;
|
|
61
|
+
constructor(code: ErrorCode, message: string);
|
|
62
|
+
}
|
|
63
|
+
export interface LoggerLike {
|
|
64
|
+
info(message: string, ...args: any[]): void;
|
|
65
|
+
warn(message: string, ...args: any[]): void;
|
|
66
|
+
error(message: string, ...args: any[]): void;
|
|
67
|
+
debug(message: string, ...args: any[]): void;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,aAAa,EAAE,MAAM,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,oBAAY,SAAS;IACnB,oBAAoB,yBAAyB;IAC7C,eAAe,oBAAoB;IACnC,eAAe,oBAAoB;IACnC,oBAAoB,yBAAyB;IAC7C,SAAS,cAAc;IACvB,qBAAqB,0BAA0B;IAC/C,sBAAsB,2BAA2B;IACjD,iBAAiB,sBAAsB;IACvC,oBAAoB,yBAAyB;IAC7C,aAAa,kBAAkB;IAC/B,oBAAoB,yBAAyB;IAC7C,4BAA4B,iCAAiC;IAC7D,aAAa,kBAAkB;CAChC;AAED,qBAAa,aAAc,SAAQ,KAAK;IAE7B,IAAI,EAAE,SAAS;gBAAf,IAAI,EAAE,SAAS,EACtB,OAAO,EAAE,MAAM;CAKlB;AAID,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;CAC9C"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// ── x402 Protocol Types ──
|
|
2
|
+
// ── Error Types ──
|
|
3
|
+
export var ErrorCode;
|
|
4
|
+
(function (ErrorCode) {
|
|
5
|
+
ErrorCode["WALLET_NOT_CONNECTED"] = "WALLET_NOT_CONNECTED";
|
|
6
|
+
ErrorCode["VAULT_NOT_FOUND"] = "VAULT_NOT_FOUND";
|
|
7
|
+
ErrorCode["AGENT_NOT_FOUND"] = "AGENT_NOT_FOUND";
|
|
8
|
+
ErrorCode["INSUFFICIENT_BALANCE"] = "INSUFFICIENT_BALANCE";
|
|
9
|
+
ErrorCode["TX_FAILED"] = "TX_FAILED";
|
|
10
|
+
ErrorCode["X402_PAYMENT_REQUIRED"] = "X402_PAYMENT_REQUIRED";
|
|
11
|
+
ErrorCode["X402_SETTLEMENT_FAILED"] = "X402_SETTLEMENT_FAILED";
|
|
12
|
+
ErrorCode["SIMULATION_FAILED"] = "SIMULATION_FAILED";
|
|
13
|
+
ErrorCode["REPUTATION_NOT_FOUND"] = "REPUTATION_NOT_FOUND";
|
|
14
|
+
ErrorCode["INVALID_SCORE"] = "INVALID_SCORE";
|
|
15
|
+
ErrorCode["VALIDATION_NOT_FOUND"] = "VALIDATION_NOT_FOUND";
|
|
16
|
+
ErrorCode["VALIDATION_ALREADY_COMPLETED"] = "VALIDATION_ALREADY_COMPLETED";
|
|
17
|
+
ErrorCode["NOT_VALIDATOR"] = "NOT_VALIDATOR";
|
|
18
|
+
})(ErrorCode || (ErrorCode = {}));
|
|
19
|
+
export class AgentNetError extends Error {
|
|
20
|
+
code;
|
|
21
|
+
constructor(code, message) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.code = code;
|
|
24
|
+
this.name = "AgentNetError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAqD5B,oBAAoB;AAEpB,MAAM,CAAN,IAAY,SAcX;AAdD,WAAY,SAAS;IACnB,0DAA6C,CAAA;IAC7C,gDAAmC,CAAA;IACnC,gDAAmC,CAAA;IACnC,0DAA6C,CAAA;IAC7C,oCAAuB,CAAA;IACvB,4DAA+C,CAAA;IAC/C,8DAAiD,CAAA;IACjD,oDAAuC,CAAA;IACvC,0DAA6C,CAAA;IAC7C,4CAA+B,CAAA;IAC/B,0DAA6C,CAAA;IAC7C,0EAA6D,CAAA;IAC7D,4CAA+B,CAAA;AACjC,CAAC,EAdW,SAAS,KAAT,SAAS,QAcpB;AAED,MAAM,OAAO,aAAc,SAAQ,KAAK;IAE7B;IADT,YACS,IAAe,EACtB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,SAAI,GAAJ,IAAI,CAAW;QAItB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agenticocean/x402-stellar",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "x402 payment protocol for Stellar — header builder, facilitator, Express middleware",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"lint": "tsc --noEmit",
|
|
21
|
+
"clean": "rm -rf dist"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/stellaragent402/stellaragent402"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://stellaragent402.io",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/stellaragent402/stellaragent402/issues"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"stellar",
|
|
36
|
+
"soroban",
|
|
37
|
+
"x402",
|
|
38
|
+
"payment",
|
|
39
|
+
"ai-agents",
|
|
40
|
+
"defi",
|
|
41
|
+
"blockchain"
|
|
42
|
+
],
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@stellar/stellar-sdk": "^13.1.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"express": ">=4.0.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"express": {
|
|
51
|
+
"optional": true
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/express": "^5.0.0",
|
|
56
|
+
"typescript": "^5.7.0"
|
|
57
|
+
},
|
|
58
|
+
"license": "MIT"
|
|
59
|
+
}
|