@rootzero/contracts 1.10.0 → 1.11.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/CHANGELOG.md +20 -1
- package/Core.sol +1 -0
- package/Endpoints.sol +1 -3
- package/Events.sol +2 -5
- package/README.md +35 -33
- package/Utils.sol +2 -1
- package/blocks/Cursors.sol +26 -75
- package/blocks/Keys.sol +14 -4
- package/blocks/Schema.sol +49 -44
- package/commands/Base.sol +43 -13
- package/commands/Burn.sol +3 -6
- package/commands/Credit.sol +9 -6
- package/commands/Debit.sol +15 -11
- package/commands/Deposit.sol +19 -23
- package/commands/Payout.sol +6 -10
- package/commands/Provision.sol +19 -23
- package/commands/Recover.sol +7 -9
- package/commands/Relay.sol +10 -11
- package/commands/Withdraw.sol +3 -6
- package/commands/admin/AllowAssets.sol +7 -10
- package/commands/admin/Allowance.sol +7 -10
- package/commands/admin/Appoint.sol +7 -10
- package/commands/admin/Authorize.sol +7 -10
- package/commands/admin/Base.sol +1 -2
- package/commands/admin/DenyAssets.sol +7 -10
- package/commands/admin/Dismiss.sol +7 -10
- package/commands/admin/Execute.sol +7 -10
- package/commands/admin/Label.sol +8 -11
- package/commands/admin/Unauthorize.sol +7 -10
- package/core/Endpoint.sol +153 -0
- package/docs/Schema.md +114 -82
- package/events/Endpoint.sol +19 -0
- package/events/Schema.sol +23 -0
- package/guards/Base.sol +17 -8
- package/guards/Revoke.sol +4 -6
- package/package.json +1 -1
- package/ports/AllowAssets.sol +6 -9
- package/ports/Allowance.sol +6 -9
- package/ports/Base.sol +21 -8
- package/ports/Credit.sol +6 -9
- package/ports/Debit.sol +6 -9
- package/ports/DenyAssets.sol +6 -9
- package/ports/Dispatch.sol +6 -9
- package/ports/Pipe.sol +4 -7
- package/ports/Redeem.sol +4 -7
- package/ports/Settle.sol +6 -9
- package/queries/Assets.sol +9 -12
- package/queries/Balances.sol +7 -9
- package/queries/Base.sol +19 -11
- package/utils/Selectors.sol +49 -0
- package/commands/admin/Destroy.sol +0 -43
- package/commands/admin/Init.sol +0 -43
- package/events/Admin.sol +0 -32
- package/events/Command.sol +0 -32
- package/events/Guard.sol +0 -18
- package/events/Port.sol +0 -22
- package/events/Query.sol +0 -20
- package/queries/Positions.sol +0 -54
package/docs/Schema.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Schema
|
|
2
2
|
|
|
3
3
|
Rootzero request and response data is encoded as a stream of typed blocks. A
|
|
4
|
-
schema string describes payload
|
|
5
|
-
runtime block key is
|
|
4
|
+
schema string describes the payload body for discovery events and tooling; the
|
|
5
|
+
runtime block key is the compact type tag that identifies that payload layout in
|
|
6
|
+
the active schema context. The block alias is published separately from the
|
|
7
|
+
payload schema.
|
|
6
8
|
|
|
7
9
|
## Wire Format
|
|
8
10
|
|
|
@@ -15,39 +17,50 @@ Every block uses the same header:
|
|
|
15
17
|
`payloadLen` is big-endian and counts only payload bytes. Child blocks and list
|
|
16
18
|
items use the same header format.
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
Standard built-in block keys use:
|
|
19
21
|
|
|
20
22
|
```txt
|
|
21
23
|
bytes4(keccak256("#name"))
|
|
22
24
|
```
|
|
23
25
|
|
|
24
|
-
For example,
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
For example, the standard `amount` alias uses the key derived from `#amount`
|
|
27
|
+
and the schema body `{ bytes32 asset, uint amount }`. Custom block keys do not
|
|
28
|
+
have to be keccak-derived. They
|
|
29
|
+
are opaque `bytes4` tags and only need to be unique in the context where they are
|
|
30
|
+
used. A host can publish the meaning of a custom key with:
|
|
31
|
+
|
|
32
|
+
```solidity
|
|
33
|
+
event Schema(uint indexed host, bytes4 key, string schema, bytes32 name);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
For example, a host-specific payment block can use `Keys.local(1)`, the command
|
|
37
|
+
selector, or any other chosen `bytes4` value as long as that key is not
|
|
38
|
+
overloaded in the relevant host/schema context.
|
|
27
39
|
|
|
28
40
|
## Block Syntax
|
|
29
41
|
|
|
30
|
-
A block
|
|
42
|
+
A block definition has an event alias and a schema body. Fixed fields are
|
|
43
|
+
written in braces:
|
|
31
44
|
|
|
32
45
|
```txt
|
|
33
|
-
|
|
34
|
-
|
|
46
|
+
alias: amount
|
|
47
|
+
schema: { bytes32 asset, uint amount }
|
|
35
48
|
```
|
|
36
49
|
|
|
37
|
-
A block
|
|
50
|
+
A block body can reference another block alias as a child item with `#`:
|
|
38
51
|
|
|
39
52
|
```txt
|
|
40
|
-
#
|
|
41
|
-
#bytes
|
|
53
|
+
{ bytes32 account, #bytes as state, #bytes as request }
|
|
42
54
|
```
|
|
43
55
|
|
|
44
|
-
|
|
56
|
+
The empty schema string `""` means the block has no structured payload. This is
|
|
57
|
+
used for zero-payload blocks such as `#unit` and raw dynamic blocks such as
|
|
58
|
+
`#bytes`.
|
|
45
59
|
|
|
46
|
-
A schema is a comma-separated list of items. Order is significant.
|
|
60
|
+
A schema body is a comma-separated list of items. Order is significant.
|
|
47
61
|
|
|
48
62
|
```txt
|
|
49
|
-
#amount
|
|
50
|
-
maybe #account { bytes32 account }
|
|
63
|
+
{ #amount, maybe #account as recipient }
|
|
51
64
|
```
|
|
52
65
|
|
|
53
66
|
## Payload Layout
|
|
@@ -56,8 +69,8 @@ A block payload has fixed fields first, followed by an optional child-block tail
|
|
|
56
69
|
Once a child block appears, no more fixed fields may follow.
|
|
57
70
|
|
|
58
71
|
```txt
|
|
59
|
-
|
|
60
|
-
|
|
72
|
+
{ uint target, uint resources, #bytes as payload }
|
|
73
|
+
{ bytes32 account, #bytes as state, #bytes as request }
|
|
61
74
|
```
|
|
62
75
|
|
|
63
76
|
The tail is embedded directly as child block bytes. There is no wrapper around a
|
|
@@ -75,59 +88,87 @@ alias to give those bytes a presentation name:
|
|
|
75
88
|
Cardinality is expressed with prefix keywords:
|
|
76
89
|
|
|
77
90
|
```txt
|
|
78
|
-
#balance
|
|
79
|
-
maybe #balance
|
|
80
|
-
many #balance
|
|
81
|
-
maybe many #balance
|
|
91
|
+
#balance
|
|
92
|
+
maybe #balance
|
|
93
|
+
many #balance
|
|
94
|
+
maybe many #balance
|
|
82
95
|
```
|
|
83
96
|
|
|
84
97
|
- no prefix: one required item
|
|
85
98
|
- `maybe`: optional item
|
|
86
|
-
- `many`: one `#list` block whose payload contains repeated items
|
|
99
|
+
- `many`: one generic `#list` block whose payload contains repeated items
|
|
87
100
|
- `maybe many`: optional `#list` block
|
|
88
101
|
|
|
89
102
|
`maybe` emits no placeholder when absent. `many` wraps repeated items in one
|
|
90
103
|
generic list block; it does not repeat the item in place.
|
|
91
104
|
|
|
92
|
-
##
|
|
105
|
+
## Endpoint Lanes
|
|
106
|
+
|
|
107
|
+
Endpoint descriptors identify each lane with a block key and group size. In
|
|
108
|
+
Solidity, endpoint definition helpers accept `bytes9` lane values, with plain
|
|
109
|
+
`bytes4` keys and the `bytes8` values returned by `many(item)` widening
|
|
110
|
+
implicitly. A plain key or `many(item)` stores a zero group byte that readers
|
|
111
|
+
interpret as group size 1, while `bytes9(0)` or `Keys.Empty` means the endpoint
|
|
112
|
+
has no blocks in that lane. Use
|
|
113
|
+
`group(lane, size)` when a lane needs an explicit group size other than 1.
|
|
114
|
+
|
|
115
|
+
The packed descriptor stores each lane key as an 8-byte value:
|
|
116
|
+
|
|
117
|
+
```txt
|
|
118
|
+
[key bytes4][item bytes4]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
A plain block key is widened into `[key][0]`, so normal endpoint declarations can
|
|
122
|
+
pass standard `bytes4` keys directly. A lane with a nonzero `item` describes a
|
|
123
|
+
generic container block: `key` is the top-level wire key and `item` is the
|
|
124
|
+
contained item key. The built-in `many(item)` helper creates `[Keys.List][item]`
|
|
125
|
+
with the default group size 1, matching the DSL form `many #item`.
|
|
93
126
|
|
|
94
|
-
|
|
127
|
+
Any non-empty lane resolves its key to a block alias and schema body through the
|
|
128
|
+
active schema context. If the item slot is nonzero, tooling also resolves that
|
|
129
|
+
item key in the same context. A bare list lane, `[Keys.List][0]`, is incomplete
|
|
130
|
+
discovery metadata because it does not say what the list contains; indexers
|
|
131
|
+
should reject it for self-describing endpoints.
|
|
95
132
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
133
|
+
The lane key is the prime item. Prime items may repeat at the top level for
|
|
134
|
+
batching. When the lane is `many #item`, the repeated prime item is the generic
|
|
135
|
+
LIST block and each LIST payload contains repeated `item` blocks. Later
|
|
136
|
+
top-level items are globals for the whole batch and are not counted as
|
|
137
|
+
per-operation prime blocks.
|
|
99
138
|
|
|
100
|
-
The prime item cannot be optional. If
|
|
101
|
-
no payload, use a zero-payload block such as `#unit`.
|
|
139
|
+
The prime item cannot be optional. If an endpoint needs a per-operation marker
|
|
140
|
+
with no payload, use a zero-payload block such as `#unit`.
|
|
102
141
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
items. Future protocol surfaces may use the more flexible
|
|
106
|
-
|
|
142
|
+
Endpoint descriptors currently use a narrower convention than the full block
|
|
143
|
+
grammar: each state, input, or output lane is a single run of blocks, without
|
|
144
|
+
additional global items. Future protocol surfaces may use the more flexible
|
|
145
|
+
top-level structure.
|
|
107
146
|
|
|
108
|
-
## Aliases
|
|
147
|
+
## Field Aliases
|
|
109
148
|
|
|
110
|
-
|
|
111
|
-
or runtime keys.
|
|
149
|
+
Block aliases are published in `Schema` events. Field aliases are presentation
|
|
150
|
+
metadata for tooling. They do not change payload layout or runtime keys.
|
|
112
151
|
|
|
113
152
|
```txt
|
|
114
|
-
maybe #account
|
|
115
|
-
|
|
153
|
+
maybe #account as recipient
|
|
154
|
+
{ uint target, uint resources, #bytes as payload }
|
|
116
155
|
```
|
|
117
156
|
|
|
118
|
-
|
|
157
|
+
Field aliases may be used on any block item, including child blocks and prime
|
|
158
|
+
items.
|
|
119
159
|
|
|
120
|
-
|
|
160
|
+
Child blocks are schema references:
|
|
121
161
|
|
|
122
162
|
```txt
|
|
123
|
-
|
|
163
|
+
{ uint handler, uint resources, bytes32 key, #bytes as witness }
|
|
124
164
|
```
|
|
125
165
|
|
|
126
|
-
Alias resolution is context-dependent. A consumer may resolve `#context` from
|
|
127
|
-
standard
|
|
128
|
-
schema context.
|
|
129
|
-
|
|
130
|
-
|
|
166
|
+
Alias resolution is context-dependent. A consumer may resolve `#context` from
|
|
167
|
+
standard block events, from app-specific block events, or from another active
|
|
168
|
+
schema context. Custom parents should define nested custom blocks from the
|
|
169
|
+
bottom up and reference them by alias. Consumers should reject schemas with
|
|
170
|
+
unresolved aliases. The runtime encoding is still an embedded child block with
|
|
171
|
+
the referenced key and layout.
|
|
131
172
|
|
|
132
173
|
## Field Paths
|
|
133
174
|
|
|
@@ -136,13 +177,13 @@ path does not change the block key, payload bytes, payload length, cursor
|
|
|
136
177
|
behavior, or any onchain validation. It is metadata only.
|
|
137
178
|
|
|
138
179
|
```txt
|
|
139
|
-
|
|
180
|
+
{ uint dst.portal, uint dst.resources, #bytes as dst.payload }
|
|
140
181
|
```
|
|
141
182
|
|
|
142
183
|
This has the same runtime layout as:
|
|
143
184
|
|
|
144
185
|
```txt
|
|
145
|
-
|
|
186
|
+
{ uint portal, uint resources, #bytes as payload }
|
|
146
187
|
```
|
|
147
188
|
|
|
148
189
|
Offchain tooling may decode the dotted form into a nested object:
|
|
@@ -169,11 +210,11 @@ uint dst.portal, uint dst.portal // duplicate path
|
|
|
169
210
|
uint dst, uint dst.portal // prefix/value collision
|
|
170
211
|
```
|
|
171
212
|
|
|
172
|
-
The same rule applies to
|
|
213
|
+
The same rule applies to field aliases:
|
|
173
214
|
|
|
174
215
|
```txt
|
|
175
|
-
|
|
176
|
-
maybe #account
|
|
216
|
+
{ uint target, uint resources, #bytes as calldata.payload }
|
|
217
|
+
maybe #account as recipient.account
|
|
177
218
|
```
|
|
178
219
|
|
|
179
220
|
## Field Types
|
|
@@ -226,8 +267,8 @@ the layout of an ID only apply to structured IDs.
|
|
|
226
267
|
|
|
227
268
|
## Identifiers
|
|
228
269
|
|
|
229
|
-
Block
|
|
230
|
-
one or more lower camelCase path segments separated by dots:
|
|
270
|
+
Block aliases use lower camelCase ASCII identifiers. Field names and aliases
|
|
271
|
+
use one or more lower camelCase path segments separated by dots:
|
|
231
272
|
|
|
232
273
|
```txt
|
|
233
274
|
[a-z][a-zA-Z0-9]*
|
|
@@ -246,48 +287,39 @@ asset.
|
|
|
246
287
|
```
|
|
247
288
|
|
|
248
289
|
Reserved words include `maybe`, `many`, `as`, all field type names, and the
|
|
249
|
-
reserved block
|
|
250
|
-
|
|
290
|
+
reserved block aliases `bytes` and `list`. For dotted paths, reserved words are
|
|
291
|
+
invalid in any path segment.
|
|
251
292
|
|
|
252
293
|
## Reserved Blocks
|
|
253
294
|
|
|
254
295
|
- `#bytes`: raw dynamic bytes, written without a body
|
|
255
|
-
- `#data`: generic/custom payload block
|
|
256
296
|
- `#list`: generic list wrapper emitted by `many`
|
|
257
297
|
|
|
258
|
-
|
|
298
|
+
Custom input shapes should define their own context-local block key and publish
|
|
299
|
+
that key with a `Schema` event:
|
|
259
300
|
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
If a schema string starts with a fixed field type, it is shorthand for one
|
|
266
|
-
top-level `#data` block:
|
|
267
|
-
|
|
268
|
-
```txt
|
|
269
|
-
uint foo, bytes32 tag
|
|
301
|
+
```solidity
|
|
302
|
+
bytes4 constant Input = Keys.local(1);
|
|
303
|
+
emit Schema(host, Input, "{ bytes32 asset, uint amount }", bytes32("payment"));
|
|
270
304
|
```
|
|
271
305
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
#data { uint foo, bytes32 tag }
|
|
276
|
-
```
|
|
306
|
+
The key can be a small literal, a selector, or any other `bytes4` value that is
|
|
307
|
+
unique in the context where it is used. The alias names the block; the schema
|
|
308
|
+
string describes only the payload body.
|
|
277
309
|
|
|
278
310
|
## Standard Blocks
|
|
279
311
|
|
|
280
312
|
Common protocol schemas live in `contracts/blocks/Schema.sol`:
|
|
281
313
|
|
|
282
314
|
```txt
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
315
|
+
amount { bytes32 asset, uint amount }
|
|
316
|
+
balance { bytes32 asset, uint amount }
|
|
317
|
+
custody { uint host, bytes32 asset, uint amount }
|
|
318
|
+
call { uint target, uint resources, #bytes as payload }
|
|
319
|
+
step { uint target, uint resources, #bytes as request }
|
|
320
|
+
context { bytes32 account, #bytes as state, #bytes as request }
|
|
321
|
+
recover { uint handler, uint resources, bytes32 key, #bytes as witness }
|
|
322
|
+
auth { uint cid, uint deadline, #bytes as proof }
|
|
291
323
|
```
|
|
292
324
|
|
|
293
|
-
`Keys.sol` contains the corresponding runtime keys.
|
|
325
|
+
`Keys.sol` contains the corresponding standard runtime keys.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {EventEmitter} from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
/// @title EndpointEvent
|
|
7
|
+
/// @notice Emitted during host deployment to publish a callable endpoint descriptor.
|
|
8
|
+
abstract contract EndpointEvent is EventEmitter {
|
|
9
|
+
string private constant ABI = "event Endpoint(uint indexed host, uint id, bytes32 descriptor)";
|
|
10
|
+
|
|
11
|
+
/// @param host Host node ID that exposes the endpoint.
|
|
12
|
+
/// @param id Endpoint node ID.
|
|
13
|
+
/// @param descriptor Packed endpoint lane metadata and flags.
|
|
14
|
+
event Endpoint(uint indexed host, uint id, bytes32 descriptor);
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
emit EventAbi(ABI);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {EventEmitter} from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
/// @title SchemaEvent
|
|
7
|
+
/// @notice Emitted during host deployment to publish a block key and payload schema.
|
|
8
|
+
/// Block keys are opaque `bytes4` tags. Standard protocol blocks use
|
|
9
|
+
/// keccak-derived keys by convention, but custom block keys only need to be
|
|
10
|
+
/// unique within the publishing host/schema context.
|
|
11
|
+
abstract contract SchemaEvent is EventEmitter {
|
|
12
|
+
string private constant ABI = "event Schema(uint indexed host, bytes4 key, string schema, bytes32 name)";
|
|
13
|
+
|
|
14
|
+
/// @param host Host node ID that publishes this block schema.
|
|
15
|
+
/// @param key Block type key being defined by `host`.
|
|
16
|
+
/// @param schema Schema DSL string describing the block payload body.
|
|
17
|
+
/// @param name Optional block alias used by endpoint descriptors and nested schemas.
|
|
18
|
+
event Schema(uint indexed host, bytes4 key, string schema, bytes32 name);
|
|
19
|
+
|
|
20
|
+
constructor() {
|
|
21
|
+
emit EventAbi(ABI);
|
|
22
|
+
}
|
|
23
|
+
}
|
package/guards/Base.sol
CHANGED
|
@@ -2,24 +2,33 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import {AccessControl} from "../core/Access.sol";
|
|
5
|
-
import {
|
|
6
|
-
import {LabeledEvent} from "../events/Labeled.sol";
|
|
5
|
+
import {EndpointBase} from "../core/Endpoint.sol";
|
|
7
6
|
import {Nodes} from "../utils/Nodes.sol";
|
|
7
|
+
import {Selectors} from "../utils/Selectors.sol";
|
|
8
8
|
|
|
9
9
|
/// @title GuardBase
|
|
10
10
|
/// @notice Abstract base for guardian-only direct host actions.
|
|
11
11
|
/// Guard actions are non-payable direct calls with no command context, state, or response.
|
|
12
|
-
abstract contract GuardBase is AccessControl,
|
|
12
|
+
abstract contract GuardBase is AccessControl, EndpointBase {
|
|
13
13
|
/// @dev Restrict execution to active guardian addresses.
|
|
14
14
|
modifier onlyGuardian() {
|
|
15
15
|
if (!isGuardian(msg.sender)) revert AccessDenied();
|
|
16
16
|
_;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
/// @notice
|
|
20
|
-
/// @param
|
|
21
|
-
/// @
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
/// @notice Publish guard metadata and a default label.
|
|
20
|
+
/// @param name Default human-readable guard label and selector name.
|
|
21
|
+
/// @param input Packed input lane plus optional group byte.
|
|
22
|
+
/// @param selector Guard ABI selector, or zero to derive it from `name`.
|
|
23
|
+
/// @return id Guard action node ID.
|
|
24
|
+
/// @return descriptor Packed endpoint lane metadata and flags.
|
|
25
|
+
function guard(
|
|
26
|
+
string memory name,
|
|
27
|
+
bytes9 input,
|
|
28
|
+
bytes4 selector
|
|
29
|
+
) internal returns (uint id, bytes32 descriptor) {
|
|
30
|
+
selector = selector == bytes4(0) ? Selectors.guard(name) : selector;
|
|
31
|
+
id = Nodes.toGuard(selector, address(this));
|
|
32
|
+
descriptor = endpoint(id, name, bytes9(0), input, bytes9(0), false, false);
|
|
24
33
|
}
|
|
25
34
|
}
|
package/guards/Revoke.sol
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import {GuardBase} from "./Base.sol";
|
|
5
|
-
import {Cursors, Cur,
|
|
5
|
+
import {Cursors, Cur, Keys} from "../Cursors.sol";
|
|
6
6
|
using Cursors for Cur;
|
|
7
7
|
|
|
8
8
|
/// @title Revoke
|
|
@@ -10,21 +10,19 @@ using Cursors for Cur;
|
|
|
10
10
|
/// Each NODE block in the request is deauthorized on the host.
|
|
11
11
|
/// Only callable by active guardian addresses.
|
|
12
12
|
abstract contract Revoke is GuardBase {
|
|
13
|
-
|
|
13
|
+
bytes32 private immutable descriptor;
|
|
14
14
|
|
|
15
15
|
constructor() {
|
|
16
|
-
|
|
17
|
-
emit Labeled(revokeId, bytes32(0), "revoke");
|
|
16
|
+
(, descriptor) = guard("revoke", Keys.Node, 0);
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
function revoke(bytes calldata request) external onlyGuardian {
|
|
21
|
-
(Cur memory input, ) =
|
|
20
|
+
(Cur memory input, ) = openInput(request, descriptor);
|
|
22
21
|
|
|
23
22
|
while (input.i < input.len) {
|
|
24
23
|
uint node = input.unpackNode();
|
|
25
24
|
setNode(node, false);
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
input.complete();
|
|
29
27
|
}
|
|
30
28
|
}
|
package/package.json
CHANGED
package/ports/AllowAssets.sol
CHANGED
|
@@ -3,7 +3,7 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import { PortBase } from "./Base.sol";
|
|
5
5
|
import { AllowAssetsHook } from "../commands/admin/AllowAssets.sol";
|
|
6
|
-
import { Cursors, Cur,
|
|
6
|
+
import { Cursors, Cur, Keys } from "../Cursors.sol";
|
|
7
7
|
|
|
8
8
|
using Cursors for Cur;
|
|
9
9
|
|
|
@@ -11,25 +11,22 @@ using Cursors for Cur;
|
|
|
11
11
|
/// @notice Port that permits a list of assets on behalf of a peer host.
|
|
12
12
|
/// Each ASSET block in the request calls `allowAsset`. Restricted to trusted peers.
|
|
13
13
|
abstract contract PortAllowAssets is PortBase, AllowAssetsHook {
|
|
14
|
-
|
|
14
|
+
bytes32 private immutable descriptor;
|
|
15
15
|
|
|
16
16
|
constructor() {
|
|
17
|
-
|
|
18
|
-
emit Labeled(portAllowAssetsId, bytes32(0), "portAllowAssets");
|
|
17
|
+
(, descriptor) = port("portAllowAssets", Keys.Asset, Keys.Empty, 0, false);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
/// @notice Execute the allow-assets peer call.
|
|
22
21
|
/// @param data ASSET block stream supplied by the trusted peer.
|
|
23
22
|
/// @return Empty response bytes.
|
|
24
23
|
function portAllowAssets(bytes calldata data) external onlyPeer returns (bytes memory) {
|
|
25
|
-
(Cur memory
|
|
24
|
+
(Cur memory input, ) = openInput(data, descriptor);
|
|
26
25
|
|
|
27
|
-
while (
|
|
28
|
-
bytes32 asset =
|
|
26
|
+
while (input.i < input.len) {
|
|
27
|
+
bytes32 asset = input.unpackAsset();
|
|
29
28
|
allowAsset(asset);
|
|
30
29
|
}
|
|
31
|
-
|
|
32
|
-
assets.complete();
|
|
33
30
|
return "";
|
|
34
31
|
}
|
|
35
32
|
}
|
package/ports/Allowance.sol
CHANGED
|
@@ -3,7 +3,7 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import {PortBase} from "./Base.sol";
|
|
5
5
|
import {AllowanceHook} from "../commands/admin/Allowance.sol";
|
|
6
|
-
import {Cursors, Cur,
|
|
6
|
+
import {Cursors, Cur, Keys} from "../Cursors.sol";
|
|
7
7
|
|
|
8
8
|
using Cursors for Cur;
|
|
9
9
|
|
|
@@ -12,26 +12,23 @@ using Cursors for Cur;
|
|
|
12
12
|
/// Each AMOUNT block in the request is scoped to the peer host and passed to the
|
|
13
13
|
/// shared allowance hook as a host-scoped allowance. Restricted to trusted peers.
|
|
14
14
|
abstract contract PortAllowance is PortBase, AllowanceHook {
|
|
15
|
-
|
|
15
|
+
bytes32 private immutable descriptor;
|
|
16
16
|
|
|
17
17
|
constructor() {
|
|
18
|
-
|
|
19
|
-
emit Labeled(portAllowanceId, bytes32(0), "portAllowance");
|
|
18
|
+
(, descriptor) = port("portAllowance", Keys.Amount, Keys.Empty, 0, false);
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
/// @notice Execute the allowance port call.
|
|
23
22
|
/// @param data AMOUNT block stream requested by the trusted peer.
|
|
24
23
|
/// @return Empty response bytes.
|
|
25
24
|
function portAllowance(bytes calldata data) external onlyPeer returns (bytes memory) {
|
|
26
|
-
(Cur memory
|
|
25
|
+
(Cur memory input, ) = openInput(data, descriptor);
|
|
27
26
|
uint peer = caller();
|
|
28
27
|
|
|
29
|
-
while (
|
|
30
|
-
(bytes32 asset, uint amount) =
|
|
28
|
+
while (input.i < input.len) {
|
|
29
|
+
(bytes32 asset, uint amount) = input.unpackAmount();
|
|
31
30
|
allowance(peer, asset, amount);
|
|
32
31
|
}
|
|
33
|
-
|
|
34
|
-
amounts.complete();
|
|
35
32
|
return "";
|
|
36
33
|
}
|
|
37
34
|
}
|
package/ports/Base.sol
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import { NodeCalls } from "../core/Calls.sol";
|
|
5
|
-
import {
|
|
6
|
-
import { LabeledEvent } from "../events/Labeled.sol";
|
|
5
|
+
import { EndpointBase } from "../core/Endpoint.sol";
|
|
7
6
|
import { Nodes } from "../utils/Nodes.sol";
|
|
7
|
+
import { Selectors } from "../utils/Selectors.sol";
|
|
8
8
|
|
|
9
9
|
/// @title PortBase
|
|
10
10
|
/// @notice Abstract base for peer-facing rootzero ports.
|
|
11
11
|
/// Ports handle inter-host operations between cooperating hosts.
|
|
12
12
|
/// Access is restricted to trusted peer callers via `onlyPeer`.
|
|
13
|
-
abstract contract PortBase is NodeCalls,
|
|
13
|
+
abstract contract PortBase is NodeCalls, EndpointBase {
|
|
14
14
|
/// @dev Thrown when the commander attempts to call a port entrypoint directly.
|
|
15
15
|
error CommanderNotAllowed();
|
|
16
16
|
|
|
@@ -21,10 +21,23 @@ abstract contract PortBase is NodeCalls, PortEvent, LabeledEvent {
|
|
|
21
21
|
_;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
/// @notice
|
|
25
|
-
/// @param
|
|
26
|
-
/// @
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
/// @notice Publish port metadata and a default label.
|
|
25
|
+
/// @param name Default human-readable port label and selector name.
|
|
26
|
+
/// @param input Packed input lane plus optional group byte.
|
|
27
|
+
/// @param output Packed output lane plus optional group byte.
|
|
28
|
+
/// @param selector Port ABI selector, or zero to derive it from `name`.
|
|
29
|
+
/// @param funded Whether the port accepts nonzero native value.
|
|
30
|
+
/// @return id Port node ID.
|
|
31
|
+
/// @return descriptor Packed endpoint lane metadata and flags.
|
|
32
|
+
function port(
|
|
33
|
+
string memory name,
|
|
34
|
+
bytes9 input,
|
|
35
|
+
bytes9 output,
|
|
36
|
+
bytes4 selector,
|
|
37
|
+
bool funded
|
|
38
|
+
) internal returns (uint id, bytes32 descriptor) {
|
|
39
|
+
selector = selector == bytes4(0) ? Selectors.port(name) : selector;
|
|
40
|
+
id = Nodes.toPort(selector, address(this));
|
|
41
|
+
descriptor = endpoint(id, name, bytes9(0), input, output, funded, false);
|
|
29
42
|
}
|
|
30
43
|
}
|
package/ports/Credit.sol
CHANGED
|
@@ -3,7 +3,7 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import { PortBase } from "./Base.sol";
|
|
5
5
|
import { CreditAccountHook } from "../commands/Credit.sol";
|
|
6
|
-
import { Cursors, Cur,
|
|
6
|
+
import { Cursors, Cur, Keys } from "../Cursors.sol";
|
|
7
7
|
|
|
8
8
|
using Cursors for Cur;
|
|
9
9
|
|
|
@@ -11,25 +11,22 @@ using Cursors for Cur;
|
|
|
11
11
|
/// @notice Port that lets a trusted peer credit supplied accounts directly.
|
|
12
12
|
/// Each ACCOUNT_AMOUNT block calls `creditAccount` for its account.
|
|
13
13
|
abstract contract PortCreditAccount is PortBase, CreditAccountHook {
|
|
14
|
-
|
|
14
|
+
bytes32 private immutable descriptor;
|
|
15
15
|
|
|
16
16
|
constructor() {
|
|
17
|
-
|
|
18
|
-
emit Labeled(portCreditAccountId, bytes32(0), "portCreditAccount");
|
|
17
|
+
(, descriptor) = port("portCreditAccount", Keys.AccountAmount, Keys.Empty, 0, false);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
/// @notice Execute the port-credit call.
|
|
22
21
|
/// @param data ACCOUNT_AMOUNT block stream supplied by the trusted peer.
|
|
23
22
|
/// @return Empty response bytes.
|
|
24
23
|
function portCreditAccount(bytes calldata data) external onlyPeer returns (bytes memory) {
|
|
25
|
-
(Cur memory
|
|
24
|
+
(Cur memory input, ) = openInput(data, descriptor);
|
|
26
25
|
|
|
27
|
-
while (
|
|
28
|
-
(bytes32 account, bytes32 asset, uint amount) =
|
|
26
|
+
while (input.i < input.len) {
|
|
27
|
+
(bytes32 account, bytes32 asset, uint amount) = input.unpackAccountAmount();
|
|
29
28
|
creditAccount(account, asset, amount);
|
|
30
29
|
}
|
|
31
|
-
|
|
32
|
-
amounts.complete();
|
|
33
30
|
return "";
|
|
34
31
|
}
|
|
35
32
|
}
|