@zero-two-labs/sekisho 0.0.0-stage → 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 +21 -0
- package/README.md +96 -2
- package/dist/abi.d.ts +104 -0
- package/dist/abi.js +16 -0
- package/dist/agent.d.ts +26 -0
- package/dist/agent.js +31 -0
- package/dist/chains.d.ts +15 -0
- package/dist/chains.js +19 -0
- package/dist/client.d.ts +43 -0
- package/dist/client.js +96 -0
- package/dist/facilitator.d.ts +24 -0
- package/dist/facilitator.js +47 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/mcp.d.ts +30 -0
- package/dist/mcp.js +39 -0
- package/dist/x402.d.ts +30 -0
- package/dist/x402.js +25 -0
- package/package.json +67 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zero Two Labs
|
|
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
CHANGED
|
@@ -1,3 +1,97 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Sekisho 関所
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**x402 payments with automatic revenue split on Avalanche.**
|
|
4
|
+
|
|
5
|
+
Sekisho turns any API or MCP tool into a paid endpoint that AI agents can pay for with USDC, using the [x402](https://x402.org) protocol. Every payment lands in the seller's on-chain **SplitVault**, which distributes the platform fee and the seller's share automatically.
|
|
6
|
+
|
|
7
|
+
> Status: `v0.1.0` — Avalanche Fuji testnet.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @zero-two-labs/sekisho viem
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## How it works
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Agent ──(x402, USDC)──▶ Seller's SplitVault ──distribute()──┬──▶ Platform fee
|
|
19
|
+
▲ └──▶ Seller
|
|
20
|
+
│
|
|
21
|
+
SplitVaultFactory (one vault per seller, deterministic address)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- Each seller gets a **deterministic vault address** (`payTo`) — payments can arrive before the vault is deployed.
|
|
25
|
+
- `distribute()` is permissionless: funds can only go to the seller and the platform treasury.
|
|
26
|
+
- Platform fee is hard-capped at **10%** in the contract.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### 1. Read vaults and split payments
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createSekishoClient } from "@zero-two-labs/sekisho";
|
|
34
|
+
|
|
35
|
+
const sekisho = createSekishoClient({ network: "avalancheFuji" });
|
|
36
|
+
|
|
37
|
+
const payTo = await sekisho.getPayTo("0xSeller...");
|
|
38
|
+
const { total, fee, merchantAmount } = await sekisho.pending("0xSeller...");
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. Sell an HTTP endpoint (Hono example)
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { paymentMiddleware, x402ResourceServer } from "@x402/hono";
|
|
45
|
+
import { ExactEvmScheme } from "@x402/evm/exact/server";
|
|
46
|
+
import {
|
|
47
|
+
createSekishoClient,
|
|
48
|
+
createPaymentOption,
|
|
49
|
+
createSekishoFacilitator,
|
|
50
|
+
toFacilitatorClient,
|
|
51
|
+
} from "@zero-two-labs/sekisho";
|
|
52
|
+
|
|
53
|
+
const sekisho = createSekishoClient({ network: "avalancheFuji" });
|
|
54
|
+
const option = await createPaymentOption(sekisho, { merchant: "0xSeller...", price: "0.01" });
|
|
55
|
+
|
|
56
|
+
const facilitator = createSekishoFacilitator({ account: facilitatorAccount });
|
|
57
|
+
const server = new x402ResourceServer(toFacilitatorClient(facilitator))
|
|
58
|
+
.register(option.network, new ExactEvmScheme());
|
|
59
|
+
|
|
60
|
+
app.use(paymentMiddleware({ "GET /premium": { accepts: [option] } }, server));
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 3. Pay as an agent (with spend limits)
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { createSekishoFetch } from "@zero-two-labs/sekisho";
|
|
67
|
+
|
|
68
|
+
const { fetch: payFetch } = createSekishoFetch({ account, maxPerPayment: "0.05" });
|
|
69
|
+
const res = await payFetch("https://api.example.com/premium");
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 4. Paid MCP tools
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { createSekishoMcpPaywall, createSekishoMcpClient } from "@zero-two-labs/sekisho";
|
|
76
|
+
|
|
77
|
+
// Server
|
|
78
|
+
const paid = await createSekishoMcpPaywall({
|
|
79
|
+
sekisho, facilitator, merchant: "0xSeller...", price: "0.01",
|
|
80
|
+
onSettled: () => sekisho.distribute("0xSeller..."),
|
|
81
|
+
});
|
|
82
|
+
mcpServer.tool("premium_insight", "Costs 0.01 USDC", { topic: z.string() }, paid(handler));
|
|
83
|
+
|
|
84
|
+
// Agent
|
|
85
|
+
const client = createSekishoMcpClient({ account, maxPerPayment: "0.05" });
|
|
86
|
+
const result = await client.callTool("premium_insight", { topic: "Avalanche" });
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Deployments
|
|
90
|
+
|
|
91
|
+
| Network | SplitVaultFactory | USDC |
|
|
92
|
+
| --- | --- | --- |
|
|
93
|
+
| Avalanche Fuji (`eip155:43113`) | [`0xA1967201adD1Ac57d1c72D04Ca4d9159B98C8C5D`](https://testnet.snowtrace.io/address/0xA1967201adD1Ac57d1c72D04Ca4d9159B98C8C5D) | `0x5425890298aed601595a70AB815c96711a31Bc65` |
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT © Zero Two Labs
|
package/dist/abi.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export declare const splitVaultFactoryAbi: readonly [{
|
|
2
|
+
readonly name: "predictVault";
|
|
3
|
+
readonly type: 'function';
|
|
4
|
+
readonly stateMutability: "view";
|
|
5
|
+
readonly inputs: readonly [{
|
|
6
|
+
readonly type: "address";
|
|
7
|
+
readonly name: "merchant";
|
|
8
|
+
}];
|
|
9
|
+
readonly outputs: readonly [{
|
|
10
|
+
readonly type: "address";
|
|
11
|
+
}];
|
|
12
|
+
}, {
|
|
13
|
+
readonly name: "vaultOf";
|
|
14
|
+
readonly type: 'function';
|
|
15
|
+
readonly stateMutability: "view";
|
|
16
|
+
readonly inputs: readonly [{
|
|
17
|
+
readonly type: "address";
|
|
18
|
+
readonly name: "merchant";
|
|
19
|
+
}];
|
|
20
|
+
readonly outputs: readonly [{
|
|
21
|
+
readonly type: "address";
|
|
22
|
+
}];
|
|
23
|
+
}, {
|
|
24
|
+
readonly name: "treasury";
|
|
25
|
+
readonly type: 'function';
|
|
26
|
+
readonly stateMutability: "view";
|
|
27
|
+
readonly inputs: readonly [];
|
|
28
|
+
readonly outputs: readonly [{
|
|
29
|
+
readonly type: "address";
|
|
30
|
+
}];
|
|
31
|
+
}, {
|
|
32
|
+
readonly name: "feeBps";
|
|
33
|
+
readonly type: 'function';
|
|
34
|
+
readonly stateMutability: "view";
|
|
35
|
+
readonly inputs: readonly [];
|
|
36
|
+
readonly outputs: readonly [{
|
|
37
|
+
readonly type: "uint16";
|
|
38
|
+
}];
|
|
39
|
+
}, {
|
|
40
|
+
readonly name: "createVault";
|
|
41
|
+
readonly type: 'function';
|
|
42
|
+
readonly stateMutability: "nonpayable";
|
|
43
|
+
readonly inputs: readonly [{
|
|
44
|
+
readonly type: "address";
|
|
45
|
+
readonly name: "merchant";
|
|
46
|
+
}];
|
|
47
|
+
readonly outputs: readonly [{
|
|
48
|
+
readonly type: "address";
|
|
49
|
+
readonly name: "vault";
|
|
50
|
+
}];
|
|
51
|
+
}];
|
|
52
|
+
export declare const splitVaultAbi: readonly [{
|
|
53
|
+
readonly name: "merchant";
|
|
54
|
+
readonly type: 'function';
|
|
55
|
+
readonly stateMutability: "view";
|
|
56
|
+
readonly inputs: readonly [];
|
|
57
|
+
readonly outputs: readonly [{
|
|
58
|
+
readonly type: "address";
|
|
59
|
+
}];
|
|
60
|
+
}, {
|
|
61
|
+
readonly name: "pending";
|
|
62
|
+
readonly type: 'function';
|
|
63
|
+
readonly stateMutability: "view";
|
|
64
|
+
readonly inputs: readonly [{
|
|
65
|
+
readonly type: "address";
|
|
66
|
+
readonly name: "token";
|
|
67
|
+
}];
|
|
68
|
+
readonly outputs: readonly [{
|
|
69
|
+
readonly type: "uint256";
|
|
70
|
+
readonly name: "total";
|
|
71
|
+
}, {
|
|
72
|
+
readonly type: "uint256";
|
|
73
|
+
readonly name: "fee";
|
|
74
|
+
}, {
|
|
75
|
+
readonly type: "uint256";
|
|
76
|
+
readonly name: "merchantAmount";
|
|
77
|
+
}];
|
|
78
|
+
}, {
|
|
79
|
+
readonly name: "distribute";
|
|
80
|
+
readonly type: 'function';
|
|
81
|
+
readonly stateMutability: "nonpayable";
|
|
82
|
+
readonly inputs: readonly [{
|
|
83
|
+
readonly type: "address";
|
|
84
|
+
readonly name: "token";
|
|
85
|
+
}];
|
|
86
|
+
readonly outputs: readonly [{
|
|
87
|
+
readonly type: "uint256";
|
|
88
|
+
readonly name: "fee";
|
|
89
|
+
}, {
|
|
90
|
+
readonly type: "uint256";
|
|
91
|
+
readonly name: "merchantAmount";
|
|
92
|
+
}];
|
|
93
|
+
}];
|
|
94
|
+
export declare const erc20Abi: readonly [{
|
|
95
|
+
readonly name: "balanceOf";
|
|
96
|
+
readonly type: 'function';
|
|
97
|
+
readonly stateMutability: "view";
|
|
98
|
+
readonly inputs: readonly [{
|
|
99
|
+
readonly type: "address";
|
|
100
|
+
}];
|
|
101
|
+
readonly outputs: readonly [{
|
|
102
|
+
readonly type: "uint256";
|
|
103
|
+
}];
|
|
104
|
+
}];
|
package/dist/abi.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { parseAbi } from "viem";
|
|
2
|
+
export const splitVaultFactoryAbi = parseAbi([
|
|
3
|
+
"function predictVault(address merchant) view returns (address)",
|
|
4
|
+
"function vaultOf(address merchant) view returns (address)",
|
|
5
|
+
"function treasury() view returns (address)",
|
|
6
|
+
"function feeBps() view returns (uint16)",
|
|
7
|
+
"function createVault(address merchant) returns (address vault)",
|
|
8
|
+
]);
|
|
9
|
+
export const splitVaultAbi = parseAbi([
|
|
10
|
+
"function merchant() view returns (address)",
|
|
11
|
+
"function pending(address token) view returns (uint256 total, uint256 fee, uint256 merchantAmount)",
|
|
12
|
+
"function distribute(address token) returns (uint256 fee, uint256 merchantAmount)",
|
|
13
|
+
]);
|
|
14
|
+
export const erc20Abi = parseAbi([
|
|
15
|
+
"function balanceOf(address) view returns (uint256)",
|
|
16
|
+
]);
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { x402Client } from "@x402/core/client";
|
|
2
|
+
import { x402HTTPClient } from "@x402/fetch";
|
|
3
|
+
import { type LocalAccount } from "viem";
|
|
4
|
+
import { type SekishoNetwork } from "./chains.js";
|
|
5
|
+
export interface SekishoAgentOptions {
|
|
6
|
+
/** Cuenta del agente que firma los pagos (viem LocalAccount). */
|
|
7
|
+
account: LocalAccount;
|
|
8
|
+
network?: SekishoNetwork;
|
|
9
|
+
/** Máximo a pagar por petición, en USD. Por defecto "1". */
|
|
10
|
+
maxPerPayment?: string;
|
|
11
|
+
}
|
|
12
|
+
/** @deprecated Usa SekishoAgentOptions. Se mantiene por compatibilidad. */
|
|
13
|
+
export type SekishoFetchOptions = SekishoAgentOptions;
|
|
14
|
+
export interface SekishoFetch {
|
|
15
|
+
/** fetch que paga automáticamente cuando recibe un 402. */
|
|
16
|
+
fetch: typeof fetch;
|
|
17
|
+
/** Utilidad oficial de x402 para leer el resultado del pago. */
|
|
18
|
+
httpClient: x402HTTPClient;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Cliente de pagos x402 para agentes: autoriza el USDC de la red
|
|
22
|
+
* de Sekisho y aplica un tope por pago.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createSekishoPaymentClient(options: SekishoAgentOptions): x402Client;
|
|
25
|
+
/** fetch con pagos x402 automáticos. */
|
|
26
|
+
export declare function createSekishoFetch(options: SekishoAgentOptions): SekishoFetch;
|
package/dist/agent.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { x402Client } from "@x402/core/client";
|
|
2
|
+
import { wrapFetchWithPayment, x402HTTPClient } from "@x402/fetch";
|
|
3
|
+
import { ExactEvmScheme } from "@x402/evm/exact/client";
|
|
4
|
+
import { parseUnits } from "viem";
|
|
5
|
+
import { NETWORKS } from "./chains.js";
|
|
6
|
+
/**
|
|
7
|
+
* Cliente de pagos x402 para agentes: autoriza el USDC de la red
|
|
8
|
+
* de Sekisho y aplica un tope por pago.
|
|
9
|
+
*/
|
|
10
|
+
export function createSekishoPaymentClient(options) {
|
|
11
|
+
const network = options.network ?? "avalancheFuji";
|
|
12
|
+
const config = NETWORKS[network];
|
|
13
|
+
const caip2 = `eip155:${config.chain.id}`;
|
|
14
|
+
const maxAtomic = parseUnits(options.maxPerPayment ?? "1", 6).toString();
|
|
15
|
+
return x402Client.fromConfig({
|
|
16
|
+
schemes: [{ network: caip2, client: new ExactEvmScheme(options.account) }],
|
|
17
|
+
spendControls: {
|
|
18
|
+
allowedAssets: [
|
|
19
|
+
{ network: caip2, asset: config.usdc, maxAmountPerPayment: maxAtomic },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** fetch con pagos x402 automáticos. */
|
|
25
|
+
export function createSekishoFetch(options) {
|
|
26
|
+
const client = createSekishoPaymentClient(options);
|
|
27
|
+
return {
|
|
28
|
+
fetch: wrapFetchWithPayment(fetch, client),
|
|
29
|
+
httpClient: new x402HTTPClient(client),
|
|
30
|
+
};
|
|
31
|
+
}
|
package/dist/chains.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Address, Chain } from "viem";
|
|
2
|
+
export type SekishoNetwork = "avalancheFuji" | "avalanche";
|
|
3
|
+
export interface NetworkConfig {
|
|
4
|
+
chain: Chain;
|
|
5
|
+
rpcUrl: string;
|
|
6
|
+
explorer: string;
|
|
7
|
+
usdc: Address;
|
|
8
|
+
/** Dominio EIP-712 del USDC (necesario para firmas EIP-3009 en x402). */
|
|
9
|
+
usdcEip712: {
|
|
10
|
+
name: string;
|
|
11
|
+
version: string;
|
|
12
|
+
};
|
|
13
|
+
factory?: Address;
|
|
14
|
+
}
|
|
15
|
+
export declare const NETWORKS: Record<SekishoNetwork, NetworkConfig>;
|
package/dist/chains.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { avalanche, avalancheFuji } from "viem/chains";
|
|
2
|
+
export const NETWORKS = {
|
|
3
|
+
avalancheFuji: {
|
|
4
|
+
chain: avalancheFuji,
|
|
5
|
+
rpcUrl: "https://api.avax-test.network/ext/bc/C/rpc",
|
|
6
|
+
explorer: "https://testnet.snowtrace.io",
|
|
7
|
+
usdc: "0x5425890298aed601595a70AB815c96711a31Bc65",
|
|
8
|
+
usdcEip712: { name: "USD Coin", version: "2" },
|
|
9
|
+
factory: "0xA1967201adD1Ac57d1c72D04Ca4d9159B98C8C5D",
|
|
10
|
+
},
|
|
11
|
+
avalanche: {
|
|
12
|
+
chain: avalanche,
|
|
13
|
+
rpcUrl: "https://api.avax.network/ext/bc/C/rpc",
|
|
14
|
+
explorer: "https://snowtrace.io",
|
|
15
|
+
usdc: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
|
|
16
|
+
usdcEip712: { name: "USD Coin", version: "2" },
|
|
17
|
+
// factory: se agrega cuando despleguemos en mainnet
|
|
18
|
+
},
|
|
19
|
+
};
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type Account, type Address, type Hash, type PublicClient } from "viem";
|
|
2
|
+
import { type NetworkConfig, type SekishoNetwork } from "./chains.js";
|
|
3
|
+
export interface SekishoClientOptions {
|
|
4
|
+
network?: SekishoNetwork;
|
|
5
|
+
rpcUrl?: string;
|
|
6
|
+
/** Necesaria solo para escribir (createVault, distribute). */
|
|
7
|
+
account?: Account;
|
|
8
|
+
}
|
|
9
|
+
export interface SekishoConfig {
|
|
10
|
+
network: SekishoNetwork;
|
|
11
|
+
chainId: number;
|
|
12
|
+
factory: Address;
|
|
13
|
+
usdc: Address;
|
|
14
|
+
treasury: Address;
|
|
15
|
+
feeBps: number;
|
|
16
|
+
}
|
|
17
|
+
export interface PendingSplit {
|
|
18
|
+
vault: Address;
|
|
19
|
+
deployed: boolean;
|
|
20
|
+
total: bigint;
|
|
21
|
+
fee: bigint;
|
|
22
|
+
merchantAmount: bigint;
|
|
23
|
+
}
|
|
24
|
+
export interface SekishoClient {
|
|
25
|
+
network: SekishoNetwork;
|
|
26
|
+
config: NetworkConfig;
|
|
27
|
+
publicClient: PublicClient;
|
|
28
|
+
/** Tesorería y fee actuales de la plataforma. */
|
|
29
|
+
getConfig(): Promise<SekishoConfig>;
|
|
30
|
+
/** Dirección payTo del vendedor (su vault), exista o no todavía. */
|
|
31
|
+
getPayTo(merchant: Address): Promise<Address>;
|
|
32
|
+
isVaultDeployed(merchant: Address): Promise<boolean>;
|
|
33
|
+
/** Crea el vault del vendedor. Requiere `account`. */
|
|
34
|
+
createVault(merchant: Address): Promise<{
|
|
35
|
+
hash: Hash;
|
|
36
|
+
vault: Address;
|
|
37
|
+
}>;
|
|
38
|
+
/** Lo que se repartiría ahora mismo para el vendedor. */
|
|
39
|
+
pending(merchant: Address, token?: Address): Promise<PendingSplit>;
|
|
40
|
+
/** Reparte el saldo del vault (lo crea primero si hace falta). Requiere `account`. */
|
|
41
|
+
distribute(merchant: Address, token?: Address): Promise<Hash>;
|
|
42
|
+
}
|
|
43
|
+
export declare function createSekishoClient(options?: SekishoClientOptions): SekishoClient;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createPublicClient, createWalletClient, http, zeroAddress, } from "viem";
|
|
2
|
+
import { splitVaultAbi, splitVaultFactoryAbi } from "./abi.js";
|
|
3
|
+
import { NETWORKS } from "./chains.js";
|
|
4
|
+
export function createSekishoClient(options = {}) {
|
|
5
|
+
const network = options.network ?? "avalancheFuji";
|
|
6
|
+
const config = NETWORKS[network];
|
|
7
|
+
if (!config.factory) {
|
|
8
|
+
throw new Error(`Sekisho: la factory aún no está desplegada en "${network}"`);
|
|
9
|
+
}
|
|
10
|
+
const factory = config.factory;
|
|
11
|
+
const transport = http(options.rpcUrl ?? config.rpcUrl);
|
|
12
|
+
const publicClient = createPublicClient({ chain: config.chain, transport });
|
|
13
|
+
const walletClient = options.account
|
|
14
|
+
? createWalletClient({ chain: config.chain, transport, account: options.account })
|
|
15
|
+
: undefined;
|
|
16
|
+
function requireWallet() {
|
|
17
|
+
if (!walletClient) {
|
|
18
|
+
throw new Error("Sekisho: esta operación requiere `account` en createSekishoClient()");
|
|
19
|
+
}
|
|
20
|
+
return walletClient;
|
|
21
|
+
}
|
|
22
|
+
async function getConfig() {
|
|
23
|
+
const [treasury, feeBps] = await Promise.all([
|
|
24
|
+
publicClient.readContract({ address: factory, abi: splitVaultFactoryAbi, functionName: "treasury" }),
|
|
25
|
+
publicClient.readContract({ address: factory, abi: splitVaultFactoryAbi, functionName: "feeBps" }),
|
|
26
|
+
]);
|
|
27
|
+
return { network, chainId: config.chain.id, factory, usdc: config.usdc, treasury, feeBps };
|
|
28
|
+
}
|
|
29
|
+
async function getPayTo(merchant) {
|
|
30
|
+
return publicClient.readContract({
|
|
31
|
+
address: factory,
|
|
32
|
+
abi: splitVaultFactoryAbi,
|
|
33
|
+
functionName: "predictVault",
|
|
34
|
+
args: [merchant],
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async function isVaultDeployed(merchant) {
|
|
38
|
+
const vault = await publicClient.readContract({
|
|
39
|
+
address: factory,
|
|
40
|
+
abi: splitVaultFactoryAbi,
|
|
41
|
+
functionName: "vaultOf",
|
|
42
|
+
args: [merchant],
|
|
43
|
+
});
|
|
44
|
+
return vault !== zeroAddress;
|
|
45
|
+
}
|
|
46
|
+
async function createVault(merchant) {
|
|
47
|
+
const wallet = requireWallet();
|
|
48
|
+
const hash = await wallet.writeContract({
|
|
49
|
+
address: factory,
|
|
50
|
+
abi: splitVaultFactoryAbi,
|
|
51
|
+
functionName: "createVault",
|
|
52
|
+
args: [merchant],
|
|
53
|
+
});
|
|
54
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
55
|
+
return { hash, vault: await getPayTo(merchant) };
|
|
56
|
+
}
|
|
57
|
+
async function pending(merchant, token = config.usdc) {
|
|
58
|
+
const vault = await getPayTo(merchant);
|
|
59
|
+
if (!(await isVaultDeployed(merchant))) {
|
|
60
|
+
return { vault, deployed: false, total: 0n, fee: 0n, merchantAmount: 0n };
|
|
61
|
+
}
|
|
62
|
+
const [total, fee, merchantAmount] = await publicClient.readContract({
|
|
63
|
+
address: vault,
|
|
64
|
+
abi: splitVaultAbi,
|
|
65
|
+
functionName: "pending",
|
|
66
|
+
args: [token],
|
|
67
|
+
});
|
|
68
|
+
return { vault, deployed: true, total, fee, merchantAmount };
|
|
69
|
+
}
|
|
70
|
+
async function distribute(merchant, token = config.usdc) {
|
|
71
|
+
const wallet = requireWallet();
|
|
72
|
+
if (!(await isVaultDeployed(merchant))) {
|
|
73
|
+
await createVault(merchant);
|
|
74
|
+
}
|
|
75
|
+
const vault = await getPayTo(merchant);
|
|
76
|
+
const hash = await wallet.writeContract({
|
|
77
|
+
address: vault,
|
|
78
|
+
abi: splitVaultAbi,
|
|
79
|
+
functionName: "distribute",
|
|
80
|
+
args: [token],
|
|
81
|
+
});
|
|
82
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
83
|
+
return hash;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
network,
|
|
87
|
+
config,
|
|
88
|
+
publicClient,
|
|
89
|
+
getConfig,
|
|
90
|
+
getPayTo,
|
|
91
|
+
isVaultDeployed,
|
|
92
|
+
createVault,
|
|
93
|
+
pending,
|
|
94
|
+
distribute,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { x402Facilitator } from "@x402/core/facilitator";
|
|
2
|
+
import { x402ResourceServer } from "@x402/core/server";
|
|
3
|
+
import { type LocalAccount } from "viem";
|
|
4
|
+
import { type SekishoNetwork } from "./chains.js";
|
|
5
|
+
export interface SekishoFacilitatorOptions {
|
|
6
|
+
/** Wallet que envía las transacciones de liquidación (paga el gas en AVAX). */
|
|
7
|
+
account: LocalAccount;
|
|
8
|
+
network?: SekishoNetwork;
|
|
9
|
+
rpcUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Tipo que acepta x402ResourceServer como facilitator. */
|
|
12
|
+
export type SekishoFacilitatorClient = NonNullable<ConstructorParameters<typeof x402ResourceServer>[0]>;
|
|
13
|
+
/**
|
|
14
|
+
* Facilitator x402 en el mismo proceso (self-facilitation).
|
|
15
|
+
* Verifica y liquida pagos EIP-3009 directamente en Avalanche,
|
|
16
|
+
* sin depender de un servicio externo.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createSekishoFacilitator(options: SekishoFacilitatorOptions): x402Facilitator;
|
|
19
|
+
/**
|
|
20
|
+
* Convierte el facilitator local en el cliente que espera x402ResourceServer.
|
|
21
|
+
* En runtime solo enlaza verify/settle/getSupported; el cast ajusta el tipo
|
|
22
|
+
* de `network` (string → formato CAIP-2), que es idéntico en valor.
|
|
23
|
+
*/
|
|
24
|
+
export declare function toFacilitatorClient(facilitator: x402Facilitator): SekishoFacilitatorClient;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { x402Facilitator } from "@x402/core/facilitator";
|
|
2
|
+
import { toFacilitatorEvmSigner } from "@x402/evm";
|
|
3
|
+
import { registerExactEvmScheme } from "@x402/evm/exact/facilitator";
|
|
4
|
+
import { createWalletClient, http, publicActions } from "viem";
|
|
5
|
+
import { NETWORKS } from "./chains.js";
|
|
6
|
+
/**
|
|
7
|
+
* Facilitator x402 en el mismo proceso (self-facilitation).
|
|
8
|
+
* Verifica y liquida pagos EIP-3009 directamente en Avalanche,
|
|
9
|
+
* sin depender de un servicio externo.
|
|
10
|
+
*/
|
|
11
|
+
export function createSekishoFacilitator(options) {
|
|
12
|
+
const network = options.network ?? "avalancheFuji";
|
|
13
|
+
const config = NETWORKS[network];
|
|
14
|
+
const viemClient = createWalletClient({
|
|
15
|
+
account: options.account,
|
|
16
|
+
chain: config.chain,
|
|
17
|
+
transport: http(options.rpcUrl ?? config.rpcUrl),
|
|
18
|
+
}).extend(publicActions);
|
|
19
|
+
const signer = toFacilitatorEvmSigner({
|
|
20
|
+
address: options.account.address,
|
|
21
|
+
getCode: viemClient.getCode,
|
|
22
|
+
readContract: viemClient.readContract,
|
|
23
|
+
// Adaptador: misma llamada en runtime, solo ajusta el tipo para TypeScript
|
|
24
|
+
verifyTypedData: (args) => viemClient.verifyTypedData(args),
|
|
25
|
+
writeContract: viemClient.writeContract,
|
|
26
|
+
sendTransaction: viemClient.sendTransaction,
|
|
27
|
+
waitForTransactionReceipt: viemClient.waitForTransactionReceipt,
|
|
28
|
+
});
|
|
29
|
+
const facilitator = new x402Facilitator();
|
|
30
|
+
registerExactEvmScheme(facilitator, {
|
|
31
|
+
signer,
|
|
32
|
+
networks: `eip155:${config.chain.id}`,
|
|
33
|
+
});
|
|
34
|
+
return facilitator;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Convierte el facilitator local en el cliente que espera x402ResourceServer.
|
|
38
|
+
* En runtime solo enlaza verify/settle/getSupported; el cast ajusta el tipo
|
|
39
|
+
* de `network` (string → formato CAIP-2), que es idéntico en valor.
|
|
40
|
+
*/
|
|
41
|
+
export function toFacilitatorClient(facilitator) {
|
|
42
|
+
return {
|
|
43
|
+
verify: facilitator.verify.bind(facilitator),
|
|
44
|
+
settle: facilitator.settle.bind(facilitator),
|
|
45
|
+
getSupported: async () => facilitator.getSupported(),
|
|
46
|
+
};
|
|
47
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createSekishoClient, type SekishoClient, type SekishoClientOptions, type SekishoConfig, type PendingSplit, } from "./client.js";
|
|
2
|
+
export { NETWORKS, type NetworkConfig, type SekishoNetwork } from "./chains.js";
|
|
3
|
+
export { createPaymentOption, DEFAULT_FACILITATOR_URL, type PaymentOptionParams, type SekishoPaymentOption, } from "./x402.js";
|
|
4
|
+
export { createSekishoFetch, createSekishoPaymentClient, type SekishoAgentOptions, type SekishoFetch, type SekishoFetchOptions, } from "./agent.js";
|
|
5
|
+
export { createSekishoFacilitator, toFacilitatorClient, type SekishoFacilitatorClient, type SekishoFacilitatorOptions, } from "./facilitator.js";
|
|
6
|
+
export { createSekishoMcpPaywall, createSekishoMcpClient, type SekishoMcpPaywall, type SekishoMcpPaywallOptions, type SekishoMcpClient, type SekishoMcpClientOptions, } from "./mcp.js";
|
|
7
|
+
export { splitVaultAbi, splitVaultFactoryAbi, erc20Abi } from "./abi.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createSekishoClient, } from "./client.js";
|
|
2
|
+
export { NETWORKS } from "./chains.js";
|
|
3
|
+
export { createPaymentOption, DEFAULT_FACILITATOR_URL, } from "./x402.js";
|
|
4
|
+
export { createSekishoFetch, createSekishoPaymentClient, } from "./agent.js";
|
|
5
|
+
export { createSekishoFacilitator, toFacilitatorClient, } from "./facilitator.js";
|
|
6
|
+
export { createSekishoMcpPaywall, createSekishoMcpClient, } from "./mcp.js";
|
|
7
|
+
export { splitVaultAbi, splitVaultFactoryAbi, erc20Abi } from "./abi.js";
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createPaymentWrapper, wrapMCPClientWithPayment } from "@x402/mcp";
|
|
2
|
+
import type { x402Facilitator } from "@x402/core/facilitator";
|
|
3
|
+
import type { Address } from "viem";
|
|
4
|
+
import type { SekishoClient } from "./client.js";
|
|
5
|
+
import { type SekishoAgentOptions } from "./agent.js";
|
|
6
|
+
export interface SekishoMcpPaywallOptions {
|
|
7
|
+
sekisho: SekishoClient;
|
|
8
|
+
/** Facilitator que verifica y liquida (por ejemplo, createSekishoFacilitator). */
|
|
9
|
+
facilitator: x402Facilitator;
|
|
10
|
+
/** Wallet del vendedor (dueño del vault). */
|
|
11
|
+
merchant: Address;
|
|
12
|
+
/** Precio por llamada en USD, por ejemplo "0.01". */
|
|
13
|
+
price: string;
|
|
14
|
+
/** Se ejecuta después de cada pago liquidado. */
|
|
15
|
+
onSettled?: (info: {
|
|
16
|
+
toolName: string;
|
|
17
|
+
transaction: string;
|
|
18
|
+
}) => void | Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export type SekishoMcpPaywall = ReturnType<typeof createPaymentWrapper>;
|
|
21
|
+
/**
|
|
22
|
+
* Envoltura para tools MCP de pago. El payTo es el SplitVault del vendedor.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createSekishoMcpPaywall(options: SekishoMcpPaywallOptions): Promise<SekishoMcpPaywall>;
|
|
25
|
+
export interface SekishoMcpClientOptions extends SekishoAgentOptions {
|
|
26
|
+
name?: string;
|
|
27
|
+
}
|
|
28
|
+
export type SekishoMcpClient = ReturnType<typeof wrapMCPClientWithPayment>;
|
|
29
|
+
/** Cliente MCP para agentes que paga tools automáticamente. */
|
|
30
|
+
export declare function createSekishoMcpClient(options: SekishoMcpClientOptions): SekishoMcpClient;
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { createPaymentWrapper, wrapMCPClientWithPayment, x402ResourceServer, } from "@x402/mcp";
|
|
3
|
+
import { ExactEvmScheme } from "@x402/evm/exact/server";
|
|
4
|
+
import { createPaymentOption } from "./x402.js";
|
|
5
|
+
import { createSekishoPaymentClient } from "./agent.js";
|
|
6
|
+
import { toFacilitatorClient } from "./facilitator.js";
|
|
7
|
+
/**
|
|
8
|
+
* Envoltura para tools MCP de pago. El payTo es el SplitVault del vendedor.
|
|
9
|
+
*/
|
|
10
|
+
export async function createSekishoMcpPaywall(options) {
|
|
11
|
+
const option = await createPaymentOption(options.sekisho, {
|
|
12
|
+
merchant: options.merchant,
|
|
13
|
+
price: options.price,
|
|
14
|
+
});
|
|
15
|
+
const resourceServer = new x402ResourceServer(toFacilitatorClient(options.facilitator));
|
|
16
|
+
resourceServer.register(option.network, new ExactEvmScheme());
|
|
17
|
+
await resourceServer.initialize();
|
|
18
|
+
const accepts = await resourceServer.buildPaymentRequirements({
|
|
19
|
+
scheme: option.scheme,
|
|
20
|
+
network: option.network,
|
|
21
|
+
payTo: option.payTo,
|
|
22
|
+
price: option.price,
|
|
23
|
+
});
|
|
24
|
+
return createPaymentWrapper(resourceServer, {
|
|
25
|
+
accepts,
|
|
26
|
+
hooks: {
|
|
27
|
+
onAfterSettlement: async ({ toolName, settlement }) => {
|
|
28
|
+
await options.onSettled?.({ toolName, transaction: settlement.transaction });
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** Cliente MCP para agentes que paga tools automáticamente. */
|
|
34
|
+
export function createSekishoMcpClient(options) {
|
|
35
|
+
const mcpClient = new Client({ name: options.name ?? "sekisho-agent", version: "0.1.0" });
|
|
36
|
+
return wrapMCPClientWithPayment(mcpClient, createSekishoPaymentClient(options), {
|
|
37
|
+
autoPayment: true,
|
|
38
|
+
});
|
|
39
|
+
}
|
package/dist/x402.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Address } from "viem";
|
|
2
|
+
import type { SekishoClient } from "./client.js";
|
|
3
|
+
/** Facilitator x402 v2 con soporte para Avalanche Fuji y C-Chain. */
|
|
4
|
+
export declare const DEFAULT_FACILITATOR_URL = "https://facilitator.ultravioletadao.xyz";
|
|
5
|
+
export interface PaymentOptionParams {
|
|
6
|
+
/** Wallet del vendedor (dueño del vault). */
|
|
7
|
+
merchant: Address;
|
|
8
|
+
/** Precio en USD como texto, por ejemplo "0.01". */
|
|
9
|
+
price: string;
|
|
10
|
+
}
|
|
11
|
+
/** Opción de pago x402 v2 (esquema exact) lista para usar en `accepts`. */
|
|
12
|
+
export interface SekishoPaymentOption {
|
|
13
|
+
scheme: "exact";
|
|
14
|
+
network: `eip155:${number}`;
|
|
15
|
+
payTo: Address;
|
|
16
|
+
price: {
|
|
17
|
+
amount: string;
|
|
18
|
+
asset: Address;
|
|
19
|
+
extra: {
|
|
20
|
+
name: string;
|
|
21
|
+
version: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Construye la opción de pago x402 de un vendedor.
|
|
27
|
+
* El payTo es el SplitVault del vendedor, así que el fee de Sekisho
|
|
28
|
+
* se aplica automáticamente al repartir.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createPaymentOption(sekisho: SekishoClient, params: PaymentOptionParams): Promise<SekishoPaymentOption>;
|
package/dist/x402.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { parseUnits } from "viem";
|
|
2
|
+
/** Facilitator x402 v2 con soporte para Avalanche Fuji y C-Chain. */
|
|
3
|
+
export const DEFAULT_FACILITATOR_URL = "https://facilitator.ultravioletadao.xyz";
|
|
4
|
+
/**
|
|
5
|
+
* Construye la opción de pago x402 de un vendedor.
|
|
6
|
+
* El payTo es el SplitVault del vendedor, así que el fee de Sekisho
|
|
7
|
+
* se aplica automáticamente al repartir.
|
|
8
|
+
*/
|
|
9
|
+
export async function createPaymentOption(sekisho, params) {
|
|
10
|
+
const amount = parseUnits(params.price, 6);
|
|
11
|
+
if (amount <= 0n) {
|
|
12
|
+
throw new Error("Sekisho: el precio debe ser mayor a 0");
|
|
13
|
+
}
|
|
14
|
+
const payTo = await sekisho.getPayTo(params.merchant);
|
|
15
|
+
return {
|
|
16
|
+
scheme: "exact",
|
|
17
|
+
network: `eip155:${sekisho.config.chain.id}`,
|
|
18
|
+
payTo,
|
|
19
|
+
price: {
|
|
20
|
+
amount: amount.toString(),
|
|
21
|
+
asset: sekisho.config.usdc,
|
|
22
|
+
extra: { ...sekisho.config.usdcEip712 },
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,69 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zero-two-labs/sekisho",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "x402 payments with automatic revenue split on Avalanche",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"directories": {
|
|
7
|
+
"example": "examples"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"example:read": "tsx examples/read-config.ts",
|
|
13
|
+
"example:seller": "node --env-file=.env --import tsx examples/seller-server.ts",
|
|
14
|
+
"example:agent": "node --env-file=.env --import tsx examples/agent-pay.ts",
|
|
15
|
+
"example:mcp": "node --env-file=.env --import tsx examples/agent-mcp.ts",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"x402",
|
|
20
|
+
"avalanche",
|
|
21
|
+
"ai-agents",
|
|
22
|
+
"mcp",
|
|
23
|
+
"payments",
|
|
24
|
+
"usdc",
|
|
25
|
+
"revenue-split"
|
|
26
|
+
],
|
|
27
|
+
"author": "Zero Two Labs",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"type": "module",
|
|
30
|
+
"types": "dist/index.d.ts",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
33
|
+
"@x402/fetch": "^2.28.0",
|
|
34
|
+
"@x402/mcp": "^2.28.0",
|
|
35
|
+
"viem": "^2.57.7",
|
|
36
|
+
"zod": "^3.25.76"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@hono/node-server": "^2.1.5",
|
|
40
|
+
"@types/node": "^26.6.5",
|
|
41
|
+
"@x402/core": "^2.28.0",
|
|
42
|
+
"@x402/evm": "^2.28.0",
|
|
43
|
+
"@x402/hono": "^2.28.0",
|
|
44
|
+
"hono": "^4.13.13",
|
|
45
|
+
"tsx": "^4.23.15",
|
|
46
|
+
"typescript": "^7.0.2"
|
|
47
|
+
},
|
|
48
|
+
"exports": {
|
|
49
|
+
".": {
|
|
50
|
+
"types": "./dist/index.d.ts",
|
|
51
|
+
"import": "./dist/index.js"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"files": [
|
|
55
|
+
"dist",
|
|
56
|
+
"README.md",
|
|
57
|
+
"LICENSE"
|
|
58
|
+
],
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=20"
|
|
61
|
+
},
|
|
62
|
+
"repository": {
|
|
63
|
+
"type": "git",
|
|
64
|
+
"url": "git+https://github.com/usainbluntmx/sekisho.git"
|
|
65
|
+
},
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
}
|
|
69
|
+
}
|