leash-monad 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.cjs +8 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.mjs +8 -1
- package/dist/networks.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ import { checkAgent } from "leash-monad";
|
|
|
16
16
|
const v = await checkAgent(agentAddress, myAddress, "2.00"); // Monad mainnet by default
|
|
17
17
|
if (!v.ok) return res.status(403).json(v);
|
|
18
18
|
// v = { status: "OK", ok: true, remainingToday: "3.0", expiry: 1791887540,
|
|
19
|
-
// erc8004Id: "
|
|
19
|
+
// erc8004Id: "10299", account: "0xB1C6…", reason: "This agent is leashed and this payment fits its budget." }
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
| `status` | Meaning |
|
|
@@ -65,7 +65,7 @@ nothing leaves the account.
|
|
|
65
65
|
|
|
66
66
|
| | Chain | LeashHub |
|
|
67
67
|
|---|---|---|
|
|
68
|
-
| `mainnet` (default) | Monad, 143 | `
|
|
68
|
+
| `mainnet` (default) | Monad, 143 | `0x64a489074dd6a4b3b977e5f635a178366a8c12c3` |
|
|
69
69
|
| `testnet` | Monad Testnet, 10143 | `0x8b427106c04e66dfc6e8d58fa4de0478a54f510a` |
|
|
70
70
|
|
|
71
71
|
Pass `{ network: "testnet" }` as the last argument to any call.
|
package/dist/index.cjs
CHANGED
|
@@ -41,7 +41,7 @@ var networks = {
|
|
|
41
41
|
chainId: 143,
|
|
42
42
|
rpc: "https://rpc.monad.xyz",
|
|
43
43
|
explorer: "https://monadvision.com",
|
|
44
|
-
hub: "
|
|
44
|
+
hub: "0x64a489074dd6a4b3b977e5f635a178366a8c12c3",
|
|
45
45
|
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
46
46
|
testUsd: "0x4adf40e6e5113339635e6dc54ff638e7b63bbea3"
|
|
47
47
|
},
|
|
@@ -124,6 +124,10 @@ async function leashGate(req, cfg) {
|
|
|
124
124
|
const client = clientFor(cfg);
|
|
125
125
|
const rc = await client.getTransactionReceipt({ hash: payment }).catch(() => null);
|
|
126
126
|
if (!rc || rc.status !== "success") return { allow: false, status: 402, body: { error: "payment_not_found", ref } };
|
|
127
|
+
const mined = await client.getBlock({ blockNumber: rc.blockNumber });
|
|
128
|
+
if (Date.now() / 1e3 - Number(mined.timestamp) > (cfg.maxPaymentAgeSeconds ?? 300)) {
|
|
129
|
+
return { allow: false, status: 402, body: { error: "payment_expired", ref, reason: "That payment is too old to use again. Pay for this request." } };
|
|
130
|
+
}
|
|
127
131
|
const d = cfg.decimals ?? 6, need = (0, import_viem2.parseUnits)(cfg.priceUsd, d);
|
|
128
132
|
for (const log of rc.logs) {
|
|
129
133
|
try {
|
|
@@ -132,6 +136,9 @@ async function leashGate(req, cfg) {
|
|
|
132
136
|
const a = ev.args;
|
|
133
137
|
const account = await client.readContract({ address: net(cfg).hub, abi: hubAbi, functionName: "accountOf", args: [agent] });
|
|
134
138
|
if (log.address.toLowerCase() === account.toLowerCase() && a.agent.toLowerCase() === agent.toLowerCase() && a.seller.toLowerCase() === cfg.seller.toLowerCase() && a.amount >= need && a.ref === ref) {
|
|
139
|
+
if (cfg.claim && !await cfg.claim(payment)) {
|
|
140
|
+
return { allow: false, status: 402, body: { error: "payment_used", ref, reason: "That payment was already used. Pay for this request." } };
|
|
141
|
+
}
|
|
135
142
|
const verdict = await checkAgent(agent, cfg.seller, "0", cfg);
|
|
136
143
|
return { allow: true, agent, paid: (0, import_viem2.formatUnits)(a.amount, d), tx: payment, verdict };
|
|
137
144
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -60,11 +60,17 @@ export type GateResult = {
|
|
|
60
60
|
* agent pays through its Leash (one tx), then retries with x-leash-payment: <txHash>
|
|
61
61
|
* 2nd request: the gate checks the receipt's Paid event (agent, seller, amount >= price, ref) -> allow
|
|
62
62
|
*/
|
|
63
|
-
export
|
|
63
|
+
export type GateConfig = {
|
|
64
64
|
seller: Address;
|
|
65
65
|
priceUsd: string;
|
|
66
66
|
resource?: string;
|
|
67
|
-
|
|
67
|
+
/** Refuse payments mined longer ago than this (default 300 s). Limits how long one payment proof stays usable. */
|
|
68
|
+
maxPaymentAgeSeconds?: number;
|
|
69
|
+
/** Record a payment as used; return false if it was already used. Plug in your store (Redis, a DB row) so one
|
|
70
|
+
* payment buys exactly one response. Without it, a payment can be replayed until it is maxPaymentAgeSeconds old. */
|
|
71
|
+
claim?: (tx: Hex) => boolean | Promise<boolean>;
|
|
72
|
+
} & Options;
|
|
73
|
+
export declare function leashGate(req: GateRequest, cfg: GateConfig): Promise<GateResult>;
|
|
68
74
|
/** Pay a seller from inside the leash. Reverts on-chain (and throws here) if it would break the leash. */
|
|
69
75
|
export declare function payWithLeash(agentAccount: Account, seller: Address, amountUsd: string, ref: Hex, o?: Options & {
|
|
70
76
|
gas?: bigint;
|
package/dist/index.mjs
CHANGED
|
@@ -18,7 +18,7 @@ var networks = {
|
|
|
18
18
|
chainId: 143,
|
|
19
19
|
rpc: "https://rpc.monad.xyz",
|
|
20
20
|
explorer: "https://monadvision.com",
|
|
21
|
-
hub: "
|
|
21
|
+
hub: "0x64a489074dd6a4b3b977e5f635a178366a8c12c3",
|
|
22
22
|
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
23
23
|
testUsd: "0x4adf40e6e5113339635e6dc54ff638e7b63bbea3"
|
|
24
24
|
},
|
|
@@ -101,6 +101,10 @@ async function leashGate(req, cfg) {
|
|
|
101
101
|
const client = clientFor(cfg);
|
|
102
102
|
const rc = await client.getTransactionReceipt({ hash: payment }).catch(() => null);
|
|
103
103
|
if (!rc || rc.status !== "success") return { allow: false, status: 402, body: { error: "payment_not_found", ref } };
|
|
104
|
+
const mined = await client.getBlock({ blockNumber: rc.blockNumber });
|
|
105
|
+
if (Date.now() / 1e3 - Number(mined.timestamp) > (cfg.maxPaymentAgeSeconds ?? 300)) {
|
|
106
|
+
return { allow: false, status: 402, body: { error: "payment_expired", ref, reason: "That payment is too old to use again. Pay for this request." } };
|
|
107
|
+
}
|
|
104
108
|
const d = cfg.decimals ?? 6, need = parseUnits(cfg.priceUsd, d);
|
|
105
109
|
for (const log of rc.logs) {
|
|
106
110
|
try {
|
|
@@ -109,6 +113,9 @@ async function leashGate(req, cfg) {
|
|
|
109
113
|
const a = ev.args;
|
|
110
114
|
const account = await client.readContract({ address: net(cfg).hub, abi: hubAbi, functionName: "accountOf", args: [agent] });
|
|
111
115
|
if (log.address.toLowerCase() === account.toLowerCase() && a.agent.toLowerCase() === agent.toLowerCase() && a.seller.toLowerCase() === cfg.seller.toLowerCase() && a.amount >= need && a.ref === ref) {
|
|
116
|
+
if (cfg.claim && !await cfg.claim(payment)) {
|
|
117
|
+
return { allow: false, status: 402, body: { error: "payment_used", ref, reason: "That payment was already used. Pay for this request." } };
|
|
118
|
+
}
|
|
112
119
|
const verdict = await checkAgent(agent, cfg.seller, "0", cfg);
|
|
113
120
|
return { allow: true, agent, paid: formatUnits(a.amount, d), tx: payment, verdict };
|
|
114
121
|
}
|
package/dist/networks.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare const networks: {
|
|
|
15
15
|
chainId: number;
|
|
16
16
|
rpc: string;
|
|
17
17
|
explorer: string;
|
|
18
|
-
hub: "
|
|
18
|
+
hub: "0x64a489074dd6a4b3b977e5f635a178366a8c12c3";
|
|
19
19
|
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432";
|
|
20
20
|
testUsd: "0x4adf40e6e5113339635e6dc54ff638e7b63bbea3";
|
|
21
21
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leash-monad",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Spend limits for AI agents on Monad. One call tells a seller whose agent it is, what it may spend today, and whether a payment will go through.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Robert Moore",
|