@escro/plugin-eliza 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 +160 -2
- package/characters/escro-buyer.character.json +37 -0
- package/characters/escro-commissioner.character.json +36 -0
- package/dist/index.cjs +3178 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +478 -0
- package/dist/index.d.ts +478 -0
- package/dist/index.js +3150 -0
- package/dist/index.js.map +1 -0
- package/package.json +104 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 escro.ai
|
|
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,161 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @escro/plugin-eliza
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Escrow for AI agents, as an [elizaOS](https://elizaos.ai) plugin. Adds three
|
|
4
|
+
buyer-side actions, `COMMISSION_TASK`, `PAY_402` and `REVIEW_DELIVERY`, so an agent can
|
|
5
|
+
commission asynchronous bot-to-bot work or fund a worker's 402, and settle the delivery,
|
|
6
|
+
with funds held in an Escro conditional-release USDC escrow on Solana. Funds
|
|
7
|
+
release when the buyer approves the delivered work, or to the worker 24 hours after
|
|
8
|
+
a submission the buyer leaves unreviewed; they default to refund if the work never
|
|
9
|
+
arrives.
|
|
10
|
+
|
|
11
|
+
Escro never judges quality. The agent (the Buyer) reviews and releases; the
|
|
12
|
+
on-chain program only enforces the state machine. This plugin is a thin wrapper
|
|
13
|
+
over [`@escro/sdk`](https://www.npmjs.com/package/@escro/sdk) and adds no
|
|
14
|
+
deliverable evaluation of its own.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @escro/plugin-eliza @escro/sdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`@elizaos/core` (v1.7.x) is provided by your elizaOS runtime at load time. This
|
|
23
|
+
plugin imports no runtime values from it and vendors the small type surface it needs,
|
|
24
|
+
so it does not install `@elizaos/core` itself.
|
|
25
|
+
|
|
26
|
+
## Configure
|
|
27
|
+
|
|
28
|
+
The plugin reads these settings from the runtime (character `settings`/`secrets`
|
|
29
|
+
or environment):
|
|
30
|
+
|
|
31
|
+
| Setting | Required | Default | Notes |
|
|
32
|
+
| ----------------------------------- | -------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
33
|
+
| `ESCRO_WALLET_SECRET` | yes | | Base58-encoded ed25519 secret key for the agent's Solana wallet. Provide via secrets/env. Never logged. |
|
|
34
|
+
| `ESCRO_CLUSTER` | no | `devnet` | `devnet` or `mainnet`. A client injected through `makePay402Action` with this unset takes mainnet's host rule for `PAY_402` and pays only mainnet entries; set `devnet` for devnet's. `PAY_402` pays only entries on this cluster's network. |
|
|
35
|
+
| `ESCRO_RPC_URL` | no | public cluster RPC | Solana RPC endpoint. |
|
|
36
|
+
| `ESCRO_API_URL` | no | the cluster's API (`https://api-devnet.escro.ai` or `https://api.escro.ai`) | Escro REST API base URL. |
|
|
37
|
+
| `ESCRO_CHAT_INPUT_CONSENT` | no | unset | Lets a fenced JSON block in chat spend the wallet. Set only to the exact sentence under [Chat input](#chat-input). |
|
|
38
|
+
| `ESCRO_PAY_402_ALLOW_PRIVATE_HOSTS` | no | unset | `1` lets `PAY_402` pay a loopback, link-local or private host, such as a worker on this machine or network. Unset or empty, `PAY_402` refuses such a host before any request; any other value fails the action. The rule follows `ESCRO_CLUSTER`, and a client injected through `makePay402Action` with `ESCRO_CLUSTER` unset takes mainnet's rule: on mainnet `PAY_402` refuses an `http:` URL either way, except to a host this setting admits. The same name and rule as `@escro/mcp`'s environment variable. An operator setting: no input sets it. |
|
|
39
|
+
| `ESCRO_SPEND_CAP_USDC` | on mainnet, to commission or pay a 402 | | The most USDC the agent's wallet may hold in open escrows, each counted as amount plus fee (for example `50` or `12.5`). A commission that would pass it is refused before its create is sent; on mainnet every commission is refused while it is unset. An operator setting: a commission carrying a cap is refused. See [Spend cap](#spend-cap). |
|
|
40
|
+
|
|
41
|
+
`ESCRO_WALLET_SECRET` is a live signing key. Keep it in your runtime secrets, not
|
|
42
|
+
in a committed character file. The example characters in `characters/` deliberately
|
|
43
|
+
inline no secret.
|
|
44
|
+
|
|
45
|
+
### Spend cap
|
|
46
|
+
|
|
47
|
+
`ESCRO_SPEND_CAP_USDC` is the `@escro/sdk` client's `spendCap`. Before each create the
|
|
48
|
+
client reads the wallet's open deposits from the Escro API (FUNDED, IN_PROGRESS,
|
|
49
|
+
SUBMITTED, DISPUTED) and adds the creates still in flight in this process, so
|
|
50
|
+
concurrent commissions on one agent, or on several agents sharing the wallet in one
|
|
51
|
+
process, are checked one at a time against one total.
|
|
52
|
+
|
|
53
|
+
The cap holds per process. Two processes or hosts using one wallet each enforce it
|
|
54
|
+
and together can pass it by the other's in-flight deposits: run one buyer process
|
|
55
|
+
per wallet, or give each its share of the cap. A commission that fails after its
|
|
56
|
+
create was sent (a network error, a confirmation timeout, an unrecorded confirm)
|
|
57
|
+
keeps its deposit in flight until the process restarts, and shrinks the cap's room
|
|
58
|
+
until then: the plugin never re-confirms a create.
|
|
59
|
+
|
|
60
|
+
## Use
|
|
61
|
+
|
|
62
|
+
Add the plugin to a character:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"name": "MyBuyer",
|
|
67
|
+
"plugins": ["@elizaos/plugin-bootstrap", "@escro/plugin-eliza"],
|
|
68
|
+
"settings": { "ESCRO_CLUSTER": "devnet" }
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The plugin has three buyer-side actions. Each takes structured input from the action
|
|
73
|
+
`options`, from `message.content`, or from the first fenced `json` block of the message
|
|
74
|
+
text (see [Chat input](#chat-input)).
|
|
75
|
+
|
|
76
|
+
### `COMMISSION_TASK` (input key `commission`)
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
{
|
|
80
|
+
worker: "So1111...11112", // assigned worker, base58 pubkey
|
|
81
|
+
amountUsdc: 5_000_000, // micro-USDC (1 USDC = 1_000_000); >= the $5.00 minimum
|
|
82
|
+
deadlineSeconds: 3600, // or deadlineUnix for an absolute deadline
|
|
83
|
+
wait: false, // optional: return once the create is sent, unconfirmed
|
|
84
|
+
task: {
|
|
85
|
+
description: "Summarize the attached document into five bullet points.",
|
|
86
|
+
taskType: "summarization",
|
|
87
|
+
acceptanceCriteria: [{ id: "ac-1", description: "Exactly five bullets", required: true }]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
It maps 1:1 onto the SDK's `createEscrow` and returns the escrow PDA, task id and
|
|
93
|
+
signature. With `wait: false` it reports `confirmed: false`: read the escrow until it is
|
|
94
|
+
FUNDED before counting on it. A failure that may have landed names the escrow and says
|
|
95
|
+
not to retry, because a retry funds a second escrow.
|
|
96
|
+
|
|
97
|
+
### `PAY_402` (input key `payment`)
|
|
98
|
+
|
|
99
|
+
`{ url | paymentRequired, to, amountMicroUsdc, deadlineSeconds, method?, contentType?, body? }`
|
|
100
|
+
funds a worker's 402 on the escrow rail only (`on-delivery` or `job-escrow`, never `exact` or
|
|
101
|
+
`upto`), for exactly that payee and amount and a deadline within `deadlineSeconds`, at most
|
|
102
|
+
604800 (7 days). A mainnet `PAY_402` needs only `ESCRO_SPEND_CAP_USDC`.
|
|
103
|
+
|
|
104
|
+
Before any request or funding, `PAY_402` refuses a URL whose host is a loopback, link-local or
|
|
105
|
+
private address, or a name that resolves to one when checked, unless
|
|
106
|
+
`ESCRO_PAY_402_ALLOW_PRIVATE_HOSTS` is `1`; on mainnet it pays only `https:` URLs. With
|
|
107
|
+
`paymentRequired` the URL checked is the 402's `resource.url`, the one the paid request goes to.
|
|
108
|
+
The request connects only to addresses that pass the same rule, from one resolution of the name,
|
|
109
|
+
so a name its owner re-points after the check (DNS rebinding) is refused; an escrow entry's job
|
|
110
|
+
specification host is held to that rule before anything is funded. The rule needs direct egress and
|
|
111
|
+
local DNS: the request resolves each host with this machine's resolver and connects directly to the
|
|
112
|
+
admitted addresses, ignoring an HTTP or HTTPS proxy set in the environment, so with a `url` on a
|
|
113
|
+
network reachable only through a proxy `PAY_402` fails before anything is funded or signed.
|
|
114
|
+
|
|
115
|
+
### `REVIEW_DELIVERY` (input key `reviewDelivery`)
|
|
116
|
+
|
|
117
|
+
`{ escrow }` settles a SUBMITTED escrow with a predicate the operator chose. The hook is
|
|
118
|
+
registered in code, never taken from a message:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { createEscroPlugin } from "@escro/plugin-eliza";
|
|
122
|
+
|
|
123
|
+
export default createEscroPlugin({
|
|
124
|
+
review: async (escrow) => ({ check, delivery, onFail: "hold" }), // or null to decide nothing
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
A `pass` releases with the predicate's memo. A `fail` holds, or raises a dispute with
|
|
129
|
+
`onFail: "dispute"`. The check and the delivered bytes are the operator's own: a message can
|
|
130
|
+
name only the escrow.
|
|
131
|
+
|
|
132
|
+
A character loaded by name uses the default plugin, which has no hook: it can commission once
|
|
133
|
+
admitted, and it can never release.
|
|
134
|
+
|
|
135
|
+
**The 24h hold.** Nothing in the plugin schedules a review. The operator's code, or the
|
|
136
|
+
operator's own message, must run `REVIEW_DELIVERY` within 24h of a submit. If nobody does, the
|
|
137
|
+
oracle's `timeout_release` pays the worker in full.
|
|
138
|
+
|
|
139
|
+
### Chat input
|
|
140
|
+
|
|
141
|
+
Text in a chat message spends nothing by default: `COMMISSION_TASK` and `PAY_402` refuse input
|
|
142
|
+
read from a fenced block, before any client is built. An operator opens it one of two ways:
|
|
143
|
+
|
|
144
|
+
- Register `createEscroPlugin({ authorizeChatInput })`. It receives the `Memory` (a hook can read
|
|
145
|
+
`entityId`) and alone decides; only `true` admits.
|
|
146
|
+
- With no such option, set `ESCRO_CHAT_INPUT_CONSENT` in runtime secrets or env to exactly:
|
|
147
|
+
|
|
148
|
+
`anyone who can message this agent can spend its wallet`
|
|
149
|
+
|
|
150
|
+
With either open, whoever they admit can spend the wallet and point `PAY_402` at any public
|
|
151
|
+
http(s) URL (any URL at all when `ESCRO_PAY_402_ALLOW_PRIVATE_HOSTS` is `1`). The spend cap bounds open escrows only, so each settled escrow frees room for the next.
|
|
152
|
+
`admitAcceptance` for a 402 carrying an acceptance predicate comes only from
|
|
153
|
+
`createEscroPlugin` too.
|
|
154
|
+
|
|
155
|
+
Example characters: [`characters/`](./characters). End-to-end example:
|
|
156
|
+
[`examples/localnet-commission.ts`](./examples/localnet-commission.ts) (runs against the
|
|
157
|
+
hosted devnet API with a funded devnet wallet).
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
MIT.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "EscroBuyer",
|
|
3
|
+
"username": "escro-buyer",
|
|
4
|
+
"system": "You are a buyer agent that commissions asynchronous work from other bots. When a task should be delegated, use the COMMISSION_TASK action to lock USDC in an Escro conditional-release escrow against a specific worker. You are the judge of the delivered work: funds release when you approve it, and default to refund if the work never arrives. A submission you leave unreviewed pays the worker automatically 24 hours after it is submitted, so review it, or dispute it, within that window. Never promise to evaluate quality on-chain; Escro only enforces the state machine.",
|
|
5
|
+
"bio": [
|
|
6
|
+
"Delegates asynchronous jobs to worker bots and pays them through Escro.",
|
|
7
|
+
"Locks funds up front, reviews every submission within 24 hours, and releases only the work that passes its own review.",
|
|
8
|
+
"Treats every escrow's deadline as a hard commitment and never overcommits."
|
|
9
|
+
],
|
|
10
|
+
"plugins": ["@elizaos/plugin-bootstrap", "@escro/plugin-eliza"],
|
|
11
|
+
"settings": {
|
|
12
|
+
"ESCRO_CLUSTER": "devnet"
|
|
13
|
+
},
|
|
14
|
+
"topics": ["escrow", "delegation", "async work", "solana", "usdc"],
|
|
15
|
+
"adjectives": ["diligent", "precise", "trustworthy"],
|
|
16
|
+
"messageExamples": [
|
|
17
|
+
[
|
|
18
|
+
{
|
|
19
|
+
"name": "operator",
|
|
20
|
+
"content": {
|
|
21
|
+
"text": "Hire this worker to summarize the report.\n\n```json\n{\n \"worker\": \"So11111111111111111111111111111111111111112\",\n \"amountUsdc\": 5000000,\n \"deadlineSeconds\": 3600,\n \"task\": {\n \"description\": \"Summarize the attached report into five bullet points.\",\n \"taskType\": \"summarization\",\n \"acceptanceCriteria\": [\n {\n \"id\": \"ac-1\",\n \"description\": \"Exactly five bullets\",\n \"required\": true\n }\n ]\n }\n}\n```"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "EscroBuyer",
|
|
26
|
+
"content": {
|
|
27
|
+
"text": "Locking 5 USDC in escrow for that worker now. I will review the summary within 24 hours of its submission and release payment only if it passes.",
|
|
28
|
+
"actions": ["COMMISSION_TASK"]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
],
|
|
33
|
+
"style": {
|
|
34
|
+
"all": ["concise", "businesslike"],
|
|
35
|
+
"chat": ["confirm the worker, amount, and deadline before commissioning"]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "EscroCommissioner",
|
|
3
|
+
"username": "escro-commissioner",
|
|
4
|
+
"system": "You are an autonomous commissioner that breaks goals into discrete jobs and hires worker bots to execute them. Use the COMMISSION_TASK action to open an Escro escrow for each job against its assigned worker, always with clear acceptance criteria and a realistic deadline. You remain the sole judge of delivered work; Escro enforces only the conditional release and defaults to refund.",
|
|
5
|
+
"bio": [
|
|
6
|
+
"Turns high-level goals into commissioned jobs with explicit acceptance criteria.",
|
|
7
|
+
"Pays exclusively through Escro so no worker is paid before the work is delivered and approved.",
|
|
8
|
+
"Runs on Solana devnet by default and keeps every job's funds in a dedicated escrow."
|
|
9
|
+
],
|
|
10
|
+
"plugins": ["@elizaos/plugin-bootstrap", "@escro/plugin-eliza"],
|
|
11
|
+
"settings": {
|
|
12
|
+
"ESCRO_CLUSTER": "devnet"
|
|
13
|
+
},
|
|
14
|
+
"topics": ["commissioning", "escrow", "acceptance criteria", "solana", "bot economy"],
|
|
15
|
+
"adjectives": ["organized", "fair", "deliberate"],
|
|
16
|
+
"messageExamples": [
|
|
17
|
+
[
|
|
18
|
+
{
|
|
19
|
+
"name": "operator",
|
|
20
|
+
"content": {
|
|
21
|
+
"text": "Commission this code-generation job.\n\n```json\n{\n \"worker\": \"So11111111111111111111111111111111111111112\",\n \"amountUsdc\": 5000000,\n \"deadlineSeconds\": 3600,\n \"wait\": false,\n \"task\": {\n \"description\": \"Generate the module described in the attached brief.\",\n \"taskType\": \"code_generation\",\n \"acceptanceCriteria\": [\n {\n \"id\": \"ac-1\",\n \"description\": \"All tests pass\",\n \"required\": true\n }\n ]\n }\n}\n```"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "EscroCommissioner",
|
|
26
|
+
"content": {
|
|
27
|
+
"text": "Sent the escrow for that job, with the acceptance criterion 'all tests pass' and a one-hour deadline. It is not yet confirmed.",
|
|
28
|
+
"actions": ["COMMISSION_TASK"]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
],
|
|
33
|
+
"style": {
|
|
34
|
+
"all": ["structured", "explicit about acceptance criteria"]
|
|
35
|
+
}
|
|
36
|
+
}
|