nightpay 0.1.0 → 0.4.4
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 +666 -21
- package/README.md +371 -125
- package/bin/cli.js +527 -24
- package/nightpay_sdk.py +398 -0
- package/openclaw.plugin.json +10 -0
- package/package.json +18 -7
- package/plugin.js +712 -0
- package/skills/nightpay/AGENTS.md +302 -0
- package/skills/nightpay/HEARTBEAT.md +55 -0
- package/skills/nightpay/SKILL.md +420 -61
- package/skills/nightpay/contracts/receipt.compact +358 -97
- package/skills/nightpay/contracts/receipt.stub.compact +55 -0
- package/skills/nightpay/ontology/context.jsonld +179 -0
- package/skills/nightpay/ontology/examples/job-delegation.example.jsonld +50 -0
- package/skills/nightpay/ontology/examples/pool-funded.example.jsonld +31 -0
- package/skills/nightpay/ontology/examples/receipt-credential.example.jsonld +33 -0
- package/skills/nightpay/ontology/ontology.jsonld +396 -0
- package/skills/nightpay/ontology/ontology.md +243 -0
- package/skills/nightpay/openclaw-fragment.json +16 -33
- package/skills/nightpay/rules/content-safety.md +15 -99
- package/skills/nightpay/rules/escrow-safety.md +62 -0
- package/skills/nightpay/rules/privacy-first.md +21 -0
- package/skills/nightpay/scripts/gateway.sh +1007 -133
- package/skills/nightpay/scripts/mip003-server.sh +4739 -93
package/skills/nightpay/SKILL.md
CHANGED
|
@@ -1,112 +1,471 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: nightpay
|
|
3
|
-
description: Anonymous community bounty
|
|
4
|
-
license:
|
|
5
|
-
compatibility:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
- cursor
|
|
9
|
-
- copilot
|
|
10
|
-
metadata:
|
|
11
|
-
category: payments
|
|
12
|
-
blockchain: midnight, cardano
|
|
13
|
-
agent-layer: masumi
|
|
14
|
-
version: 0.1.0
|
|
3
|
+
description: Primarily for OpenClaw agents. Anonymous community bounty pools — create a pool, crowdfund via Midnight ZK proofs, hire agents via Masumi, settle on Cardano. Use deployed NIGHTPAY_API_URL and BRIDGE_URL (no localhost). Trigger with /nightpay <instruction> to create or fund a bounty pool.
|
|
4
|
+
license: AGPL-3.0-only
|
|
5
|
+
compatibility: "openclaw, acp, claude-code, cursor, copilot"
|
|
6
|
+
allowed-tools: Bash
|
|
7
|
+
metadata: {"openclaw":{"requires":{"bins":["bash","curl","openssl","sqlite3","sha256sum"],"env":["MASUMI_API_KEY","OPERATOR_ADDRESS","NIGHTPAY_API_URL","BRIDGE_URL"]},"primaryEnv":"MASUMI_API_KEY","os":["darwin","linux"]},"category":"payments","blockchain":"midnight, cardano","agent-layer":"masumi","version":"0.4.0"}
|
|
15
8
|
---
|
|
16
9
|
|
|
17
10
|
# nightpay
|
|
18
11
|
|
|
19
|
-
> Anonymous community
|
|
12
|
+
> Anonymous community bounty pools for AI agents — Midnight ZK proofs + Masumi settlement + Cardano finality.
|
|
20
13
|
|
|
21
|
-
|
|
14
|
+
**This skill is primarily for OpenClaw agents.** The agent talks to a **deployed** NightPay MIP-003 API and bridge via `NIGHTPAY_API_URL` and `BRIDGE_URL` in the skill env. Do not use localhost unless the agent runs on the same machine as the stack.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx nightpay init
|
|
20
|
+
```
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
Installs the full skill into `./skills/nightpay/` (SKILL.md, scripts, ontology, rules, contracts). One command, no git clone needed.
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
4. **A ZK receipt proves completion** — shielded token minted on Midnight, verifiable by anyone, reveals nothing about funders
|
|
29
|
-
5. **The operator earns a fee** — configurable basis points (default 2%) on every successful bounty
|
|
24
|
+
## What This Does
|
|
25
|
+
|
|
26
|
+
This skill turns an OpenClaw agent into a **community bounty pool operator**:
|
|
30
27
|
|
|
31
|
-
|
|
28
|
+
1. **An agent or human creates a bounty pool** — sets a funding goal, fixed contribution amount, and max funders
|
|
29
|
+
2. **Funders back the pool anonymously** — shielded NIGHT via Midnight's Zswap (identity destroyed by nullifier model)
|
|
30
|
+
3. **If the funding goal is met, the pool activates** — an AI agent is hired via Masumi to do the work
|
|
31
|
+
4. **If the goal isn't met by the deadline, funders reclaim their NIGHT** — funder-initiated refund, no fee charged
|
|
32
|
+
5. **A ZK receipt proves completion** — shielded token minted on Midnight, verifiable by anyone, reveals nothing about funders
|
|
33
|
+
6. **The operator collects an infrastructure fee** — configurable basis points (default 2%) on successful pools only
|
|
32
34
|
|
|
33
35
|
## Activation
|
|
34
36
|
|
|
35
37
|
This skill activates when the agent encounters:
|
|
36
38
|
- "bounty", "community bounty", "anonymous bounty", "crowdfund"
|
|
37
|
-
- "nightpay", "bounty board", "
|
|
38
|
-
- "fund this privately", "anonymous tip"
|
|
39
|
-
- Any request to
|
|
39
|
+
- "nightpay", "bounty board", "bounty pool", "create a pool"
|
|
40
|
+
- "fund this privately", "anonymous tip", "fund pool"
|
|
41
|
+
- Any request to create, fund, or manage bounty pools with privacy
|
|
42
|
+
|
|
43
|
+
## OpenClaw Heartbeat
|
|
44
|
+
|
|
45
|
+
NightPay includes `HEARTBEAT.md` for scheduled OpenClaw heartbeat runs.
|
|
46
|
+
|
|
47
|
+
- Heartbeat contract: return `HEARTBEAT_OK` when nothing needs attention.
|
|
48
|
+
- Default focus: API `/availability`, bridge `/health` (when `BRIDGE_URL` is set), work-queue deltas, and daily skill version freshness.
|
|
49
|
+
- Keep heartbeat delivery silent by default or route to last active channel via `openclaw.json`.
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"agents": {
|
|
56
|
+
"defaults": {
|
|
57
|
+
"heartbeat": {
|
|
58
|
+
"every": "2h",
|
|
59
|
+
"target": "last",
|
|
60
|
+
"directPolicy": "allow"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
40
66
|
|
|
41
67
|
## Ledger Compatibility
|
|
42
68
|
|
|
43
69
|
Built against `midnightntwrk/midnight-ledger` spec:
|
|
44
70
|
|
|
45
|
-
| Ledger Concept | How
|
|
71
|
+
| Ledger Concept | How Pools Use It |
|
|
46
72
|
|---|---|
|
|
47
73
|
| **Zswap** (commitment/nullifier) | Funders send shielded NIGHT — identity destroyed by nullifier unlinkability |
|
|
48
|
-
| **ContractState.balance** | Contract pools
|
|
74
|
+
| **ContractState.balance** | Contract pools funds + operator fees |
|
|
49
75
|
| **Effects.shielded_mints** | Mints a receipt token when bounty is completed |
|
|
50
|
-
| **Bounded Merkle trees** (depth 25) |
|
|
51
|
-
| **Nullifier set** | Prevents double-completion
|
|
52
|
-
| **DUST** | Network fees only — never deducted from
|
|
76
|
+
| **Bounded Merkle trees** (depth 25) | Pool tree, funding tree, bounty tree, receipt tree |
|
|
77
|
+
| **Nullifier set** | Prevents double-funding, double-completion, double-refund |
|
|
78
|
+
| **DUST** | Network fees only — never deducted from pool funds |
|
|
53
79
|
|
|
54
|
-
##
|
|
80
|
+
## Pool Parameters
|
|
81
|
+
|
|
82
|
+
| Parameter | Set By | Enforced | Description |
|
|
83
|
+
|---|---|---|---|
|
|
84
|
+
| `fundingGoal` | Pool creator | On-chain | Minimum total NIGHT to activate |
|
|
85
|
+
| `contributionAmount` | Pool creator | On-chain | Fixed per-funder contribution (equal shares) |
|
|
86
|
+
| `maxFunders` | Pool creator | On-chain | Maximum number of backers |
|
|
87
|
+
| Deadline | Gateway | Off-chain | Funding window — expired pools become refundable |
|
|
88
|
+
|
|
89
|
+
## Infrastructure Fee
|
|
55
90
|
|
|
56
91
|
```
|
|
57
|
-
|
|
58
|
-
+-- 2 NIGHT ->
|
|
92
|
+
Pool activates with 100 NIGHT total
|
|
93
|
+
+-- 2 NIGHT -> infrastructure fee (held in contract)
|
|
59
94
|
+-- 98 NIGHT -> released to agent on completion
|
|
60
95
|
|
|
61
|
-
No fee on
|
|
96
|
+
No fee on expired/refunded pools. Fee rate is public on-chain.
|
|
62
97
|
```
|
|
63
98
|
|
|
64
99
|
## Configuration
|
|
65
100
|
|
|
101
|
+
**OpenClaw (primary):** Set the skill env with **deployed** base URLs. Required for the agent to reach the stack:
|
|
102
|
+
|
|
103
|
+
- **`NIGHTPAY_API_URL`** — MIP-003 API base (e.g. `https://api.nightpay.dev`). Heartbeat and all job/bounty API calls use this.
|
|
104
|
+
- **`BRIDGE_URL`** — Bridge base (e.g. `https://bridge.nightpay.dev`) for on-chain flows.
|
|
105
|
+
- **`MASUMI_API_KEY`**, **`OPERATOR_ADDRESS`**, **`RECEIPT_CONTRACT_ADDRESS`** — from the operator.
|
|
106
|
+
- **`GATEWAY_SECRET_KEY`** — Bridge-only (operator machine). A 64-char hex string (32 bytes) that identifies the gateway on-chain. Set this in your secrets manager (OpenShart, Vault, etc.) — **never in plain `.env` files**. If unset the bridge generates an ephemeral key per restart (dev-only; will break the on-chain `gatewayAuthKey` on redeploy).
|
|
107
|
+
|
|
108
|
+
Localhost is **not** valid for OpenClaw unless the agent runs on the same host as the stack (rare).
|
|
109
|
+
|
|
66
110
|
```json
|
|
67
111
|
{
|
|
68
112
|
"nightpay": {
|
|
69
|
-
"midnightNetwork": "
|
|
70
|
-
"masumiPaymentUrl": "
|
|
71
|
-
"masumiRegistryUrl": "
|
|
72
|
-
"receiptContractAddress":
|
|
73
|
-
"operatorAddress": "
|
|
113
|
+
"midnightNetwork": "preprod",
|
|
114
|
+
"masumiPaymentUrl": "https://your-masumi-payment-url/api/v1",
|
|
115
|
+
"masumiRegistryUrl": "https://your-masumi-registry-url/api/v1",
|
|
116
|
+
"receiptContractAddress": "<64-char hex from operator>",
|
|
117
|
+
"operatorAddress": "<64-char hex from operator>",
|
|
74
118
|
"operatorFeeBps": 200,
|
|
75
119
|
"maxBountySpecks": 500000000,
|
|
76
|
-
"escrowTimeoutMinutes": 60
|
|
120
|
+
"escrowTimeoutMinutes": 60,
|
|
121
|
+
"defaultPoolDeadlineHours": 72,
|
|
122
|
+
"minContributionSpecks": 1000
|
|
77
123
|
}
|
|
78
124
|
}
|
|
79
125
|
```
|
|
80
126
|
|
|
127
|
+
*(Use deployed URLs. Localhost only for same-machine/local dev.)*
|
|
128
|
+
|
|
81
129
|
## Flow
|
|
82
130
|
|
|
83
131
|
```
|
|
84
|
-
|
|
85
|
-
| |
|
|
86
|
-
|--
|
|
87
|
-
| (
|
|
88
|
-
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
|
92
|
-
|
|
|
93
|
-
| |
|
|
94
|
-
|
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
| |
|
|
99
|
-
|
|
|
100
|
-
|
|
|
101
|
-
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
132
|
+
Pool Creator NightPay Contract Masumi/Cardano
|
|
133
|
+
| | |
|
|
134
|
+
|-- createPool --------------->| |
|
|
135
|
+
| (goal, amount, maxFunders) | |
|
|
136
|
+
| | |
|
|
137
|
+
Funders (anonymous) | |
|
|
138
|
+
|-- fundPool (× N) ---------->| |
|
|
139
|
+
| (equal contributions) | |
|
|
140
|
+
| | |
|
|
141
|
+
| goal met? ------+ |
|
|
142
|
+
| / \ |
|
|
143
|
+
| yes no (deadline passed) |
|
|
144
|
+
| | \ |
|
|
145
|
+
| activatePool expirePool |
|
|
146
|
+
| | | |
|
|
147
|
+
| | claimRefund (× N) |
|
|
148
|
+
| | (100% returned) |
|
|
149
|
+
| | |
|
|
150
|
+
| |-- find agent --------------------------------->|
|
|
151
|
+
| |-- hire + escrow ------------------------------>|
|
|
152
|
+
| | |
|
|
153
|
+
| |<-- agent delivers work ------------------------|
|
|
154
|
+
| | |
|
|
155
|
+
| |-- completeAndReceipt ------------------------->|
|
|
156
|
+
| | (nullify bounty, mint receipt, |
|
|
157
|
+
| | release funds to agent) |
|
|
158
|
+
| | |
|
|
159
|
+
|<-- ZK receipt (verifiable, reveals nothing) ----------------|
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Agent Command Interface
|
|
163
|
+
|
|
164
|
+
Use `/nightpay <instruction>` to dispatch a bounty pool. The skill will:
|
|
165
|
+
1. Create a pool with appropriate parameters
|
|
166
|
+
2. Wait for funding (or fund from the agent's own balance)
|
|
167
|
+
3. When activated, find and hire an agent via Masumi
|
|
168
|
+
4. Return a job_id and job_token for tracking
|
|
169
|
+
|
|
170
|
+
### Tools available to agents
|
|
171
|
+
|
|
172
|
+
**create_pool** — Create a new bounty pool.
|
|
173
|
+
Required params: `description` (string), `contributionAmountSpecks` (number), `fundingGoalSpecks` (number), `maxFunders` (number)
|
|
174
|
+
Returns: `{ poolCommitment, contributionAmount, fundingGoal, maxFunders }`
|
|
175
|
+
Bridge endpoint: `POST /createPool`
|
|
176
|
+
Annotations: `{ readOnly: false, destructive: false, idempotent: false, openWorld: true }`
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
**fund_pool** — Contribute to an existing pool (exactly contributionAmount NIGHT).
|
|
180
|
+
Required params: `poolCommitment` (64-char hex), `funderNullifier` (64-char hex)
|
|
181
|
+
Returns: `{ fundingRecord, currentFunding, fundersCount, goalMet }`
|
|
182
|
+
Bridge endpoint: `POST /fundPool`
|
|
183
|
+
Annotations: `{ readOnly: false, destructive: false, idempotent: false, openWorld: true }`
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
**claim_refund** — Reclaim contribution from an expired pool.
|
|
187
|
+
Required params: `poolCommitment` (64-char hex), `funderNullifier` (64-char hex)
|
|
188
|
+
Returns: `{ refunded, amountSpecks }`
|
|
189
|
+
Bridge endpoint: `POST /claimRefund`
|
|
190
|
+
Annotations: `{ readOnly: false, destructive: false, idempotent: false, openWorld: true }`
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
**emergency_refund** — Failsafe: reclaim contribution without the gateway. Use only if the gateway is unresponsive and enough contract interactions have passed (500+ txCounter delta). Does not require `expirePool`.
|
|
194
|
+
Required params: `poolCommitment` (64-char hex), `funderNullifier` (64-char hex), `contributionAmountSpecks` (number), `fundedAtTx` (number), `nonce` (64-char hex), `funderAddress` (64-char hex)
|
|
195
|
+
Returns: `{ refunded, amountSpecks, emergencyPath: true }`
|
|
196
|
+
Bridge endpoint: N/A — submitted directly to Midnight contract (no bridge needed)
|
|
197
|
+
Annotations: `{ readOnly: false, destructive: false, idempotent: false, openWorld: true }`
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
**submit_work** — Call this when you have completed the bounty work.
|
|
201
|
+
Required params: `jobId` (string), `workOutput` (string, min 100 chars), `bountyCommitment` (64-char hex), `outputHash` (64-char hex)
|
|
202
|
+
Optional params: `artifactPaths` (list of file paths)
|
|
203
|
+
Returns: `{ receiptHash, txId, payment, feeBps, verifyUrl, stub }`
|
|
204
|
+
Bridge endpoint: `POST /submitWork`
|
|
205
|
+
Annotations: `{ readOnly: false, destructive: false, idempotent: false, openWorld: true }`
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
**get_job_economics** — Check payment breakdown for a job.
|
|
209
|
+
Required params: `jobId` (string)
|
|
210
|
+
Returns: `{ amountSpecks, netToAgent, fee, feeBps, status, survivalStatus }`
|
|
211
|
+
Bridge endpoint: `GET /jobEconomics/<jobId>`
|
|
212
|
+
Annotations: `{ readOnly: true, destructive: false, idempotent: true }`
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
**verify_receipt** — Verify a ZK receipt is valid on-chain.
|
|
216
|
+
Required params: `receiptHash` (64-char hex)
|
|
217
|
+
Returns: `{ valid, stub }`
|
|
218
|
+
Bridge endpoint: `POST /verifyReceipt`
|
|
219
|
+
Annotations: `{ readOnly: true, destructive: false, idempotent: true }`
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
**management_chat** — Ask the CEO assistant for onboarding or navigation help. Use this to trigger RAG-based explanations.
|
|
223
|
+
Required params: `message` (string), `mode` (string: "general", "onboarding", "troubleshooting")
|
|
224
|
+
Returns: `{ reply, actions, intent }`
|
|
225
|
+
MIP-003 endpoint: `POST /management/chat`
|
|
226
|
+
Annotations: `{ readOnly: true, destructive: false, idempotent: true }`
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
**get_ontology** — Fetch the Knowledge Graph (JSON-LD) to understand site structures and status schemas.
|
|
230
|
+
Required params: none
|
|
231
|
+
Returns: JSON-LD ontology document
|
|
232
|
+
MIP-003 endpoint: `GET /ontology`
|
|
233
|
+
See also `ontology/ontology.md` for contest mode, obtaining responses, and voting (GET /submissions, POST /vote_submission).
|
|
234
|
+
Annotations: `{ readOnly: true, destructive: false, idempotent: true }`
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
**get_submissions** — List all submissions for a contest-mode job. Read-only.
|
|
238
|
+
Required params: `jobId` (string)
|
|
239
|
+
Auth: `Authorization: Bearer <job_token>` (bounty creator or operator only)
|
|
240
|
+
Returns: `{ submissions: [{ submission_id, agent_id, payload, approve_votes, reject_votes, score }], voting: { started_at, ends_at, eligible_voters_count, agent_voting_only }, voter_snapshot: [agent_ids] }`
|
|
241
|
+
MIP-003 endpoint: `GET /submissions/<job_id>`
|
|
242
|
+
Annotations: `{ readOnly: true, destructive: false, idempotent: true }`
|
|
243
|
+
|
|
244
|
+
**vote_submission** — Vote approve or reject on a contest submission.
|
|
245
|
+
Required params: `jobId` (string), `submissionId` (string), `voterId` (string), `vote` ("approve" | "reject")
|
|
246
|
+
Optional params: `reason` (string)
|
|
247
|
+
Returns: `{ recorded: true, vote: "approve"|"reject", submission_id, voter_id }`
|
|
248
|
+
MIP-003 endpoint: `POST /vote_submission/<job_id>/<submission_id>`
|
|
249
|
+
Constraints: One vote per (job, submission, voter); later POSTs upsert. Self-voting rejected (403). Must be in voter snapshot when `agent_voting_only` is true.
|
|
250
|
+
Annotations: `{ readOnly: false, destructive: false, idempotent: true }`
|
|
251
|
+
|
|
252
|
+
**select_winner** — Select the winning submission for a contest-mode job after voting.
|
|
253
|
+
Required params: `jobId` (string)
|
|
254
|
+
Auth: `Authorization: Bearer <job_token>` (bounty creator or operator only)
|
|
255
|
+
Returns: `{ winner_submission_id, agent_id, tally: { approve, reject }, quorum_met }`
|
|
256
|
+
MIP-003 endpoint: `POST /select_winner/<job_id>`
|
|
257
|
+
Constraints: Requires `min_votes_to_select` quorum or vote window to have closed. Irreversible.
|
|
258
|
+
Annotations: `{ readOnly: false, destructive: false, idempotent: false }`
|
|
259
|
+
|
|
260
|
+
### Contest mode: obtaining responses and voting
|
|
261
|
+
|
|
262
|
+
When a job is started with `contest.enabled: true`, multiple agents can claim it and each may submit work. The **responses** are the stored submissions (each agent’s delivered work). You must know how to **obtain** them and how to **vote** on them.
|
|
263
|
+
|
|
264
|
+
**Obtaining responses (what to vote on):** Only the **bounty creator** (who has the `job_token` from `POST /start_job`) or the operator may list submissions. Call the MIP-003 API with **`Authorization: Bearer <job_token>`**:
|
|
265
|
+
|
|
266
|
+
- **`GET /submissions/<job_id>`** — Requires `Authorization: Bearer <job_token>`. Returns `submissions`: array of `{ submission_id, agent_id, payload, approve_votes, reject_votes, score, ... }`. The `payload` contains the work (e.g. `work_output`, `artifact_file_paths`). Also returns `voting` (e.g. `started_at`, `ends_at`, `eligible_voters_count`, `agent_voting_only`) and `voter_snapshot`. Use this to see all candidate responses before voting.
|
|
267
|
+
|
|
268
|
+
**Voting:** Only agents in the **voter snapshot** (agents who had claimed the job when the first submission arrived) may vote when `agent_voting_only=true`. Self-voting is rejected.
|
|
269
|
+
|
|
270
|
+
- **`POST /vote_submission/<job_id>/<submission_id>`** — Body: `{ "voter_id": "<your_agent_id>", "vote": "approve" | "reject", "reason": "optional" }`. One vote per (job, submission, voter); later POSTs update. Votes are tallied per submission; the operator (or automation) later calls `POST /select_winner/<job_id>` with the job token to pick the winner.
|
|
271
|
+
|
|
272
|
+
**Flow (contest):** Claim job → (optional) submit your own result via `POST /provide_result/<job_id>` → **GET /submissions/<job_id>** with `Authorization: Bearer <job_token>` (bounty creator only) to obtain all responses → **POST /vote_submission/...** for each submission you want to vote on (approve/reject) → operator runs select_winner when the vote window allows.
|
|
273
|
+
|
|
274
|
+
**Job visibility and attachments (POST /start_job):** When creating a job you can set **`visibility`**: `"public"` or `"private"` (default **private**). Private jobs are hidden from public listings; only the creator or operator can list them and their submissions. Optional **attachment** (`.md` or `.txt`): send `attachment_filename` and `attachment_content` only when the request is **authenticated** (valid `X-Agent-Token` or `Authorization: Bearer <operator_secret>`); otherwise the server returns 403. Max attachment size 256KB.
|
|
275
|
+
|
|
276
|
+
### Economics
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
Fee formula: fee = poolTotal × feeBps / 10000
|
|
280
|
+
Net to agent: netToAgent = poolTotal - fee
|
|
281
|
+
Default fee: 200 bps (2%)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Fee is only charged when a pool activates and the work is completed. Expired pools return 100% to funders.
|
|
285
|
+
|
|
286
|
+
## Trust Model
|
|
287
|
+
|
|
288
|
+
Before participating in a nightpay pool, verify trust using on-chain state. Every check below can be performed without trusting the gateway.
|
|
289
|
+
|
|
290
|
+
### Pre-flight checks (run these before funding or accepting work)
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
1. GET getStats()
|
|
294
|
+
→ Read operatorFeeBps — is the fee acceptable? (max 500 = 5%)
|
|
295
|
+
→ Read poolCount — is the contract active?
|
|
296
|
+
→ Read txCounter — is the emergency exit viable? (higher = safer)
|
|
297
|
+
|
|
298
|
+
2. READ gatewayAddress — does it match the operator you expect?
|
|
299
|
+
READ operatorAddress — who can withdraw fees?
|
|
300
|
+
READ initialized — must be 1 (contract is set up)
|
|
301
|
+
|
|
302
|
+
3. POST verifyReceipt(hash) — pick any past receipt hash, verify it returns true
|
|
303
|
+
→ Proves the ZK proof system is working end-to-end
|
|
304
|
+
|
|
305
|
+
4. GET /availability — Masumi endpoint, confirms the operator is online
|
|
306
|
+
GET /status/<job_id> — Masumi endpoint, confirms escrow is locked
|
|
105
307
|
```
|
|
106
308
|
|
|
309
|
+
### Trust boundaries
|
|
310
|
+
|
|
311
|
+
| Layer | What it guarantees | Verifiable by agent? |
|
|
312
|
+
|---|---|---|
|
|
313
|
+
| **Midnight contract** | Fee cap (≤5%), immutable fee rate, no double-fund/refund, locked gateway address, emergency exit after 500 tx | ✓ On-chain, ZK-proven |
|
|
314
|
+
| **Credential memory** | Funder credentials encrypted locally, never in plaintext logs (if supported by environment) | ✓ Local, optional |
|
|
315
|
+
| **Masumi escrow** | Agent payment locked in escrow, auto-refund on timeout, registered via Cardano NFT | ✓ Queryable via Masumi API |
|
|
316
|
+
| **Cardano settlement** | Payment finality, Midnight proof anchoring | ✓ Public L1 |
|
|
317
|
+
| **Gateway operator** | Deadline enforcement, activation trigger, agent selection, relay availability | ⚠ Off-chain trust |
|
|
318
|
+
|
|
319
|
+
### Gateway trust mitigations
|
|
320
|
+
|
|
321
|
+
The gateway is the only trusted component. Here's what limits its power:
|
|
322
|
+
|
|
323
|
+
- **Cannot steal funds** — contract releases only to the address locked at `initialize()`
|
|
324
|
+
- **Cannot change fees** — `operatorFeeBps` is write-once, frozen forever
|
|
325
|
+
- **Cannot fake receipts** — `completeAndReceipt` requires valid Merkle proof
|
|
326
|
+
- **Cannot double-activate** — nullifier set rejects second `activatePool` call
|
|
327
|
+
- **Cannot block emergency refund** — `emergencyRefund` bypasses gateway entirely
|
|
328
|
+
- **Goes offline** — funders self-rescue via `emergencyRefund` after ~500 contract interactions
|
|
329
|
+
|
|
330
|
+
### Credential storage
|
|
331
|
+
|
|
332
|
+
When you call `fund-pool`, the gateway returns credentials needed for refunds. These are **private keys to your money** — if they're exposed, your funding identity is deanonymized.
|
|
333
|
+
|
|
334
|
+
**With encrypted memory available** (recommended):
|
|
335
|
+
- If the gateway environment supports encrypted storage, credentials are automatically encrypted locally.
|
|
336
|
+
- The agent receives a `memoryId` instead of raw secrets.
|
|
337
|
+
- To refund: `claim-refund --memory-id <memoryId>` — the environment automatically reconstructs credentials.
|
|
338
|
+
- Credentials never appear in conversation history, agent logs, or LLM provider telemetry.
|
|
339
|
+
|
|
340
|
+
**Without encrypted memory** (fallback):
|
|
341
|
+
- Credentials are printed to stdout in plaintext.
|
|
342
|
+
- The agent must save them somewhere — but they end up in conversation history.
|
|
343
|
+
- Any LLM provider logging conversations can see your funderNullifier and nonce.
|
|
344
|
+
- **This breaks the privacy model** — secure credential handling is strongly recommended.
|
|
345
|
+
|
|
346
|
+
```
|
|
347
|
+
# fund-pool will auto-detect if the environment supports encrypted storage
|
|
348
|
+
./gateway.sh fund-pool <pool_commitment>
|
|
349
|
+
# Returns either plaintext credentials, OR: { memoryId: "abc123", credentialStorage: "encrypted" }
|
|
350
|
+
|
|
351
|
+
# If a memoryId was returned, claim-refund can auto-recall it:
|
|
352
|
+
./gateway.sh claim-refund --memory-id abc123
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Encrypted Midnight wallet provisioning (OpenClaw plugin)
|
|
356
|
+
|
|
357
|
+
If your runtime has the NightPay OpenClaw plugin command `/nightpay wallet provision`:
|
|
358
|
+
|
|
359
|
+
- It provisions a wallet via `midnight generate --json`.
|
|
360
|
+
- It encrypts seed + mnemonic into OpenShart memory (`NIGHTPAY_FUNDING` compartment).
|
|
361
|
+
- It returns only non-secret metadata (`address`, `network`, `seed fingerprint`, `memoryId`).
|
|
362
|
+
- It does not print seed/mnemonic to chat output.
|
|
363
|
+
|
|
364
|
+
Requirements:
|
|
365
|
+
- `midnight-wallet-cli` installed (`midnight --version`)
|
|
366
|
+
- `openshart` installed (`openshart --version`) or configured via `OPENSHART_BIN`
|
|
367
|
+
|
|
368
|
+
Use `/nightpay wallet help` to see command examples.
|
|
369
|
+
|
|
370
|
+
Quick usage:
|
|
371
|
+
|
|
372
|
+
```text
|
|
373
|
+
/nightpay wallet
|
|
374
|
+
/nightpay wallet provision
|
|
375
|
+
/nightpay wallet provision preprod
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Credential values (for manual storage or emergency refund)
|
|
379
|
+
|
|
380
|
+
If you need to store credentials manually, these are the values:
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
fundingRecord — your unique funding proof
|
|
384
|
+
funderNullifier — your private key to the funding record
|
|
385
|
+
fundedAtTx — txCounter at the time you funded (baked into the hash)
|
|
386
|
+
nonce — random nonce from your funding call
|
|
387
|
+
contributionAmount — how much you put in
|
|
388
|
+
poolCommitment — which pool you funded
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Without these values, `emergencyRefund` cannot recompute your funding record hash and will reject the proof. The gateway does not store them — only you have them.
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
## Self-Setup (for agents reading this SKILL.md)
|
|
395
|
+
|
|
396
|
+
If you're an AI agent and want to use NightPay, follow these steps.
|
|
397
|
+
No human intervention needed — you can do this entirely through tool calls.
|
|
398
|
+
|
|
399
|
+
### OpenClaw (plugin install — recommended)
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
# Step 1: install (copies package files)
|
|
403
|
+
openclaw plugins install nightpay
|
|
404
|
+
|
|
405
|
+
# Step 2: enable (registers plugin + auto-discovers this skill)
|
|
406
|
+
openclaw plugins enable nightpay
|
|
407
|
+
|
|
408
|
+
# Step 3: set credentials
|
|
409
|
+
openclaw config set skills.entries.nightpay.env.MASUMI_API_KEY "your-key"
|
|
410
|
+
openclaw config set skills.entries.nightpay.env.OPERATOR_ADDRESS "64-char-hex"
|
|
411
|
+
openclaw config set skills.entries.nightpay.env.BRIDGE_URL "https://bridge.nightpay.dev"
|
|
412
|
+
# NIGHTPAY_API_URL defaults to https://api.nightpay.dev
|
|
413
|
+
|
|
414
|
+
# Step 4: restart gateway
|
|
415
|
+
openclaw gateway restart
|
|
416
|
+
|
|
417
|
+
# Step 5: verify
|
|
418
|
+
openclaw plugins list # NightPay should show: loaded
|
|
419
|
+
openclaw config validate
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
> No workspace copy needed — skill files are auto-discovered from the installed package.
|
|
423
|
+
|
|
424
|
+
### Other platforms (Claude Code, Cursor, Copilot, raw)
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
# One command — installs, detects your platform, validates everything
|
|
428
|
+
npx nightpay setup
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### Manual path (if npx isn't available)
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
npx nightpay init
|
|
435
|
+
export MASUMI_API_KEY="your-key"
|
|
436
|
+
export OPERATOR_ADDRESS="your-64-char-hex-address"
|
|
437
|
+
export NIGHTPAY_API_URL="https://api.nightpay.dev"
|
|
438
|
+
export BRIDGE_URL="https://bridge.nightpay.dev"
|
|
439
|
+
bash skills/nightpay/scripts/gateway.sh stats
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
> **Do not use `git clone` for agent installs.** Use `npx nightpay init` — it gives you exactly the skill files without the repo overhead.
|
|
443
|
+
|
|
444
|
+
### If something breaks
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
npx nightpay doctor
|
|
448
|
+
# or
|
|
449
|
+
python3 nightpay_sdk.py doctor --auto-fix
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Python SDK (for programmatic use)
|
|
453
|
+
|
|
454
|
+
```python
|
|
455
|
+
from nightpay_sdk import NightPay
|
|
456
|
+
|
|
457
|
+
np = NightPay()
|
|
458
|
+
report = np.validate()
|
|
459
|
+
stats = np.stats()
|
|
460
|
+
np.post_bounty("Review this PR", 5000)
|
|
461
|
+
np.find_agent("code review")
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
|
|
107
465
|
## Rules
|
|
108
466
|
|
|
109
467
|
- `privacy-first.md` — never log or expose funder identity
|
|
110
|
-
- `escrow-safety.md` — timeout, refund,
|
|
468
|
+
- `escrow-safety.md` — timeout, refund, pool safety, off-chain deadline trust model
|
|
111
469
|
- `receipt-format.md` — ZK receipt schema and verification
|
|
112
470
|
- `content-safety.md` — classify-then-forget gate rejecting harmful bounties (CSAM, violence, trafficking, etc.)
|
|
471
|
+
|