@kuiralabs/midnight-account-chain 0.0.0-stage → 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.
Files changed (56) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +300 -2
  3. package/dist/cli/owner.d.ts +3 -0
  4. package/dist/cli/owner.js +260 -0
  5. package/dist/driver.d.ts +34 -0
  6. package/dist/driver.js +121 -0
  7. package/dist/managed/Account/compiler/contract-info.json +5712 -0
  8. package/dist/managed/Account/compiler/contract-manifest.json +639 -0
  9. package/dist/managed/Account/contract/index.d.ts +1688 -0
  10. package/dist/managed/Account/contract/index.js +12892 -0
  11. package/dist/managed/Account/contract/index.js.map +8 -0
  12. package/dist/scripts/completeDeploy.d.ts +2 -0
  13. package/dist/scripts/completeDeploy.js +42 -0
  14. package/dist/scripts/deploy.d.ts +9 -0
  15. package/dist/scripts/deploy.js +136 -0
  16. package/dist/src/account.d.ts +17 -0
  17. package/dist/src/account.js +25 -0
  18. package/dist/src/agent.d.ts +58 -0
  19. package/dist/src/agent.js +279 -0
  20. package/dist/src/artefacts.d.ts +13 -0
  21. package/dist/src/artefacts.js +257 -0
  22. package/dist/src/coins.d.ts +25 -0
  23. package/dist/src/coins.js +159 -0
  24. package/dist/src/compose.d.ts +11 -0
  25. package/dist/src/compose.js +90 -0
  26. package/dist/src/connect.d.ts +18 -0
  27. package/dist/src/connect.js +37 -0
  28. package/dist/src/deposit.d.ts +6 -0
  29. package/dist/src/deposit.js +13 -0
  30. package/dist/src/device.d.ts +25 -0
  31. package/dist/src/device.js +50 -0
  32. package/dist/src/grantee.d.ts +32 -0
  33. package/dist/src/grantee.js +45 -0
  34. package/dist/src/indexer.d.ts +2 -0
  35. package/dist/src/indexer.js +89 -0
  36. package/dist/src/issuance.d.ts +36 -0
  37. package/dist/src/issuance.js +349 -0
  38. package/dist/src/localnet.d.ts +16 -0
  39. package/dist/src/localnet.js +50 -0
  40. package/dist/src/mailbox.d.ts +9 -0
  41. package/dist/src/mailbox.js +44 -0
  42. package/dist/src/maintenance.d.ts +13 -0
  43. package/dist/src/maintenance.js +100 -0
  44. package/dist/src/ownerCalls.d.ts +19 -0
  45. package/dist/src/ownerCalls.js +106 -0
  46. package/dist/src/profile.d.ts +10 -0
  47. package/dist/src/profile.js +73 -0
  48. package/dist/src/providers.d.ts +11 -0
  49. package/dist/src/providers.js +33 -0
  50. package/dist/src/reader.d.ts +31 -0
  51. package/dist/src/reader.js +73 -0
  52. package/dist/src/seedWallets.d.ts +75 -0
  53. package/dist/src/seedWallets.js +31 -0
  54. package/dist/src/session.d.ts +47 -0
  55. package/dist/src/session.js +133 -0
  56. package/package.json +50 -4
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright {yyyy} {name of copyright owner}
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md CHANGED
@@ -1,3 +1,301 @@
1
- # Temporary Holding Version
1
+ # chain
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The account contract on a local ledger-9 network. This package builds the same
4
+ `../account/contract/Account.compact` as the library, with Compact 0.35.0 in place
5
+ of 0.34.0. The reason is the SDK: midnight-js 5.0.0-rc.1 and the wallet SDK
6
+ 2.0.0-rc.0 run on compact-runtime 0.20.0, which only a 0.35.0 build targets.
7
+ The library keeps 0.34.0, because OpenZeppelin's simulator is still on
8
+ runtime 0.19.0.
9
+
10
+ ## The stack
11
+
12
+ Every component is on ledger 9.1.0.0-rc.5:
13
+
14
+ | Component | Version |
15
+ |---|---|
16
+ | Compact | 0.35.0 (runtime 0.20.0) |
17
+ | midnight-js | 5.0.0-rc.1, with testkit-js 5.0.0-rc.1 |
18
+ | Wallet SDK | `@midnightntwrk/wallet-sdk` 2.0.0-rc.0 |
19
+ | Node | `midnightntwrk/midnight-node:2.1.0-rc.2` |
20
+ | Indexer | built from midnight-indexer main at `3e9f6374` |
21
+ | Proof server | `midnightntwrk/proof-server:9.0.0-rc.8` |
22
+
23
+ The public networks (Preview, Preprod) still run ledger 8. Midnight's
24
+ compatibility matrix does not cover ledger 9 yet.
25
+
26
+ The indexer has to be built from source:
27
+ - Every published ledger-9 indexer image is 4.4.0-rc.2, which is on ledger rc.3.
28
+ - Newer indexers exist only as source.
29
+
30
+ Node 2.1.0-rc.2 is the newest node version the indexer carries metadata for.
31
+
32
+ ## Running
33
+
34
+ Build the indexer image once. Use the release profile, which is the Dockerfile's default:
35
+
36
+ ```
37
+ git clone https://github.com/midnightntwrk/midnight-indexer && cd midnight-indexer
38
+ git checkout 3e9f6374
39
+ docker build --build-arg RUST_VERSION=$(sed -nr 's/channel = "(.*)"/\1/p' rust-toolchain.toml) \
40
+ -t midnight-bench/indexer-standalone:4.4.0-rc.5-3e9f6374 -f indexer-standalone/Dockerfile .
41
+ ```
42
+
43
+ Start the localnet. The indexer needs a 32-byte hex secret in `infra/.env`, which git ignores:
44
+
45
+ ```
46
+ cd infra
47
+ echo "APP__INFRA__SECRET=$(openssl rand -hex 32)" > .env
48
+ docker compose up -d
49
+ ```
50
+
51
+ Compile with keys, then deploy:
52
+
53
+ ```
54
+ npm install # after npm install in the repository root, which builds the library
55
+ npm run compile # 30 circuits, about 4 GB of proving keys
56
+ node scripts/deploy.ts
57
+ ```
58
+
59
+ ## Deploying
60
+
61
+ The whole roster's verifier keys come to 73,806 bytes. A single deploy is
62
+ refused by the fee computation before any transaction exists: `exceeded block
63
+ limit in transaction fee computation`. The grants draft (section 6.7) measured
64
+ the same.
65
+
66
+ `scripts/deploy.ts` therefore deploys in waves:
67
+ 1. **The deploy transaction.** It carries the two deposits and the eight
68
+ circuits of the arm the account is born on.
69
+ 2. **Maintenance updates.** `src/maintenance.ts` adds every other circuit's key,
70
+ packed to 25,000 bytes per update. That is the draft's budget, below the
71
+ ceiling it measured between 29,484 and 32,229 bytes.
72
+
73
+ On this localnet that is four transactions in about 75 seconds. Then
74
+ midnight-js's own `findDeployedContract` checks every on-chain key against the build.
75
+
76
+ The maintenance updates are built by hand on the ledger-v9 API, not through
77
+ midnight-js's `submitInsertVerifierKeyTx`:
78
+ - compact-js, in every 3.0.0 release so far, wraps inserted keys at
79
+ contract-operation version `'v3'`, which expects a `verifier-key[v6]` header.
80
+ - A ZKIR v3 build writes `verifier-key[v7]`, which needs version `'v4'`.
81
+ - So the SDK path fails for any ZKIR v3 contract before a transaction exists.
82
+ - The update built here is the one compact-js builds, at the version the key
83
+ actually carries.
84
+
85
+ The last update also retires the maintenance authority (the grants draft,
86
+ section 6.7): it replaces the authority with an empty committee at threshold
87
+ 1, which can sign nothing. After it, no one can change the contract's rules.
88
+
89
+ `scripts/completeDeploy.ts` resumes an interrupted deploy. It inserts only
90
+ the entry points that are still blank, and leaves a finished account as it
91
+ is.
92
+
93
+ The owner's key material is written to `.state/`, which git ignores:
94
+ - the JubJub device key
95
+ - the boot salt
96
+ - the X25519 account encryption key
97
+
98
+ The maintenance authority's key is written to the level private-state store in
99
+ `midnight-level-db/`.
100
+
101
+ ## The account on chain
102
+
103
+ After the deploy, these scripts run the account's life as its parties see
104
+ it. Each one proves on the local proof server and submits to the node:
105
+
106
+ | Script | Who | What |
107
+ |---|---|---|
108
+ | `scripts/deploy.ts [v1 \| k1]` | owner | deploys an account born on a JubJub or a secp256k1 device key, in waves, and retires the authority |
109
+ | `scripts/activate.ts` | owner | activates the boot device, on either arm |
110
+ | `scripts/owner.ts` | owner | activates the boot device; the unshielded deposit it then tries is refused (below) |
111
+ | `scripts/depositShielded.ts` | anyone | `deposit_shielded`, with the InboxEntry sealed to `enc_key` read from chain |
112
+ | `scripts/discoverCoins.ts` | owner | the inbox walk (MIP-0012 section 6.5) |
113
+ | `scripts/ownerShielded.ts` | owner | a shielded withdrawal to the genesis wallet, then the change backfilled by `append_inbox` |
114
+ | `scripts/ownerPayContract.ts <payee>` | owner | pays another contract, composed with the payee's claim |
115
+ | `scripts/agentRequest.ts <account> [slot] [v1 \| k1] [payee contract]` | agent | a grant request: grantee key, X25519 read key, origin, slot, payee |
116
+ | `scripts/issueGrant.ts [seconds]` | owner | rotate before share, re-seal to the other live read grants, `issue_grant`, the sealed view |
117
+ | `scripts/agentSpend.ts [slot]` | agent | pays the merchant under the grant from its own wallet; an over-cap payment is refused |
118
+ | `scripts/agentPayContract.ts <slot> <payee>` | agent | pays a contract under a grant pinned to it, composed with the payee's claim |
119
+ | `scripts/admissionExpiry.ts <slot> [hold]` | agent | proves while live, holds, submits: refused after `expires_at`, included before it |
120
+ | `scripts/inFlight.ts <slot> <deposit \| revoke>` | agent | proves, then a deposit or a revocation lands, then submits: refused |
121
+ | `scripts/revokeGrant.ts <slot>` | owner | `revoke_grant`, then the rotation and re-seals section 8 item 6 asks |
122
+ | `scripts/revokeAllGrants.ts` | owner | `revoke_all_grants`, then the rotation |
123
+ | `scripts/agentStatus.ts [slot] [--mailbox-only]` | agent | what the agent sees of its grant, and where it learned it |
124
+ | `cli/owner.ts <command>` | owner | the owner's command line: `status`, `grants`, `issue <link> [--yes]`, `revoke <id \| slot>`, `revoke-all`, `revoke-exhausted [<id>...] [--yes]`, each with `--json` |
125
+
126
+ Each account is a profile (`src/profile.ts`). The first account's records
127
+ are in `.state/`. Another account is deployed and driven under its own
128
+ `BENCH_PROFILE`, with records in `.state/<profile>/`. For example, a
129
+ k1-born account:
130
+
131
+ ```
132
+ BENCH_PROFILE=k1 node scripts/deploy.ts k1
133
+ BENCH_PROFILE=k1 node scripts/activate.ts
134
+ ```
135
+
136
+ The owner's gated calls go through one API that picks the circuit of the
137
+ device's arm, `_with_jubjub` or `_with_k256` (`src/ownerCalls.ts`). The
138
+ agent's grant spends do the same by the grantee key's arm.
139
+
140
+ Four wallets take part: the owner pays from genesis seed `…01`, the agent
141
+ from `…02`, and the merchant is `…03`'s shielded address.
142
+
143
+ The owner's code also runs over a wallet it did not build. Anything that offers midnight-js's wallet and submit providers (`FeeWallet` in `src/providers.ts`; a wallet behind a DApp connector, say) can pay. Such a caller imports one module, `driver.ts`: `deployOver` deploys the account on the k1 arm and activates its boot device, on a device key the caller may bring, and is safe to run again (it completes a deploy that stopped part way, and moves aside the record of one that never reached the chain); `runOwnerOver` runs one of the owner's commands and hands back the result. The caller names its endpoints as URLs (`MIDNIGHT_ACCOUNT_NODE_URL`, `MIDNIGHT_ACCOUNT_INDEXER_URL`, `MIDNIGHT_ACCOUNT_PROOF_SERVER_URL`) and keeps its accounts' records outside the repo by naming a directory in `MIDNIGHT_ACCOUNT_STATE_DIR`; profiles live under it as they do under `.state/`.
144
+
145
+ Nothing is kept that the chain can give back:
146
+ - The owner's device use counter is recovered from the `devices` set.
147
+ - Both coin stores are rebuilt by the inbox walk on every session.
148
+ - The owner keeps every encryption secret it has held, so its walk reads the
149
+ whole inbox. A delegate holds only the current one.
150
+
151
+ ### Coin discovery
152
+
153
+ The walk verifies each opened entry against the ledger's own `zswapOutput`
154
+ events for the account:
155
+ - The commitment is recomputed with the ledger's `runtimeCoinCommitment`.
156
+ - The event carries the coin's `mt_index`, so no position window or candidate
157
+ retry is needed.
158
+ - A coin is spent when its nullifier (`runtimeCoinNullifier`, with the
159
+ contract as sender) is among the account's `zswapInput` events.
160
+
161
+ `deposit_shielded` is permissionless, so the inbox can hold anything
162
+ 192 bytes long. The walk skips any entry it cannot open, including one whose
163
+ ephemeral key is of low order, where the X25519 derivation itself fails. It
164
+ treats every such entry as inert noise (grants draft section 8 item 4), so no
165
+ depositor can stop the walk.
166
+
167
+ The events come from the indexer's `contractActions` subscription, which
168
+ lists a contract's transactions by address. MIP-0012 records that surface as
169
+ an ecosystem dependency; the indexer at `3e9f6374` has it.
170
+
171
+ ### A grant, end to end
172
+
173
+ The draft's flow, with no step skipped:
174
+ 1. **The agent's request** carries its grantee key, its read key and the
175
+ merchant's coin key.
176
+ 2. **The owner** checks both keys (section 3.3, section 8 item 1), then
177
+ rotates before share (section 8 item 2):
178
+ - `rotate_enc_key_with_jubjub`
179
+ - one `append_inbox_with_jubjub` per held coin
180
+ - a re-seal of the new secret to every other live read grant
181
+ 3. **The owner issues** the grant under the boot device and seals the new
182
+ secret to the read key in a 94-byte GrantViewSeal (section 8 item 3).
183
+ 4. **The agent** opens the view and checks that `X25519(secret, 9)` is
184
+ `enc_key`. Then it walks the inbox and pays the merchant with
185
+ `withdraw_shielded_with_grant_jubjub`, sealing the change entry itself.
186
+
187
+ Neither party can lose track through a crash:
188
+ - **The owner** writes its roster before each step. A read grant is marked
189
+ for re-seal before a rotation blinds it; a new grant is written before it
190
+ is issued. The next run finishes what the last one left.
191
+ - **Interrupted issues.** One that landed is sealed on the next run. One
192
+ that left nothing on chain is kept as `issuing` while its transaction could
193
+ still land, an hour plus a margin by midnight-js's expiry, then marked
194
+ `abandoned`.
195
+ - **Unknown read grants.** A live read grant on chain that the roster holds
196
+ no key for is surfaced as requiring reconnection.
197
+ - **Re-seals** go only to the key the record's `read_pk_hash` names.
198
+ - **Rotation secrets** are written before the rotation is submitted, and
199
+ none is ever dropped.
200
+ - **Revocations.** A revocation records the rotation it owes before it is
201
+ submitted, so the rotation happens once, however many grants it revoked.
202
+ A revocation that never landed is retried, and its grant is never
203
+ re-sealed in the meantime.
204
+ - **Change coins** are recorded before the spend that creates them. Each
205
+ session open backfills any recorded change the chain created but no inbox
206
+ entry describes.
207
+ - **The use counter** is re-read from the `devices` set after every gated
208
+ call, whether or not the call landed.
209
+ - **The agent** keys its running spend by grant incarnation (the grant id
210
+ with `issued_at`), so a re-issued grant starts from zero. It records a
211
+ spend as pending before submitting it. Its
212
+ running spend is checked against the record's `spent_commit` on every
213
+ session and before every spend, and a pending spend is counted once that
214
+ commitment shows it landed.
215
+
216
+ Measured on this localnet, with one held coin:
217
+ - Issuing a read grant takes three transactions: rotation 48 s (two
218
+ transactions), then issue 24 s.
219
+ - Each grant spend takes about 30 s.
220
+
221
+ The runs check each outcome on chain:
222
+ - **Payment.** The merchant's coin is found by its commitment in the
223
+ transaction's events. The change is found by the agent's next walk.
224
+ - **Over the cap.** A payment that would exceed the cap fails the circuit's
225
+ own assert before any proof exists.
226
+ - **Admission expiry.** A spend proved while the grant is live and held
227
+ 173 s is included if submitted before `expires_at`. Submitted after it,
228
+ the node refuses it from the mempool, with custom error 104: `guaranteed
229
+ execution would fail: mismatch between expected (<[01]: b1>) and actual
230
+ (<[-]: b1>) read`. The proof recorded the block-time comparison as true;
231
+ at admission it reads false. The record's nonce and the coin are untouched.
232
+
233
+ ### The grant mailbox
234
+
235
+ The owner's response to a grant request travels on chain, sealed to the
236
+ agent's read key (`../src/grants/mailbox.ts`, `src/mailbox.ts`):
237
+ - **What it is.** Two `append_inbox` entries carry the scope's salt and
238
+ object, its `rp_id_hash`, and the account secret.
239
+ - **Finding it.** The agent computes its grant id, walks the inbox with its
240
+ read key, and checks the message against the record's commitments and
241
+ `enc_key`.
242
+ - **Re-seals.** After a rotation they arrive the same way, so the agent
243
+ picks up the new secret by reading the chain again.
244
+ - **Fallback.** The owner also writes the same sealed message as a response
245
+ file, and `cli/owner.ts issue` prints it as a link for a QR code. Nothing
246
+ in it is in clear, and the agent verifies it exactly as a mailbox message.
247
+ `--mailbox-only` ignores it.
248
+ - **Grant requests** travel as a link: 276 characters with a 16-byte
249
+ `client_id`, up to about 600 with the longest the form admits
250
+ (`midnight-mandate:grant-request?r=…`), which `scripts/agentRequest.ts`
251
+ prints and `cli/owner.ts issue` takes.
252
+
253
+ On chain:
254
+ - **Learned from chain alone.** An agent ignoring every file learned a new
255
+ grant from the mailbox and paid under it.
256
+ - **Re-seals arrive.** An older grant's re-seal arrived through the mailbox.
257
+ - **Other readers.** The owner's coin walk skipped every mailbox entry.
258
+ - **Cost.** Each message is two appends, about 48 s together here.
259
+
260
+ ### On chain, beyond the first grant
261
+
262
+ Every one of these was run against the node:
263
+ - **Both owner-device arms.** A k1-born account activates, withdraws and
264
+ backfills with `_with_k256` circuits, then issues a grant with
265
+ `issue_grant_with_k256`.
266
+ - **Both grantee arms.** A secp256k1 grantee under envelope 0 pays with
267
+ `withdraw_shielded_with_grant_k256`. Envelope-1 grantees are read-only, by
268
+ the draft's section 3.2.
269
+ - **Paying a contract.** The owner's `withdraw_shielded_to_contract_with_jubjub`
270
+ and an agent's `withdraw_shielded_to_contract_with_grant_jubjub` each land
271
+ in one transaction with the payee's `deposit_shielded` claim
272
+ (`src/compose.ts`), and the payee's own walk finds the coin.
273
+ - **In flight.** A spend proved before a deposit, or before a revocation, is
274
+ refused from the mempool on the read that changed: `round`, or the
275
+ record's `active`.
276
+ - **Revocation.** `revoke_grant` and `revoke_all_grants`, each followed by
277
+ the rotation. Afterwards the revoked agent's view still opens, to a secret
278
+ that is no longer `enc_key`, so the agent refuses to act on it ("reconnect
279
+ to the owner"). After revoke-all, its record is gone as well.
280
+
281
+ ### Findings
282
+
283
+ The findings written up for their teams are in `../docs/findings/`.
284
+
285
+ - **An unshielded deposit is refused by the fee computation.**
286
+ `deposit_unshielded` fails with custom error 231,
287
+ `FeeCalculationError::OutsideTimeToDismiss`. Under the on-chain ledger
288
+ parameters (read from the indexer's `block.ledgerParameters`), validation
289
+ plus guaranteed cost comes out 21 µs over the time-to-dismiss bound.
290
+ `scripts/diagnoseDeposit.ts` reproduces it. The shielded path runs instead.
291
+ - **The change coin is predictable, as the draft says.** A grantee seals the
292
+ change entry, which the challenge covers, before the proof exists. The
293
+ draft's section 6.5 gives the change nonce as Compact's stdlib evolution of
294
+ the spent nonce under `midnight:kernel:nonce_evolve/2`. It matched every
295
+ change the chain created here (`chain/src/coins.ts`, `changeCoinOf`).
296
+ - **Paying a pinned shielded recipient needs its encryption key.** The grant
297
+ pins the merchant by coin public key (`recipient_kind` 2). midnight-js still
298
+ refuses to build the output without the recipient's encryption public key:
299
+ it encrypts the output so the recipient's wallet finds the coin. So the
300
+ grantee needs the merchant's full shielded address, off chain. Neither the
301
+ grant nor the request carries it.
@@ -0,0 +1,3 @@
1
+ import type { Session } from '../src/session.ts';
2
+ export type Out = (text: string) => void;
3
+ export declare const runOwner: (argv: readonly string[], open: () => Promise<Session>, out?: Out) => Promise<number>;