@tabai/sdk 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +401 -0
- package/bin/tab.mjs +23 -0
- package/dist/_shared/abi.d.ts +150 -0
- package/dist/_shared/abi.d.ts.map +1 -0
- package/dist/_shared/abi.js +197 -0
- package/dist/_shared/abi.js.map +1 -0
- package/dist/_shared/chains.d.ts +118 -0
- package/dist/_shared/chains.d.ts.map +1 -0
- package/dist/_shared/chains.js +89 -0
- package/dist/_shared/chains.js.map +1 -0
- package/dist/_shared/hex.d.ts +35 -0
- package/dist/_shared/hex.d.ts.map +1 -0
- package/dist/_shared/hex.js +40 -0
- package/dist/_shared/hex.js.map +1 -0
- package/dist/_shared/index.d.ts +14 -0
- package/dist/_shared/index.d.ts.map +1 -0
- package/dist/_shared/index.js +14 -0
- package/dist/_shared/index.js.map +1 -0
- package/dist/_shared/keccak256.d.ts +29 -0
- package/dist/_shared/keccak256.d.ts.map +1 -0
- package/dist/_shared/keccak256.js +145 -0
- package/dist/_shared/keccak256.js.map +1 -0
- package/dist/_shared/result.d.ts +78 -0
- package/dist/_shared/result.d.ts.map +1 -0
- package/dist/_shared/result.js +61 -0
- package/dist/_shared/result.js.map +1 -0
- package/dist/cli/client-config.d.ts +155 -0
- package/dist/cli/client-config.d.ts.map +1 -0
- package/dist/cli/client-config.js +382 -0
- package/dist/cli/client-config.js.map +1 -0
- package/dist/cli/connect.d.ts +76 -0
- package/dist/cli/connect.d.ts.map +1 -0
- package/dist/cli/connect.js +158 -0
- package/dist/cli/connect.js.map +1 -0
- package/dist/cli/doctor.d.ts +57 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +253 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +13 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/main.d.ts +45 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +371 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +37 -0
- package/dist/errors.js.map +1 -0
- package/dist/http/client-402.d.ts +243 -0
- package/dist/http/client-402.d.ts.map +1 -0
- package/dist/http/client-402.js +515 -0
- package/dist/http/client-402.js.map +1 -0
- package/dist/http/headers.d.ts +173 -0
- package/dist/http/headers.d.ts.map +1 -0
- package/dist/http/headers.js +284 -0
- package/dist/http/headers.js.map +1 -0
- package/dist/http/index.d.ts +15 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +15 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/metering-claim.d.ts +82 -0
- package/dist/http/metering-claim.d.ts.map +1 -0
- package/dist/http/metering-claim.js +99 -0
- package/dist/http/metering-claim.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +40 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +50 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/assets.d.ts +31 -0
- package/dist/mcp/assets.d.ts.map +1 -0
- package/dist/mcp/assets.js +78 -0
- package/dist/mcp/assets.js.map +1 -0
- package/dist/mcp/index.d.ts +19 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +19 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/json-schema.d.ts +86 -0
- package/dist/mcp/json-schema.d.ts.map +1 -0
- package/dist/mcp/json-schema.js +215 -0
- package/dist/mcp/json-schema.js.map +1 -0
- package/dist/mcp/json.d.ts +43 -0
- package/dist/mcp/json.d.ts.map +1 -0
- package/dist/mcp/json.js +69 -0
- package/dist/mcp/json.js.map +1 -0
- package/dist/mcp/registry-client.d.ts +88 -0
- package/dist/mcp/registry-client.d.ts.map +1 -0
- package/dist/mcp/registry-client.js +158 -0
- package/dist/mcp/registry-client.js.map +1 -0
- package/dist/mcp/schemas.d.ts +82 -0
- package/dist/mcp/schemas.d.ts.map +1 -0
- package/dist/mcp/schemas.js +493 -0
- package/dist/mcp/schemas.js.map +1 -0
- package/dist/mcp/server.d.ts +97 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +285 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/settings.d.ts +90 -0
- package/dist/mcp/settings.d.ts.map +1 -0
- package/dist/mcp/settings.js +160 -0
- package/dist/mcp/settings.js.map +1 -0
- package/dist/mcp/toolset.d.ts +231 -0
- package/dist/mcp/toolset.d.ts.map +1 -0
- package/dist/mcp/toolset.js +760 -0
- package/dist/mcp/toolset.js.map +1 -0
- package/dist/payments/abi.d.ts +9 -0
- package/dist/payments/abi.d.ts.map +1 -0
- package/dist/payments/abi.js +17 -0
- package/dist/payments/abi.js.map +1 -0
- package/dist/payments/config.d.ts +199 -0
- package/dist/payments/config.d.ts.map +1 -0
- package/dist/payments/config.js +259 -0
- package/dist/payments/config.js.map +1 -0
- package/dist/payments/index.d.ts +13 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +13 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/payments/kuru.d.ts +191 -0
- package/dist/payments/kuru.d.ts.map +1 -0
- package/dist/payments/kuru.js +377 -0
- package/dist/payments/kuru.js.map +1 -0
- package/dist/payments/monad.d.ts +69 -0
- package/dist/payments/monad.d.ts.map +1 -0
- package/dist/payments/monad.js +306 -0
- package/dist/payments/monad.js.map +1 -0
- package/dist/payments/permit2.d.ts +118 -0
- package/dist/payments/permit2.d.ts.map +1 -0
- package/dist/payments/permit2.js +366 -0
- package/dist/payments/permit2.js.map +1 -0
- package/dist/payments/registry.d.ts +119 -0
- package/dist/payments/registry.d.ts.map +1 -0
- package/dist/payments/registry.js +199 -0
- package/dist/payments/registry.js.map +1 -0
- package/dist/payments/strategy.d.ts +80 -0
- package/dist/payments/strategy.d.ts.map +1 -0
- package/dist/payments/strategy.js +103 -0
- package/dist/payments/strategy.js.map +1 -0
- package/dist/proxy/hooks.d.ts +90 -0
- package/dist/proxy/hooks.d.ts.map +1 -0
- package/dist/proxy/hooks.js +35 -0
- package/dist/proxy/hooks.js.map +1 -0
- package/dist/proxy/index.d.ts +9 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +9 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/proxy/proxy.d.ts +156 -0
- package/dist/proxy/proxy.d.ts.map +1 -0
- package/dist/proxy/proxy.js +366 -0
- package/dist/proxy/proxy.js.map +1 -0
- package/dist/server/adapters/express.d.ts +89 -0
- package/dist/server/adapters/express.d.ts.map +1 -0
- package/dist/server/adapters/express.js +215 -0
- package/dist/server/adapters/express.js.map +1 -0
- package/dist/server/adapters/hono.d.ts +52 -0
- package/dist/server/adapters/hono.d.ts.map +1 -0
- package/dist/server/adapters/hono.js +61 -0
- package/dist/server/adapters/hono.js.map +1 -0
- package/dist/server/adapters/next.d.ts +52 -0
- package/dist/server/adapters/next.d.ts.map +1 -0
- package/dist/server/adapters/next.js +56 -0
- package/dist/server/adapters/next.js.map +1 -0
- package/dist/server/index.d.ts +30 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +30 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/metering.d.ts +209 -0
- package/dist/server/metering.d.ts.map +1 -0
- package/dist/server/metering.js +365 -0
- package/dist/server/metering.js.map +1 -0
- package/dist/server/post-paid.d.ts +355 -0
- package/dist/server/post-paid.d.ts.map +1 -0
- package/dist/server/post-paid.js +512 -0
- package/dist/server/post-paid.js.map +1 -0
- package/dist/x402/client.d.ts +203 -0
- package/dist/x402/client.d.ts.map +1 -0
- package/dist/x402/client.js +337 -0
- package/dist/x402/client.js.map +1 -0
- package/dist/x402/hub.d.ts +79 -0
- package/dist/x402/hub.d.ts.map +1 -0
- package/dist/x402/hub.js +164 -0
- package/dist/x402/hub.js.map +1 -0
- package/dist/x402/index.d.ts +27 -0
- package/dist/x402/index.d.ts.map +1 -0
- package/dist/x402/index.js +27 -0
- package/dist/x402/index.js.map +1 -0
- package/dist/x402/proxy.d.ts +162 -0
- package/dist/x402/proxy.d.ts.map +1 -0
- package/dist/x402/proxy.js +198 -0
- package/dist/x402/proxy.js.map +1 -0
- package/dist/x402/server.d.ts +162 -0
- package/dist/x402/server.d.ts.map +1 -0
- package/dist/x402/server.js +306 -0
- package/dist/x402/server.js.map +1 -0
- package/dist/x402/wire.d.ts +104 -0
- package/dist/x402/wire.d.ts.map +1 -0
- package/dist/x402/wire.js +265 -0
- package/dist/x402/wire.js.map +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2026 Tab Project Contributors
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
# @tabai/sdk
|
|
2
|
+
|
|
3
|
+
**Post-paid billing for autonomous agents on Monad.** Your agent calls a priced tool, gets the result immediately, and settles the bill later with its own keys. No prepayment, no held responses, no API key bought in advance.
|
|
4
|
+
|
|
5
|
+
This package is three things in one: an **MCP server** exposing four tools to any MCP client, a **CLI**, and a **TypeScript library** for building on the rail directly.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx -y @tabai/sdk connect
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
That is the whole setup step. It finds your MCP client's configuration file, backs it up, merges one entry, and prints the diff before it writes.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What is behind it
|
|
16
|
+
|
|
17
|
+
A Service meters your agent's usage into an **Open Tab** held in `TabBook` on Monad. Your agent settles that tab in USDC on the same chain, whenever it likes, signing with keys nobody else holds.
|
|
18
|
+
|
|
19
|
+
Settlement is one transaction. `TabSettlement.settle` moves the Asset to the Service's collection address and applies the Settlement to the Open Tab in the same block, atomically. There is no facilitator, no oracle, no bridge and no waiting: the transfer and the credit are the same state change, so nobody has to be trusted to say the money arrived.
|
|
20
|
+
|
|
21
|
+
That is why a credit limit here is a pure function of onchain history. It is computed from the Settlements the chain itself recorded and the Bonds the agent's counterparties have escrowed, and nothing an operator reports enters the figure.
|
|
22
|
+
|
|
23
|
+
**Costs.** Gas is paid in MON. Tab itself adds no fee: each Service sets its own price per tool, in integer base units of one asset, and the amount charged is the amount transferred.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
Requires Node `>= 20.10.0`.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx -y @tabai/sdk connect # wire it into an MCP client
|
|
33
|
+
npx -y @tabai/sdk doctor # check the whole installation, keylessly
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or as a dependency:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install @tabai/sdk
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`connect` supports `claude-code`, `claude-desktop`, `cursor`, `windsurf` and `vscode`, and takes `--client <id>`, `--config <path>` or `--dry-run`. Run it twice and the second run writes nothing: the merge is idempotent and leaves no second backup.
|
|
43
|
+
|
|
44
|
+
**It never writes a private key.** Signing keys are read from the environment at the moment a Settlement is broadcast, and nothing about them is copied into a client configuration file.
|
|
45
|
+
|
|
46
|
+
`doctor` reports what it could reach and warns rather than failing on what it could not. A missing agent address is a warning, not an error, because every read-only tool works without one.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## The four MCP tools
|
|
51
|
+
|
|
52
|
+
Each tool declares a JSON Schema for its input and its output, and validates its own input against the schema it published.
|
|
53
|
+
|
|
54
|
+
| Tool | What it does | Spends |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `tab_discover` | Lists Services, the assets each accepts, what each tool costs, and the Bond each has staked | nothing, and needs no key |
|
|
57
|
+
| `tab_call` | Calls a metered tool. The charge lands on the Open Tab and is settled later. With an x402 signer configured, a refusal that carries an x402 offer is prepaid instead | nothing at call time, unless it prepays |
|
|
58
|
+
| `tab_status` | Credit limit, Open Tab, prepaid credit and headroom, per asset, with recent Settlements | nothing, and needs no key |
|
|
59
|
+
| `tab_settle` | Pays down an Open Tab by sending a Settlement with the agent's own key | real funds |
|
|
60
|
+
|
|
61
|
+
Start with `tab_discover`, because `tab_call` needs a `serviceId` from its list.
|
|
62
|
+
|
|
63
|
+
### Nothing throws
|
|
64
|
+
|
|
65
|
+
Every fallible call returns `ok: false` with a `category`, a `code` and a `message`, so a model can decide what to do next rather than parse an exception.
|
|
66
|
+
|
|
67
|
+
The one failure worth handling by name is an agent with no headroom:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"ok": false,
|
|
72
|
+
"category": "LIMIT",
|
|
73
|
+
"code": "LIMIT_EXCEEDED",
|
|
74
|
+
"message": "the charge exceeds the Agent's headroom in this Asset",
|
|
75
|
+
"requiredBaseUnits": "10000",
|
|
76
|
+
"headroomBaseUnits": "2500"
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Both figures are present only on `LIMIT_EXCEEDED`, and they are there so the answer is actionable. **The correct response is to settle, not to retry**: retrying a call that exceeded a credit limit produces the same refusal at the same cost. A Settlement restores headroom in the block it lands.
|
|
81
|
+
|
|
82
|
+
### A new agent has no credit, and that is the rule
|
|
83
|
+
|
|
84
|
+
A credit limit is capped by the Bonds of counterparties the agent already has settlement history with. An agent with no history has no counterparties, so it has no limit and must settle before it can buy on credit. Its first Settlement banks prepaid credit and creates the history a limit is computed from.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## The CLI
|
|
89
|
+
|
|
90
|
+
The same package is a CLI. Every command reads the chain; one of them writes to it, and it says so before it does.
|
|
91
|
+
|
|
92
|
+
| Command | What it does | Spends |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `connect` | Writes the `tab` entry into your MCP client's configuration | nothing |
|
|
95
|
+
| `mcp` | Serves the four tools over MCP. This is what a client launches | nothing |
|
|
96
|
+
| `doctor` | Checks the installation against the live deployment | nothing, and needs no key |
|
|
97
|
+
| `status` | What an agent owes, may still spend, and has settled | nothing, and needs no key |
|
|
98
|
+
| `settle` | Pays down an Open Tab | real funds, and only with `--broadcast` |
|
|
99
|
+
|
|
100
|
+
`settle` is a dry run unless you ask otherwise. It checks the Service accepts the Asset, quotes the amount, and stops:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx -y @tabai/sdk settle \
|
|
104
|
+
--agent 0x1f6f…0542 \
|
|
105
|
+
--asset 10143:0x4802…4083 \
|
|
106
|
+
--service 0x7461…0000 \
|
|
107
|
+
--amount 47000
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
Dry run. Nothing was broadcast.
|
|
112
|
+
chain id 10143
|
|
113
|
+
amount 47000
|
|
114
|
+
|
|
115
|
+
Add --broadcast to send it. This spends real funds.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Amounts are always base units.** USDC has six decimals, so `47000` is 0.047 USDC. Nothing in this system takes a decimal, holds a price, or consults a rate.
|
|
119
|
+
|
|
120
|
+
`mcp` serves over stdio by default, and over streamable HTTP with `--http [--port <n>] [--host <h>] [--endpoint <p>]`.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
`doctor` warns when two things are missing, and both live in a config file rather than the environment, because neither is a secret: the agent whose Open Tab a call meters to, and where a Service can be reached.
|
|
127
|
+
|
|
128
|
+
Put a `tab.config.mjs` beside your project, or in any parent directory:
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
import { Wallet, JsonRpcProvider } from "ethers";
|
|
132
|
+
import { createMonadStrategy } from "@tabai/sdk";
|
|
133
|
+
|
|
134
|
+
export default {
|
|
135
|
+
// Whose Open Tab a metered call lands on.
|
|
136
|
+
agent: process.env.AGENT_ADDRESS,
|
|
137
|
+
|
|
138
|
+
registryUrl: process.env.NEXT_PUBLIC_REGISTRY_API_URL,
|
|
139
|
+
|
|
140
|
+
// The chain records no URL for a Service, deliberately, so the address lives here.
|
|
141
|
+
services: [
|
|
142
|
+
{
|
|
143
|
+
serviceId: "0x7461622e64656d6f000000000000000000000000000000000000000000000000",
|
|
144
|
+
name: "tab.demo",
|
|
145
|
+
endpoint: "http://localhost:8788",
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
|
|
149
|
+
// The prepaid fallback, a factory for the same reason the strategies are.
|
|
150
|
+
// Called only when a Service has refused a call on credit and offered x402
|
|
151
|
+
// for it. Returning undefined declines, and the refusal stands as LIMIT_EXCEEDED.
|
|
152
|
+
x402: () =>
|
|
153
|
+
process.env.AGENT_PRIVATE_KEY === undefined
|
|
154
|
+
? undefined
|
|
155
|
+
: new Wallet(process.env.AGENT_PRIVATE_KEY, new JsonRpcProvider(process.env.MONAD_RPC_URL)),
|
|
156
|
+
|
|
157
|
+
// A factory, not an object: the signer is built only if something settles,
|
|
158
|
+
// so every read stays keyless.
|
|
159
|
+
strategies: [
|
|
160
|
+
() => {
|
|
161
|
+
if (process.env.AGENT_PRIVATE_KEY === undefined) return undefined;
|
|
162
|
+
return createMonadStrategy({
|
|
163
|
+
signer: new Wallet(process.env.AGENT_PRIVATE_KEY, new JsonRpcProvider(process.env.MONAD_RPC_URL)),
|
|
164
|
+
tabSettlement: process.env.TAB_SETTLEMENT_ADDRESS,
|
|
165
|
+
assets: {
|
|
166
|
+
"10143:0x480209747417f5c830fda188a9b9acfa70bc4083": {
|
|
167
|
+
chainId: 10143n,
|
|
168
|
+
address: "0x480209747417f5c830fda188a9b9acfa70bc4083",
|
|
169
|
+
decimals: 6,
|
|
170
|
+
symbol: "mUSDC",
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The key is read at the moment a Settlement is built, and never from this file. `tab_discover`, `tab_status` and `doctor` never call the factory, which is what keeps every read on this rail keyless.
|
|
180
|
+
|
|
181
|
+
**A factory may decline.** Returning `undefined`, as the one above does when no key is set, means "not available here" rather than "this config is broken": the strategy is skipped and everything else in the file stands. That is the whole reason the entry is a factory rather than an object, and it lets one config file serve a read-only process and a settling one without branching.
|
|
182
|
+
|
|
183
|
+
### Environment
|
|
184
|
+
|
|
185
|
+
| Variable | Needed for |
|
|
186
|
+
| --- | --- |
|
|
187
|
+
| `MONAD_RPC_URL` | every read. The MCP server and `doctor` need only this |
|
|
188
|
+
| `MONAD_CHAIN_ID` | `143` for Mainnet, `10143` for Testnet. Defaults to Testnet |
|
|
189
|
+
| `TAB_BOOK_ADDRESS`, `TAB_SETTLEMENT_ADDRESS`, `SERVICE_REGISTRY_ADDRESS`, `BOND_ADDRESS` | resolving credit, Services and Bond |
|
|
190
|
+
| `NEXT_PUBLIC_REGISTRY_API_URL` | the Service directory and an agent's history, if you use the read API rather than the chain |
|
|
191
|
+
| `AGENT_PRIVATE_KEY` | broadcasting a Settlement, and nothing else. Never written to a configuration file |
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## As a library
|
|
196
|
+
|
|
197
|
+
Every export is typed, with the types shipped in the package. It carries no workspace dependency, so it installs and type-checks on its own.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { createTabToolset, createTab402Client, createMonadStrategy } from "@tabai/sdk";
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The main surfaces:
|
|
204
|
+
|
|
205
|
+
| Import | What it is |
|
|
206
|
+
| --- | --- |
|
|
207
|
+
| `createTabToolset` | The four tools as plain functions, for embedding without MCP |
|
|
208
|
+
| `createTabMcpServer` | The MCP server itself |
|
|
209
|
+
| `createTab402Client` | An HTTP client that understands the post-paid `402` and its charge headers |
|
|
210
|
+
| `tabPostPaid`, `honoTabPostPaid`, `expressTabPostPaid`, `withTabPostPaid` | Server plugins that meter a route after it has already responded |
|
|
211
|
+
| `createTabProxy` | A reverse proxy that meters an upstream you do not control |
|
|
212
|
+
| `createX402Client`, `signExactPayment` | The x402 side of the Agent: sign an EIP-3009 authorization for an `exact` requirement and repeat the request with it |
|
|
213
|
+
| `handlePrepaidRequest`, `exactRequirementFor`, `createX402Facilitator` | The x402 side of a Service: offer a payment on a `402`, and take one through a facilitator |
|
|
214
|
+
| `createX402FrontedProxy`, `createX402UpstreamPricing` | Buy now, pay later: front an x402 upstream, pay it, and meter the Agent |
|
|
215
|
+
| `fetchHubManifest` | Monad's API Hub manifest, as tools of the Service fronting a provider |
|
|
216
|
+
| `createMonadStrategy`, `createStrategyRegistry` | The Monad payment strategy, and the registry that resolves strategies |
|
|
217
|
+
| `createKuruFundedStrategy`, `createKuruOnchainRouter` | Settle in any asset: swap the shortfall in through Kuru before the Monad strategy settles |
|
|
218
|
+
| `revertMappingFor` | The single table mapping a contract revert to a category, code, disposition and remedy |
|
|
219
|
+
|
|
220
|
+
### Running a metered Service
|
|
221
|
+
|
|
222
|
+
Deliver first, charge after. The plugin adds exactly one status code to your surface, a `402` when a charge would exceed the caller's credit limit.
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
import { honoTabPostPaid } from "@tabai/sdk";
|
|
226
|
+
|
|
227
|
+
app.use("/meter/*", honoTabPostPaid({ serviceId, priceOf, tabBook }));
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Mount it under `/meter/`: `tab_call` sends a call to `<endpoint>/meter/<tool>`, so the endpoint in `tab.config` is the Service's root and `/hub/<prefix>` sits beside the tools.
|
|
231
|
+
|
|
232
|
+
A gateway anyone can reach requires a signature on every metered call, and the Agent gives its own: put `headers: agentSignedMetering(agentSigner)` on the Service entry in `tab.config` and `tab_call` signs a digest of the method, path, Agent, tool, units and a timestamp with the Agent's key, sent as `Tab-Agent-Signature`. The key is built per call and never for a read, and it signs only when it is the Agent the call is metered against; for anyone else it adds nothing and the Service decides. A Service's own front can sign the same digest with the operator key instead.
|
|
233
|
+
|
|
234
|
+
### Adding a strategy
|
|
235
|
+
|
|
236
|
+
A strategy is how an agent pays. On Monad there is exactly one way, `TabSettlement.settle`, and the shipped strategy does that with an `ethers` signer. The seam still exists so that a different signer, a smart account, a session key, or a test double can stand behind the same call without the SDK caring which.
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
export interface PaymentStrategy {
|
|
240
|
+
readonly id: string;
|
|
241
|
+
readonly chainIds: readonly bigint[];
|
|
242
|
+
supports(asset: AssetRef): boolean;
|
|
243
|
+
quote(request: ChargeRequest): Promise<Result<ChargeQuote>>;
|
|
244
|
+
settle(request: SettleRequest): Promise<Result<SettlementReceipt>>;
|
|
245
|
+
settleBatch?(requests: readonly SettleRequest[]): Promise<Result<readonly SettlementReceipt[]>>;
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
A receipt carries the transaction hash and, once the receipt is read, the `settlementId`, `applied` and `toPrepaid` figures straight off the `Settled` event. `settleBatch` maps onto `TabSettlement.settleBatch`, which settles several tabs in one transaction.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## x402: prepaid fallback and buy-now-pay-later
|
|
254
|
+
|
|
255
|
+
x402 is the prepaid protocol: a server answers `402` with a `PAYMENT-REQUIRED` header naming what it accepts, the client signs a payment and repeats the request with `PAYMENT-SIGNATURE`, and the server returns the resource once a facilitator has settled the payment on chain. Tab is the opposite model, and this package makes the two meet in two places.
|
|
256
|
+
|
|
257
|
+
**The offer on a credit refusal.** A Tab Service that refuses a call on `LimitExceeded` can put an x402 `exact` requirement for the same charge beside its `Tab-Charge-*` block. An Agent that would rather pay for that one call than settle its tab first takes the offer; one that would rather settle ignores it. When the offer is taken, the facilitator moves the Asset to the Service's Collection address, the work is delivered, and nothing lands on the Open Tab, because nothing is owed.
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
// A Service, on a Hono route
|
|
261
|
+
const requirement = exactRequirementFor({ chainId: 10143n, asset, amount, payTo: collectionAddress });
|
|
262
|
+
// On LimitExceeded: onLimitExceeded: (ctx) => jsonResponse(ctx.status, { ...ctx.headers, ...paymentRequiredHeaders(paymentRequiredFor({ resource, accepts: [requirement.value] })).value }, ctx.body)
|
|
263
|
+
// On a request carrying PAYMENT-SIGNATURE:
|
|
264
|
+
const outcome = await handlePrepaidRequest({ facilitator: createX402Facilitator(), payload, requirements: requirement.value, resource, deliver });
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
`handlePrepaidRequest` runs x402's default flow and no other: verify through the facilitator, deliver, settle through the facilitator, answer with `PAYMENT-RESPONSE`. A payment that does not verify is answered `402` with the reason and nothing is delivered; a delivery that failed is never settled, on the same rule the post-paid plugin meters no failed response. Monad's facilitator at `x402-facilitator.molandak.org` is the default and settles `exact` on Mainnet and Testnet.
|
|
268
|
+
|
|
269
|
+
On the Agent's side, `createTab402Client` and `tab_call` take the offer when, and only when, an x402 signer is configured. The signer comes from `tab.config`'s `x402` entry, a factory called at the moment a refusal carries an offer and never before, so every read stays keyless. In the library client the repeat still happens first: a `402` is answered by one repeat, and only a `402` that stands after it and carries `PAYMENT-REQUIRED` is paid. `tab_call`, which never repeats, takes the offer on the first refusal, and reports the payment:
|
|
270
|
+
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"ok": true,
|
|
274
|
+
"result": { "quote": "42" },
|
|
275
|
+
"charge": { "amountBaseUnits": "10000", "asset": "10143:0x534b…43a3", "tool": "0x71…" },
|
|
276
|
+
"tab": { "openTabBaseUnits": "40000", "headroomBaseUnits": "500", "asset": "10143:0x534b…43a3" },
|
|
277
|
+
"x402": {
|
|
278
|
+
"txHash": "0xef…",
|
|
279
|
+
"network": "eip155:10143",
|
|
280
|
+
"amountBaseUnits": "10000",
|
|
281
|
+
"asset": "10143:0x534b…43a3",
|
|
282
|
+
"payTo": "0x9d3d…d837",
|
|
283
|
+
"payer": "0x19e7…ff2a",
|
|
284
|
+
"explorerUrl": "https://testnet.monadvision.com/tx/0xef…"
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
`charge` and `tab` are the refusal the call was answered with; `x402` is what paid for it instead.
|
|
290
|
+
|
|
291
|
+
**Buy now, pay later for x402 APIs.** The reverse direction is the one that changes what an Agent can do. A Tab Service can front any x402 upstream: the Agent calls the Service on credit, the Service pays the upstream with its operator's key, and the Service meters the Agent's Open Tab for the upstream's price plus a margin. The Agent never signs and never holds the upstream's currency.
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
const pricing = createX402UpstreamPricing({ tool, margin: { bps: 500n } });
|
|
295
|
+
const metering = tabPostPaid({ serviceId, asset, tabBook, priceOf: pricing.priceOf });
|
|
296
|
+
const proxy = createX402FrontedProxy({
|
|
297
|
+
upstream: "https://api.nansen.ai/api/v1",
|
|
298
|
+
stripPrefix: "/hub/nansen",
|
|
299
|
+
signer: operatorWallet,
|
|
300
|
+
asset,
|
|
301
|
+
pricing,
|
|
302
|
+
metering,
|
|
303
|
+
preflight: async ({ agent, amount }) => simulateDelivery(agent, amount),
|
|
304
|
+
});
|
|
305
|
+
app.all("/hub/nansen/*", (c) => proxy(c.req.raw));
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
The price is known only after the upstream's `402`, so `pricing` is a book the forward writes and `priceOf` reads, keyed by the request. **The amount rides in the unit count, not the unit price.** `TabBook.recordDelivery` refuses any unit price the applied price list does not hold, and a fronted price varies per call, so the Service publishes a small fixed unit for the fronted tool, one base unit by default, and a call consumes as many units as it cost. Without that published price every fronted delivery reverts `UnknownTool`, the plugin delivers anyway because a broken price list is the Service's fault, and the Service pays the upstream for work it bills nobody. `unitBaseUnits` sets a coarser unit, rounded up so the Service is never left short. `preflight` runs between the upstream's `402` and the operator's signature, with the quoted amount in hand: a Service simulates the delivery against `TabBook` there and refuses an Agent with no headroom before its own funds move. Only `exact` with EIP-3009 is signed, on the Service's own chain and Asset; an upstream that accepts nothing the Service can pay in is answered with why, and nothing is metered.
|
|
309
|
+
|
|
310
|
+
`fetchHubManifest` reads Monad's API Hub, which fronts 74 pay-per-request providers behind one x402 endpoint, and `tab_discover` lists a fronted provider's endpoints under the Service as the tools they are, with the Hub's per-call price in base units:
|
|
311
|
+
|
|
312
|
+
```js
|
|
313
|
+
services: [{ serviceId, endpoint, hub: { provider: "defillama", prefix: "apihub" } }]
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The reference metering gateway mounts both: `GATEWAY_HUB_UPSTREAMS` names the upstreams, `X402_ENABLED` and `X402_FACILITATOR_URL` govern the offer on a `402`, and `GATEWAY_COLLECTION_ADDRESS` is the `payTo` fallback when `ServiceRegistry.collectionOf` cannot be read.
|
|
317
|
+
|
|
318
|
+
**What is official and what is not.** The types, the three header codecs and the facilitator HTTP client are `@x402/core`, the reference implementation. The EIP-3009 signing is this package's own, over ethers rather than the reference client's viem, and it is checked two ways: every test recovers the signer with `verifyTypedData`, and the reference client was run over the same authorization while this was written, producing the same signature byte for byte. The request handling is this package's own because the reference server middleware gates every request on payment, which is the model Tab exists to replace.
|
|
319
|
+
|
|
320
|
+
### Settle in any asset through Kuru
|
|
321
|
+
|
|
322
|
+
`TabSettlement.settle` moves the Asset the tab is denominated in. An Agent that holds MON, or a different stablecoin, can still settle: `createKuruFundedStrategy` wraps the Monad strategy, reads the Agent's balance of the Asset before every Settlement, and when it is short, swaps the shortfall in from a configured source token through Kuru, Monad's on-chain order book, then settles. The Settlement is still the inner strategy's transaction.
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
import { createKuruFundedStrategy, createKuruOnchainRouter, KURU_DEPLOYMENTS, KURU_NATIVE_TOKEN, kuruRouteKey } from "@tabai/sdk";
|
|
326
|
+
|
|
327
|
+
const inner = createMonadStrategy({ signer, tabSettlement, assets });
|
|
328
|
+
const strategy = createKuruFundedStrategy({
|
|
329
|
+
inner,
|
|
330
|
+
signer,
|
|
331
|
+
kuru: {
|
|
332
|
+
source: { address: KURU_NATIVE_TOKEN, decimals: 18, symbol: "MON" },
|
|
333
|
+
maxSourceAmount: 5n * 10n ** 18n,
|
|
334
|
+
router: createKuruOnchainRouter({
|
|
335
|
+
signer,
|
|
336
|
+
router: KURU_DEPLOYMENTS.mainnet.router,
|
|
337
|
+
routes: {
|
|
338
|
+
[kuruRouteKey(KURU_NATIVE_TOKEN, usdc.address)]: {
|
|
339
|
+
markets: [KURU_DEPLOYMENTS.mainnet.markets["MON-USDC"]],
|
|
340
|
+
isBuy: [false],
|
|
341
|
+
nativeSend: [true],
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
slippageBps: 100,
|
|
345
|
+
}),
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The swap runs through a `KuruRouter`, a two-method seam: `quote` says how much of the source token buys the shortfall, `swap` executes it. `createKuruOnchainRouter` is the shipped implementation over Kuru's `Router.anyToAnySwap`, quoting by simulation at the amount that will be sent and passing the shortfall as the swap's minimum out, so a Settlement is either fully funded or the swap reverts. A test hands in a fake router. The Router is deployed on Testnet and Mainnet; Kuru's aggregator is Mainnet only and is not used here, and neither is Kuru's own SDK, which pins ethers 5 and takes amounts as floating point.
|
|
351
|
+
|
|
352
|
+
### Configuration keys
|
|
353
|
+
|
|
354
|
+
| Key | Where | What it does |
|
|
355
|
+
| --- | --- | --- |
|
|
356
|
+
| `x402` | `tab.config` | A factory returning an x402 signer, or `undefined` to decline. Called only when a refusal carries an offer |
|
|
357
|
+
| `services[].hub` | `tab.config` | `{ provider, prefix?, manifestUrl? }`: the API Hub provider a Service fronts, listed by `tab_discover` |
|
|
358
|
+
| `x402` | `createTab402Client` | `{ signer, chainId?, asset?, maxAmount?, onPayment? }`: the same fallback, for the library client |
|
|
359
|
+
| `upstreamPayment` | `createX402FrontedProxy` | `{ chainId, asset, signer? }`: where the upstream is paid when that is not the Service's own chain and Asset. The API Hub takes Mainnet USDC only, so a Testnet Service pays there and meters here, base unit for base unit |
|
|
360
|
+
| `X402_ENABLED`, `X402_FACILITATOR_URL`, `GATEWAY_COLLECTION_ADDRESS`, `GATEWAY_HUB_UPSTREAMS`, `GATEWAY_X402_PRIVATE_KEY` | gateway environment | The offer on a `402`, the facilitator, the `payTo` fallback, the fronted upstreams (each with an optional `payOn: { chainId, asset }`), and an optional dedicated paying key |
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Network
|
|
365
|
+
|
|
366
|
+
Tab is deployed on both Monad networks, and `MONAD_CHAIN_ID` picks which one this package talks to.
|
|
367
|
+
|
|
368
|
+
| | Monad Mainnet | Monad Testnet |
|
|
369
|
+
| --- | --- | --- |
|
|
370
|
+
| Chain id | `143` | `10143` |
|
|
371
|
+
| RPC | `https://rpc.monad.xyz` | `https://testnet-rpc.monad.xyz` |
|
|
372
|
+
| Explorer | `https://monadvision.com` | `https://testnet.monadvision.com` |
|
|
373
|
+
| Assets | USDC, AUSD | Circle's USDC, and `mUSDC`, a test token |
|
|
374
|
+
|
|
375
|
+
| Contract | Mainnet | Testnet |
|
|
376
|
+
| --- | --- | --- |
|
|
377
|
+
| `ServiceRegistry` | `0x4F791F13F94944fCB2F884f8C7991cAa583884A6` | `0x3638DB35A76E5a22EA1E827636dA994be622c139` |
|
|
378
|
+
| `Bond` | `0xbA86C0D053ba88afDECbED8aBa5b2eC3973fb230` | `0x29aDfD90Fc7c9026563Fc60651f696ab089080E7` |
|
|
379
|
+
| `TabBook` | `0x0Dabf8E52280D0F128f546602a99b6DC4fbb80DC` | `0x87571030cCe27C84836bAfF85288eB1d85d908a4` |
|
|
380
|
+
| `TabSettlement` | `0x32A96bfEABe766B4898b961B333B7B89f079a9a9` | `0x654Fac48185e4B71779eEc2457B1F24aEdf46717` |
|
|
381
|
+
| `CurationMultisig` (2-of-3) | `0x123c19F46C38d5b4E922D1297250a71A03DFFD17` | |
|
|
382
|
+
| `mUSDC` | | `0x480209747417f5c830fDA188a9b9AcFa70Bc4083` |
|
|
383
|
+
|
|
384
|
+
Mainnet USDC is `0x754704Bc059F8C67012fEd69BC8A327a5aafb603` and AUSD is `0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a`.
|
|
385
|
+
Testnet USDC is `0x534b2f3A21130d7a60830c2Df862319e593943A3`, from Circle's faucet; MON for gas comes from `https://faucet.monad.xyz`.
|
|
386
|
+
|
|
387
|
+
A Settlement is final when its block is. **Nothing in an agent's request path waits for anything**: a metered call completes immediately, and headroom is restored in the block the Settlement lands.
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Status
|
|
392
|
+
|
|
393
|
+
The contracts are live on Mainnet and Testnet, and everything in this package runs against them today.
|
|
394
|
+
A hosted read API, a public demo Service endpoint and a Dashboard are coming soon on Monad.
|
|
395
|
+
Until then, `tab_discover` and `tab_status` need a Tab registry you point `registryUrl` at, and a Service's `endpoint` is wherever that Service runs.
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Built by
|
|
400
|
+
|
|
401
|
+
Emad Qureshi. MIT licensed.
|
package/bin/tab.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The `tab` executable.
|
|
4
|
+
*
|
|
5
|
+
* A thin shim over `runCli`, and thin on purpose: the CLI is ordinary library
|
|
6
|
+
* code in `src/cli/`, which is what lets the tests drive every command in
|
|
7
|
+
* process with an injected environment and injected input and output, instead of
|
|
8
|
+
* spawning a shell and parsing what comes back.
|
|
9
|
+
*
|
|
10
|
+
* The shim owns three things the library deliberately does not: reading
|
|
11
|
+
* `process.argv`, setting the exit code, and the last-resort handler. Nothing in
|
|
12
|
+
* `runCli` throws, so the `catch` is a backstop for a bug in this file or a
|
|
13
|
+
* failure to load the build at all.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { runCli } from "../dist/cli/main.js";
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
process.exitCode = await runCli(process.argv.slice(2));
|
|
20
|
+
} catch (error) {
|
|
21
|
+
process.stderr.write(`tab: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
22
|
+
process.exitCode = 1;
|
|
23
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type { Bytes32 } from "./hex.js";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical event signatures, the exact strings the topic hash is taken over.
|
|
4
|
+
* No spaces, no parameter names, canonical types.
|
|
5
|
+
*/
|
|
6
|
+
export declare const EVENT_SIGNATURES: {
|
|
7
|
+
/** `TabBook.SettlementApplied`: a Settlement lowered an Open Tab. `topics[1]` is the settlement id. */
|
|
8
|
+
readonly SettlementApplied: "SettlementApplied(bytes32,address,bytes32,address,uint256,uint256,uint128)";
|
|
9
|
+
/** `TabBook.DeliveryRecorded`: a Service metered usage into an Open Tab. `topics[1]` is the Agent. */
|
|
10
|
+
readonly DeliveryRecorded: "DeliveryRecorded(address,bytes32,address,bytes32,uint32,uint256,uint64)";
|
|
11
|
+
/** `TabBook.HistoryExtended`: the Agent's history commitment advanced by one record. */
|
|
12
|
+
readonly HistoryExtended: "HistoryExtended(address,address,bytes32,uint32,(bytes32,address,uint128,uint64,uint64,bool,bool))";
|
|
13
|
+
/** `TabBook.TabDelinquent`: a Settlement Window closed with the tab still open. */
|
|
14
|
+
readonly TabDelinquent: "TabDelinquent(bytes32,address,bytes32,address,uint128,uint64)";
|
|
15
|
+
/** `TabBook.TabDelinquencyCleared`: the delinquent tab settled to zero. */
|
|
16
|
+
readonly TabDelinquencyCleared: "TabDelinquencyCleared(bytes32,address,address)";
|
|
17
|
+
/** `TabSettlement.Settled`: the Asset moved from the Agent to the Service's Collection address. */
|
|
18
|
+
readonly Settled: "Settled(bytes32,address,bytes32,address,uint128,uint128,uint128,address)";
|
|
19
|
+
/**
|
|
20
|
+
* `TabSettlement.SettledGasless`: the Settlement arrived on the Agent's Permit2 signature and
|
|
21
|
+
* `topics[2]` is the relayer that paid for it. Always follows a `Settled` with the same id.
|
|
22
|
+
*/
|
|
23
|
+
readonly SettledGasless: "SettledGasless(bytes32,address)";
|
|
24
|
+
/** `Bond.BondFunded`: stake entered the escrow. */
|
|
25
|
+
readonly BondFunded: "BondFunded(bytes32,address,uint128,address)";
|
|
26
|
+
/** `Bond.BondWithdrawn`: stake left the escrow. */
|
|
27
|
+
readonly BondWithdrawn: "BondWithdrawn(bytes32,address,uint128,address)";
|
|
28
|
+
/** ERC-20 `Transfer`, for reading balances and payouts off the Asset contract. */
|
|
29
|
+
readonly Transfer: "Transfer(address,address,uint256)";
|
|
30
|
+
};
|
|
31
|
+
/** Name of an event whose signature this module pins. */
|
|
32
|
+
export type EventName = keyof typeof EVENT_SIGNATURES;
|
|
33
|
+
/**
|
|
34
|
+
* `topics[0]` for each pinned event: the Keccak-256 hash of its canonical
|
|
35
|
+
* signature. Derived rather than transcribed, so a signature edit cannot leave a
|
|
36
|
+
* stale hash behind.
|
|
37
|
+
*/
|
|
38
|
+
export declare const EVENT_TOPIC0: Readonly<Record<EventName, Bytes32>>;
|
|
39
|
+
/** `topics[0]` for a pinned event. */
|
|
40
|
+
export declare const eventTopic0: (name: EventName) => Bytes32;
|
|
41
|
+
/**
|
|
42
|
+
* The witness struct, exactly as `TabSettlement.WITNESS_TYPE` declares it.
|
|
43
|
+
* `surface` is the `TabSettlement` address and `chainId` the chain it lives on.
|
|
44
|
+
*/
|
|
45
|
+
export declare const TAB_SETTLEMENT_WITNESS_TYPE: "TabSettlement(bytes32 serviceId,address asset,uint128 amount,address surface,uint256 chainId)";
|
|
46
|
+
/** `keccak256(TAB_SETTLEMENT_WITNESS_TYPE)`, the same value as `TabSettlement.WITNESS_TYPEHASH`. */
|
|
47
|
+
export declare const TAB_SETTLEMENT_WITNESS_TYPEHASH: Bytes32;
|
|
48
|
+
/**
|
|
49
|
+
* What the contract passes Permit2 as `witnessTypeString`, exactly as
|
|
50
|
+
* `TabSettlement.WITNESS_TYPE_STRING` declares it. Permit2 appends it to
|
|
51
|
+
* `PERMIT2_WITNESS_TRANSFER_FROM_STUB`.
|
|
52
|
+
*/
|
|
53
|
+
export declare const PERMIT2_WITNESS_TYPE_STRING: "TabSettlement witness)TabSettlement(bytes32 serviceId,address asset,uint128 amount,address surface,uint256 chainId)TokenPermissions(address token,uint256 amount)";
|
|
54
|
+
/** Permit2's own `_PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB`. */
|
|
55
|
+
export declare const PERMIT2_WITNESS_TRANSFER_FROM_STUB: "PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,";
|
|
56
|
+
/** The full primary type Permit2 hashes, and its typehash. */
|
|
57
|
+
export declare const PERMIT2_WITNESS_TRANSFER_FROM_TYPE: "PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,TabSettlement witness)TabSettlement(bytes32 serviceId,address asset,uint128 amount,address surface,uint256 chainId)TokenPermissions(address token,uint256 amount)";
|
|
58
|
+
export declare const PERMIT2_WITNESS_TRANSFER_FROM_TYPEHASH: Bytes32;
|
|
59
|
+
/** Permit2's EIP-712 domain name. Its domain has no `version`. */
|
|
60
|
+
export declare const PERMIT2_DOMAIN_NAME: "Permit2";
|
|
61
|
+
/**
|
|
62
|
+
* The EIP-712 domain an Agent signs a gasless Settlement under: Permit2's, on
|
|
63
|
+
* the chain the Settlement happens on.
|
|
64
|
+
*/
|
|
65
|
+
export declare function permit2Domain(chainId: number | bigint, permit2: `0x${string}`): {
|
|
66
|
+
readonly name: "Permit2";
|
|
67
|
+
readonly chainId: bigint;
|
|
68
|
+
readonly verifyingContract: `0x${string}`;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* The typed-data types for `signTypedData`, primary type
|
|
72
|
+
* `PermitWitnessTransferFrom`. Field order matches Permit2's stub and the
|
|
73
|
+
* witness type above; the referenced structs are what the type string names.
|
|
74
|
+
*/
|
|
75
|
+
export declare const PERMIT2_WITNESS_TRANSFER_FROM_TYPES: {
|
|
76
|
+
readonly PermitWitnessTransferFrom: readonly [{
|
|
77
|
+
readonly name: "permitted";
|
|
78
|
+
readonly type: "TokenPermissions";
|
|
79
|
+
}, {
|
|
80
|
+
readonly name: "spender";
|
|
81
|
+
readonly type: "address";
|
|
82
|
+
}, {
|
|
83
|
+
readonly name: "nonce";
|
|
84
|
+
readonly type: "uint256";
|
|
85
|
+
}, {
|
|
86
|
+
readonly name: "deadline";
|
|
87
|
+
readonly type: "uint256";
|
|
88
|
+
}, {
|
|
89
|
+
readonly name: "witness";
|
|
90
|
+
readonly type: "TabSettlement";
|
|
91
|
+
}];
|
|
92
|
+
readonly TokenPermissions: readonly [{
|
|
93
|
+
readonly name: "token";
|
|
94
|
+
readonly type: "address";
|
|
95
|
+
}, {
|
|
96
|
+
readonly name: "amount";
|
|
97
|
+
readonly type: "uint256";
|
|
98
|
+
}];
|
|
99
|
+
readonly TabSettlement: readonly [{
|
|
100
|
+
readonly name: "serviceId";
|
|
101
|
+
readonly type: "bytes32";
|
|
102
|
+
}, {
|
|
103
|
+
readonly name: "asset";
|
|
104
|
+
readonly type: "address";
|
|
105
|
+
}, {
|
|
106
|
+
readonly name: "amount";
|
|
107
|
+
readonly type: "uint128";
|
|
108
|
+
}, {
|
|
109
|
+
readonly name: "surface";
|
|
110
|
+
readonly type: "address";
|
|
111
|
+
}, {
|
|
112
|
+
readonly name: "chainId";
|
|
113
|
+
readonly type: "uint256";
|
|
114
|
+
}];
|
|
115
|
+
};
|
|
116
|
+
export declare const PERMIT2_WITNESS_TRANSFER_FROM_PRIMARY_TYPE: "PermitWitnessTransferFrom";
|
|
117
|
+
/**
|
|
118
|
+
* The gasless entry point on `TabSettlement`, as a human-readable ABI fragment.
|
|
119
|
+
* `spender` in the signed message is the `TabSettlement` address and `witness`
|
|
120
|
+
* is `TabSettlement.witnessHash(serviceId, asset, amount)`.
|
|
121
|
+
*/
|
|
122
|
+
export declare const TAB_SETTLEMENT_PERMIT2_ABI: readonly ["function settleWithPermit2(address agent, bytes32 serviceId, address asset, uint128 amount, uint256 nonce, uint256 deadline, bytes signature) returns (bytes32 settlementId, uint128 applied, uint128 toPrepaid)", "function witnessHash(bytes32 serviceId, address asset, uint128 amount) view returns (bytes32)", "function WITNESS_TYPE_STRING() view returns (string)", "function WITNESS_TYPEHASH() view returns (bytes32)", "function PERMIT2() view returns (address)", "event SettledGasless(bytes32 indexed settlementId, address indexed relayer)"];
|
|
123
|
+
/** The slice of Permit2 a signer or relayer touches, as human-readable ABI. */
|
|
124
|
+
export declare const PERMIT2_ABI: readonly ["function DOMAIN_SEPARATOR() view returns (bytes32)", "function nonceBitmap(address owner, uint256 wordPosition) view returns (uint256)", "function invalidateUnorderedNonces(uint256 wordPos, uint256 mask)", "event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask)"];
|
|
125
|
+
/**
|
|
126
|
+
* The Identity Registry: an ERC-721 whose token id is the agentId, whose
|
|
127
|
+
* `tokenURI` is the agent's registration file, and whose `agentWallet`
|
|
128
|
+
* metadata is the account acting for the agent. `register` mints to the
|
|
129
|
+
* caller and records it as the wallet; ids are sequential from zero.
|
|
130
|
+
*/
|
|
131
|
+
export declare const ERC8004_IDENTITY_REGISTRY_ABI: readonly ["function register() returns (uint256 agentId)", "function register(string agentURI) returns (uint256 agentId)", "function register(string agentURI, (string metadataKey, bytes metadataValue)[] metadata) returns (uint256 agentId)", "function setAgentURI(uint256 agentId, string newURI)", "function tokenURI(uint256 tokenId) view returns (string)", "function ownerOf(uint256 tokenId) view returns (address)", "function balanceOf(address owner) view returns (uint256)", "function getAgentWallet(uint256 agentId) view returns (address)", "function getMetadata(uint256 agentId, string metadataKey) view returns (bytes)", "function setMetadata(uint256 agentId, string metadataKey, bytes metadataValue)", "function isAuthorizedOrOwner(address spender, uint256 agentId) view returns (bool)", "function getVersion() pure returns (string)", "event Registered(uint256 indexed agentId, string agentURI, address indexed owner)", "event URIUpdated(uint256 indexed agentId, string newURI, address indexed updatedBy)", "event MetadataSet(uint256 indexed agentId, string indexed indexedMetadataKey, string metadataKey, bytes metadataValue)", "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"];
|
|
132
|
+
/**
|
|
133
|
+
* The Reputation Registry: feedback about an agent, keyed by agentId and the
|
|
134
|
+
* client that gave it, 1-indexed per client. An agent's owner or operator
|
|
135
|
+
* cannot give feedback about it.
|
|
136
|
+
*/
|
|
137
|
+
export declare const ERC8004_REPUTATION_REGISTRY_ABI: readonly ["function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash)", "function revokeFeedback(uint256 agentId, uint64 feedbackIndex)", "function appendResponse(uint256 agentId, address clientAddress, uint64 feedbackIndex, string responseURI, bytes32 responseHash)", "function getSummary(uint256 agentId, address[] clientAddresses, string tag1, string tag2) view returns (uint64 count, int128 summaryValue, uint8 summaryValueDecimals)", "function readFeedback(uint256 agentId, address clientAddress, uint64 feedbackIndex) view returns (int128 value, uint8 valueDecimals, string tag1, string tag2, bool isRevoked)", "function readAllFeedback(uint256 agentId, address[] clientAddresses, string tag1, string tag2, bool includeRevoked) view returns (address[] clients, uint64[] feedbackIndexes, int128[] values, uint8[] valueDecimals, string[] tag1s, string[] tag2s, bool[] revokedStatuses)", "function getLastIndex(uint256 agentId, address clientAddress) view returns (uint64)", "function getClients(uint256 agentId) view returns (address[])", "function getIdentityRegistry() view returns (address)", "function getVersion() pure returns (string)", "event NewFeedback(uint256 indexed agentId, address indexed clientAddress, uint64 feedbackIndex, int128 value, uint8 valueDecimals, string indexed indexedTag1, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash)", "event FeedbackRevoked(uint256 indexed agentId, address indexed clientAddress, uint64 indexed feedbackIndex)", "event ResponseAppended(uint256 indexed agentId, address indexed clientAddress, uint64 feedbackIndex, address indexed responder, string responseURI, bytes32 responseHash)"];
|
|
138
|
+
/** Canonical ERC-8004 event signatures, for topic filters. */
|
|
139
|
+
export declare const ERC8004_EVENT_SIGNATURES: {
|
|
140
|
+
readonly Registered: "Registered(uint256,string,address)";
|
|
141
|
+
readonly URIUpdated: "URIUpdated(uint256,string,address)";
|
|
142
|
+
readonly MetadataSet: "MetadataSet(uint256,string,string,bytes)";
|
|
143
|
+
readonly NewFeedback: "NewFeedback(uint256,address,uint64,int128,uint8,string,string,string,string,string,bytes32)";
|
|
144
|
+
readonly FeedbackRevoked: "FeedbackRevoked(uint256,address,uint64)";
|
|
145
|
+
readonly ResponseAppended: "ResponseAppended(uint256,address,uint64,address,string,bytes32)";
|
|
146
|
+
};
|
|
147
|
+
export type Erc8004EventName = keyof typeof ERC8004_EVENT_SIGNATURES;
|
|
148
|
+
/** `topics[0]` for each ERC-8004 event, derived from its canonical signature. */
|
|
149
|
+
export declare const ERC8004_EVENT_TOPIC0: Readonly<Record<Erc8004EventName, Bytes32>>;
|
|
150
|
+
//# sourceMappingURL=abi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abi.d.ts","sourceRoot":"","sources":["../src/abi.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,gBAAgB;IAC3B,uGAAuG;;IAEvG,sGAAsG;;IAEtG,wFAAwF;;IAGxF,mFAAmF;;IAEnF,2EAA2E;;IAE3E,mGAAmG;;IAEnG;;;OAGG;;IAEH,mDAAmD;;IAEnD,mDAAmD;;IAEnD,kFAAkF;;CAE1E,CAAC;AAEX,yDAAyD;AACzD,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAE/B,CAAC;AAEhC,sCAAsC;AACtC,eAAO,MAAM,WAAW,GAAI,MAAM,SAAS,KAAG,OAA6B,CAAC;AAY5E;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EACtC,+FAAwG,CAAC;AAE3G,oGAAoG;AACpG,eAAO,MAAM,+BAA+B,EAAE,OAAqD,CAAC;AAEpG;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,qKACuE,CAAC;AAEhH,mEAAmE;AACnE,eAAO,MAAM,kCAAkC,EAC7C,sGAA+G,CAAC;AAElH,8DAA8D;AAC9D,eAAO,MAAM,kCAAkC,yQACiC,CAAC;AACjF,eAAO,MAAM,sCAAsC,EAAE,OAEpD,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,mBAAmB,EAAG,SAAkB,CAAC;AAEtD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE;;;;EAM7E;AAED;;;;GAIG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmBtC,CAAC;AAEX,eAAO,MAAM,0CAA0C,EAAG,2BAAoC,CAAC;AAE/F;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,0iBAO7B,CAAC;AAEX,+EAA+E;AAC/E,eAAO,MAAM,WAAW,iTAKd,CAAC;AAWX;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,qsCAiBhC,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,mvDAclC,CAAC;AAEX,8DAA8D;AAC9D,eAAO,MAAM,wBAAwB;;;;;;;CAO3B,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,wBAAwB,CAAC;AAErE,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAEvC,CAAC"}
|