@rootzero/contracts 0.7.2 → 0.9.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/Commands.sol +15 -20
- package/Core.sol +3 -4
- package/Cursors.sol +3 -2
- package/Events.sol +1 -1
- package/Queries.sol +3 -3
- package/README.md +18 -19
- package/Utils.sol +3 -3
- package/blocks/Cursors.sol +937 -551
- package/blocks/Keys.sol +60 -34
- package/blocks/Schema.sol +112 -122
- package/blocks/Writers.sol +476 -301
- package/commands/Base.sol +32 -22
- package/commands/Burn.sol +14 -12
- package/commands/Credit.sol +16 -15
- package/commands/Debit.sol +14 -12
- package/commands/Deposit.sol +30 -37
- package/commands/Pipe.sol +14 -20
- package/commands/Provision.sol +19 -49
- package/commands/Transfer.sol +9 -18
- package/commands/Withdraw.sol +15 -14
- package/commands/admin/AllowAssets.sol +3 -3
- package/commands/admin/Allowance.sol +43 -0
- package/commands/admin/Authorize.sol +4 -4
- package/commands/admin/DenyAssets.sol +3 -3
- package/commands/admin/Destroy.sol +10 -8
- package/commands/admin/Execute.sol +38 -0
- package/commands/admin/Init.sol +10 -8
- package/commands/admin/Relocate.sol +5 -5
- package/commands/admin/Unauthorize.sol +4 -4
- package/core/Access.sol +38 -34
- package/core/Balances.sol +17 -18
- package/core/{Operation.sol → Calls.sol} +5 -8
- package/core/{CursorBase.sol → Context.sol} +11 -5
- package/core/Host.sol +11 -10
- package/core/Types.sol +86 -0
- package/docs/GETTING_STARTED.md +37 -29
- package/events/Asset.sol +1 -1
- package/events/Command.sol +10 -10
- package/events/Deposit.sol +3 -4
- package/events/Listing.sol +1 -1
- package/events/Peer.sol +3 -3
- package/events/Position.sol +21 -0
- package/events/Query.sol +3 -3
- package/events/Withdraw.sol +2 -3
- package/package.json +1 -1
- package/peer/AllowAssets.sol +1 -1
- package/peer/Allowance.sol +36 -0
- package/peer/AssetPull.sol +33 -31
- package/peer/Base.sol +8 -4
- package/peer/DenyAssets.sol +1 -1
- package/peer/Settle.sol +3 -4
- package/queries/Assets.sol +18 -16
- package/queries/Balances.sol +21 -19
- package/queries/Base.sol +2 -3
- package/queries/Positions.sol +32 -24
- package/utils/Accounts.sol +14 -13
- package/utils/Assets.sol +137 -62
- package/utils/Ids.sol +9 -9
- package/utils/Layout.sol +5 -3
- package/utils/Utils.sol +10 -0
- package/commands/Create.sol +0 -42
- package/commands/Remove.sol +0 -42
- package/commands/Settle.sol +0 -38
- package/commands/Stake.sol +0 -47
- package/commands/Supply.sol +0 -41
- package/commands/admin/Allocate.sol +0 -41
- package/core/HostBound.sol +0 -14
- package/events/Erc721.sol +0 -20
- package/peer/Pull.sol +0 -39
- package/peer/Push.sol +0 -45
- package/utils/State.sol +0 -22
package/core/Types.sol
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
/// @notice Asset and amount pair used across ledger, command, and block flows.
|
|
5
|
+
struct AssetAmount {
|
|
6
|
+
/// @dev Asset identifier.
|
|
7
|
+
bytes32 asset;
|
|
8
|
+
/// @dev Asset metadata slot.
|
|
9
|
+
bytes32 meta;
|
|
10
|
+
/// @dev Token amount in the asset's native units.
|
|
11
|
+
uint amount;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/// @notice Account-scoped asset shape.
|
|
15
|
+
struct AccountAsset {
|
|
16
|
+
/// @dev Account identifier.
|
|
17
|
+
bytes32 account;
|
|
18
|
+
/// @dev Asset identifier.
|
|
19
|
+
bytes32 asset;
|
|
20
|
+
/// @dev Asset metadata slot.
|
|
21
|
+
bytes32 meta;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// @notice Account-scoped amount shape used by payout blocks and query responses.
|
|
25
|
+
struct AccountAmount {
|
|
26
|
+
/// @dev Account identifier.
|
|
27
|
+
bytes32 account;
|
|
28
|
+
/// @dev Asset identifier.
|
|
29
|
+
bytes32 asset;
|
|
30
|
+
/// @dev Asset metadata slot.
|
|
31
|
+
bytes32 meta;
|
|
32
|
+
/// @dev Token amount in the asset's native units.
|
|
33
|
+
uint amount;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// @notice Host-scoped asset and amount shape.
|
|
37
|
+
struct HostAmount {
|
|
38
|
+
/// @dev Host node identifier.
|
|
39
|
+
uint host;
|
|
40
|
+
/// @dev Asset identifier.
|
|
41
|
+
bytes32 asset;
|
|
42
|
+
/// @dev Asset metadata slot.
|
|
43
|
+
bytes32 meta;
|
|
44
|
+
/// @dev Token amount in the asset's native units.
|
|
45
|
+
uint amount;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// @notice Host-scoped account asset shape.
|
|
49
|
+
struct HostAccountAsset {
|
|
50
|
+
/// @dev Host node identifier.
|
|
51
|
+
uint host;
|
|
52
|
+
/// @dev Account identifier.
|
|
53
|
+
bytes32 account;
|
|
54
|
+
/// @dev Asset identifier.
|
|
55
|
+
bytes32 asset;
|
|
56
|
+
/// @dev Asset metadata slot.
|
|
57
|
+
bytes32 meta;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// @notice Host-scoped account amount shape.
|
|
61
|
+
struct HostAccountAmount {
|
|
62
|
+
/// @dev Host node identifier.
|
|
63
|
+
uint host;
|
|
64
|
+
/// @dev Account identifier.
|
|
65
|
+
bytes32 account;
|
|
66
|
+
/// @dev Asset identifier.
|
|
67
|
+
bytes32 asset;
|
|
68
|
+
/// @dev Asset metadata slot.
|
|
69
|
+
bytes32 meta;
|
|
70
|
+
/// @dev Token amount in the asset's native units.
|
|
71
|
+
uint amount;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// @notice Transfer payload used by transaction blocks and peer settlement.
|
|
75
|
+
struct Tx {
|
|
76
|
+
/// @dev Sender account identifier.
|
|
77
|
+
bytes32 from;
|
|
78
|
+
/// @dev Destination account identifier.
|
|
79
|
+
bytes32 to;
|
|
80
|
+
/// @dev Asset identifier.
|
|
81
|
+
bytes32 asset;
|
|
82
|
+
/// @dev Asset metadata slot.
|
|
83
|
+
bytes32 meta;
|
|
84
|
+
/// @dev Transfer amount in the asset's native units.
|
|
85
|
+
uint amount;
|
|
86
|
+
}
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -14,7 +14,6 @@ rootzero moves data through a small command context:
|
|
|
14
14
|
|
|
15
15
|
```solidity
|
|
16
16
|
struct CommandContext {
|
|
17
|
-
uint target;
|
|
18
17
|
bytes32 account;
|
|
19
18
|
bytes state;
|
|
20
19
|
bytes request;
|
|
@@ -25,8 +24,7 @@ In practice:
|
|
|
25
24
|
|
|
26
25
|
- `account` is the user account the command is acting for.
|
|
27
26
|
- `request` is the new input for this command.
|
|
28
|
-
- `state` is
|
|
29
|
-
- `target` is the command id you expect to receive, or `0`.
|
|
27
|
+
- `state` is live pipeline state produced by an earlier command.
|
|
30
28
|
|
|
31
29
|
Most built-in commands follow a simple pattern:
|
|
32
30
|
|
|
@@ -86,7 +84,7 @@ contract ExampleHost is Host, DebitAccount {
|
|
|
86
84
|
bytes32 meta,
|
|
87
85
|
uint amount
|
|
88
86
|
) internal override {
|
|
89
|
-
bytes32 key = Assets.
|
|
87
|
+
bytes32 key = Assets.slot(asset, meta);
|
|
90
88
|
balances[account][key] -= amount;
|
|
91
89
|
}
|
|
92
90
|
}
|
|
@@ -105,22 +103,21 @@ The built-in commands are easiest to use when you know which blocks they expect.
|
|
|
105
103
|
### Commands That Read `request`
|
|
106
104
|
|
|
107
105
|
- `deposit`: reads `AMOUNT` blocks, returns `BALANCE`
|
|
108
|
-
- `transfer`: reads `
|
|
106
|
+
- `transfer`: reads `PAYOUT` blocks
|
|
109
107
|
- `debitAccount`: reads `AMOUNT`, returns `BALANCE`
|
|
110
|
-
- `provision`: reads `
|
|
111
|
-
- `
|
|
108
|
+
- `provision`: reads `ALLOCATION`, returns `CUSTODY` state
|
|
109
|
+
- `pipePayable`: reads `STEP` blocks and runs them in order
|
|
112
110
|
|
|
113
111
|
### Commands That Read `state`
|
|
114
112
|
|
|
115
|
-
- `withdraw`: reads `BALANCE`, optionally reads `
|
|
116
|
-
- `creditAccount`: reads `BALANCE`, optionally reads `
|
|
117
|
-
- `settle`: reads `TX`
|
|
118
|
-
- `provisionFromBalance`: reads `BALANCE` from `state` and `NODE` from `request`
|
|
113
|
+
- `withdraw`: reads `BALANCE`, optionally reads `ACCOUNT` from `request`
|
|
114
|
+
- `creditAccount`: reads `BALANCE`, optionally reads `ACCOUNT` from `request`
|
|
119
115
|
|
|
120
116
|
This is the main pattern to keep in mind:
|
|
121
117
|
|
|
122
118
|
- use `request` for the command's direct input
|
|
123
|
-
- use `state`
|
|
119
|
+
- use `state` for live value threaded through a pipeline, currently `BALANCE` and `CUSTODY`
|
|
120
|
+
- use peer commands such as `peerSettle` for settlement messages such as `TRANSACTION`
|
|
124
121
|
|
|
125
122
|
## Step 4: Send A Simple Request
|
|
126
123
|
|
|
@@ -137,7 +134,6 @@ const meta = ethers.ZeroHash;
|
|
|
137
134
|
const amount = 100n;
|
|
138
135
|
|
|
139
136
|
const ctx = {
|
|
140
|
-
target: 0n,
|
|
141
137
|
account: "0x...", // 32-byte rootzero account id
|
|
142
138
|
state: "0x",
|
|
143
139
|
request: encodeAmountBlock(asset, meta, amount),
|
|
@@ -160,11 +156,10 @@ When the built-in modules are not enough, add your own command entrypoint.
|
|
|
160
156
|
// SPDX-License-Identifier: MIT
|
|
161
157
|
pragma solidity ^0.8.33;
|
|
162
158
|
|
|
163
|
-
import {
|
|
164
|
-
import {
|
|
165
|
-
import {Cursors, Cursor, Schemas} from "@rootzero/contracts/Cursors.sol";
|
|
159
|
+
import {CommandBase, CommandContext, Keys} from "@rootzero/contracts/Commands.sol";
|
|
160
|
+
import {Cursors, Cur, Schemas} from "@rootzero/contracts/Cursors.sol";
|
|
166
161
|
|
|
167
|
-
using Cursors for
|
|
162
|
+
using Cursors for Cur;
|
|
168
163
|
|
|
169
164
|
string constant NAME = "myCommand";
|
|
170
165
|
string constant ROUTE = "route(uint foo, uint bar)";
|
|
@@ -174,16 +169,20 @@ abstract contract MyCommand is CommandBase {
|
|
|
174
169
|
uint internal immutable myCommandId = commandId(NAME);
|
|
175
170
|
|
|
176
171
|
constructor() {
|
|
177
|
-
emit Command(host, NAME, INPUT,
|
|
172
|
+
emit Command(host, myCommandId, NAME, INPUT, Keys.Empty, Keys.Balance, false);
|
|
178
173
|
}
|
|
179
174
|
|
|
180
175
|
function myCommand(
|
|
181
176
|
CommandContext calldata c
|
|
182
|
-
) external
|
|
183
|
-
|
|
184
|
-
uint
|
|
177
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
178
|
+
Cur memory input = cursor(c.request);
|
|
179
|
+
uint next = input.bundle();
|
|
180
|
+
|
|
181
|
+
bytes calldata route = input.unpackRaw(Keys.Route);
|
|
185
182
|
(bytes32 asset, bytes32 meta, uint amount) = input.unpackAmount();
|
|
186
|
-
|
|
183
|
+
input.ensure(next);
|
|
184
|
+
|
|
185
|
+
route;
|
|
187
186
|
return Cursors.toBalanceBlock(asset, meta, amount);
|
|
188
187
|
}
|
|
189
188
|
}
|
|
@@ -193,7 +192,7 @@ There are three important ideas here:
|
|
|
193
192
|
|
|
194
193
|
- every custom command gets a deterministic command id
|
|
195
194
|
- you announce it with the `Command` event
|
|
196
|
-
- `onlyCommand(
|
|
195
|
+
- `onlyCommand(c.account)` ensures the caller is trusted and the calldata account matches `c.account`
|
|
197
196
|
|
|
198
197
|
## Step 6: Read Input With A Cursor
|
|
199
198
|
|
|
@@ -205,7 +204,7 @@ If your request contains a bundled input like:
|
|
|
205
204
|
|
|
206
205
|
your command can:
|
|
207
206
|
|
|
208
|
-
- open it with `Cursors.
|
|
207
|
+
- open it with `cursor(c.request)` or `Cursors.open(...)`
|
|
209
208
|
- consume the route first
|
|
210
209
|
- then consume the amount
|
|
211
210
|
- keep parsing in bundle/member order without indexing helpers
|
|
@@ -232,18 +231,27 @@ function buildBalances() internal pure returns (bytes memory) {
|
|
|
232
231
|
Writer memory writer = Writers.allocBalances(2);
|
|
233
232
|
writer.appendBalance(bytes32(uint256(1)), bytes32(0), 50);
|
|
234
233
|
writer.appendBalance(bytes32(uint256(2)), bytes32(0), 75);
|
|
235
|
-
return writer.
|
|
234
|
+
return writer.finish();
|
|
236
235
|
}
|
|
237
236
|
```
|
|
238
237
|
|
|
239
238
|
Use this when your command needs to return:
|
|
240
239
|
|
|
241
240
|
- balances
|
|
242
|
-
-
|
|
243
|
-
- transactions
|
|
241
|
+
- custody state
|
|
244
242
|
|
|
245
243
|
If you are only consuming built-in commands, you often will not need to touch writers directly.
|
|
246
244
|
|
|
245
|
+
## Query Forms
|
|
246
|
+
|
|
247
|
+
Queries use reusable `Forms` as their input and output schema vocabulary. For example, `getBalances` accepts `Forms.AccountAsset` blocks and returns `Forms.AccountAmount` blocks:
|
|
248
|
+
|
|
249
|
+
```solidity
|
|
250
|
+
emit Query(host, NAME, Forms.AccountAsset, Forms.AccountAmount, getBalancesId);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
This keeps query payloads structural: the query name describes what is being asked, while the form describes the fields carried by each block.
|
|
254
|
+
|
|
247
255
|
## A Tiny End-To-End Example
|
|
248
256
|
|
|
249
257
|
Imagine you want a host that keeps internal balances and lets rootzero debit them.
|
|
@@ -251,7 +259,7 @@ Imagine you want a host that keeps internal balances and lets rootzero debit the
|
|
|
251
259
|
1. Deploy a host that inherits `Host` and `DebitAccount`.
|
|
252
260
|
2. Store balances in your own mapping.
|
|
253
261
|
3. Implement `debitAccount(account, asset, meta, amount)`.
|
|
254
|
-
4. Send `
|
|
262
|
+
4. Send `debitAccount` a request containing one or more `AMOUNT` blocks.
|
|
255
263
|
5. rootzero returns `BALANCE` blocks representing the debited amounts.
|
|
256
264
|
|
|
257
265
|
That is already a valid and useful integration.
|
|
@@ -272,7 +280,7 @@ If you want to learn by example, these are the best files to read next:
|
|
|
272
280
|
|
|
273
281
|
- Passing data in `state` when the command expects it in `request`
|
|
274
282
|
- Forgetting to emit a `Command` event for a custom command
|
|
275
|
-
- Using
|
|
283
|
+
- Using an admin account with user-only command flows such as `pipePayable`
|
|
276
284
|
- Trying to parse raw bytes manually when a built-in reader already exists
|
|
277
285
|
- Starting with a custom command when a built-in module already matches the job
|
|
278
286
|
|
package/events/Asset.sol
CHANGED
|
@@ -8,7 +8,7 @@ string constant ABI = "event Asset(uint indexed host, bytes32 name, uint32 prefi
|
|
|
8
8
|
/// @notice Emitted when an asset is registered or updated on a host.
|
|
9
9
|
abstract contract AssetEvent is EventEmitter {
|
|
10
10
|
/// @param host Host node ID that registered the asset.
|
|
11
|
-
/// @param name Asset
|
|
11
|
+
/// @param name Asset name encoded as a bytes32 string.
|
|
12
12
|
/// @param prefix 4-byte type prefix of the asset ID.
|
|
13
13
|
event Asset(uint indexed host, bytes32 name, uint32 prefix);
|
|
14
14
|
|
package/events/Command.sol
CHANGED
|
@@ -4,24 +4,24 @@ pragma solidity ^0.8.33;
|
|
|
4
4
|
import { EventEmitter } from "./Emitter.sol";
|
|
5
5
|
|
|
6
6
|
string constant ABI =
|
|
7
|
-
"event Command(uint indexed host,
|
|
7
|
+
"event Command(uint indexed host, uint id, string name, string request, bytes4 state, bytes4 output, bool acceptsValue)";
|
|
8
8
|
|
|
9
|
-
/// @notice Emitted once per command during host deployment to publish its schema and state
|
|
9
|
+
/// @notice Emitted once per command during host deployment to publish its request schema and state keys.
|
|
10
10
|
abstract contract CommandEvent is EventEmitter {
|
|
11
11
|
/// @param host Host node ID that owns this command.
|
|
12
|
+
/// @param id Command node ID.
|
|
12
13
|
/// @param name Human-readable command name.
|
|
13
|
-
/// @param
|
|
14
|
-
/// @param
|
|
15
|
-
/// @param
|
|
16
|
-
/// @param stateOut State type discriminant for the output state.
|
|
14
|
+
/// @param request Schema DSL string describing the request shape.
|
|
15
|
+
/// @param state Block key expected for input state, or `Keys.Empty`.
|
|
16
|
+
/// @param output Block key produced for output state, or `Keys.Empty`.
|
|
17
17
|
/// @param acceptsValue Whether the command entrypoint accepts nonzero `msg.value`.
|
|
18
18
|
event Command(
|
|
19
19
|
uint indexed host,
|
|
20
|
+
uint id,
|
|
20
21
|
string name,
|
|
21
|
-
string
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
uint8 stateOut,
|
|
22
|
+
string request,
|
|
23
|
+
bytes4 state,
|
|
24
|
+
bytes4 output,
|
|
25
25
|
bool acceptsValue
|
|
26
26
|
);
|
|
27
27
|
|
package/events/Deposit.sol
CHANGED
|
@@ -3,16 +3,15 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import { EventEmitter } from "./Emitter.sol";
|
|
5
5
|
|
|
6
|
-
string constant ABI = "event Deposit(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount
|
|
6
|
+
string constant ABI = "event Deposit(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount)";
|
|
7
7
|
|
|
8
8
|
/// @notice Emitted when assets are deposited into an account.
|
|
9
9
|
abstract contract DepositEvent is EventEmitter {
|
|
10
|
-
/// @param account
|
|
10
|
+
/// @param account Destination account identifier.
|
|
11
11
|
/// @param asset Asset identifier.
|
|
12
12
|
/// @param meta Asset metadata slot.
|
|
13
13
|
/// @param amount Amount deposited.
|
|
14
|
-
|
|
15
|
-
event Deposit(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint cid);
|
|
14
|
+
event Deposit(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount);
|
|
16
15
|
|
|
17
16
|
constructor() {
|
|
18
17
|
emit EventAbi(ABI);
|
package/events/Listing.sol
CHANGED
|
@@ -11,7 +11,7 @@ abstract contract ListingEvent is EventEmitter {
|
|
|
11
11
|
/// @param asset Asset identifier.
|
|
12
12
|
/// @param meta Asset metadata slot.
|
|
13
13
|
/// @param active True if the listing is currently active.
|
|
14
|
-
/// @param created True if
|
|
14
|
+
/// @param created True if the asset was created as part of this listing.
|
|
15
15
|
event Listing(uint indexed host, bytes32 asset, bytes32 meta, bool active, bool created);
|
|
16
16
|
|
|
17
17
|
constructor() {
|
package/events/Peer.sol
CHANGED
|
@@ -4,16 +4,16 @@ pragma solidity ^0.8.33;
|
|
|
4
4
|
import { EventEmitter } from "./Emitter.sol";
|
|
5
5
|
|
|
6
6
|
string constant ABI =
|
|
7
|
-
"event Peer(uint indexed host, string name, string schema,
|
|
7
|
+
"event Peer(uint indexed host, uint id, string name, string schema, bool acceptsValue)";
|
|
8
8
|
|
|
9
9
|
/// @notice Emitted once per peer during host deployment to publish its schema.
|
|
10
10
|
abstract contract PeerEvent is EventEmitter {
|
|
11
11
|
/// @param host Host node ID that owns this peer.
|
|
12
|
+
/// @param id Peer node ID.
|
|
12
13
|
/// @param name Human-readable peer name.
|
|
13
14
|
/// @param schema Schema DSL string describing the peer request shape.
|
|
14
|
-
/// @param pid Peer node ID.
|
|
15
15
|
/// @param acceptsValue Whether the peer entrypoint accepts nonzero `msg.value`.
|
|
16
|
-
event Peer(uint indexed host, string name, string schema,
|
|
16
|
+
event Peer(uint indexed host, uint id, string name, string schema, bool acceptsValue);
|
|
17
17
|
|
|
18
18
|
constructor() {
|
|
19
19
|
emit EventAbi(ABI);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {EventEmitter} from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
string constant ABI = "event AssetPosition(bytes32 indexed account, bytes32 asset, bytes32 meta, uint value, uint queryId)";
|
|
7
|
+
|
|
8
|
+
/// @notice Emitted when the reported value of an asset-backed position changes or is observed.
|
|
9
|
+
/// A value of 0 should be interpreted as a closed position.
|
|
10
|
+
abstract contract AssetPositionEvent is EventEmitter {
|
|
11
|
+
/// @param account Account identifier that owns or is associated with the position.
|
|
12
|
+
/// @param asset Asset identifier for the asset class.
|
|
13
|
+
/// @param meta Asset metadata slot carrying the position context.
|
|
14
|
+
/// @param value Context-specific position value; 0 indicates a closed position.
|
|
15
|
+
/// @param queryId Query ID associated with the position lookup or reporting context.
|
|
16
|
+
event AssetPosition(bytes32 indexed account, bytes32 asset, bytes32 meta, uint value, uint queryId);
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
emit EventAbi(ABI);
|
|
20
|
+
}
|
|
21
|
+
}
|
package/events/Query.sol
CHANGED
|
@@ -3,16 +3,16 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import {EventEmitter} from "./Emitter.sol";
|
|
5
5
|
|
|
6
|
-
string constant ABI = "event Query(uint indexed host, string name, string input, string output
|
|
6
|
+
string constant ABI = "event Query(uint indexed host, uint id, string name, string input, string output)";
|
|
7
7
|
|
|
8
8
|
/// @notice Emitted once per query during host deployment to publish its request and response schemas.
|
|
9
9
|
abstract contract QueryEvent is EventEmitter {
|
|
10
10
|
/// @param host Host node ID that owns this query.
|
|
11
|
+
/// @param id Query node ID.
|
|
11
12
|
/// @param name Human-readable query name.
|
|
12
13
|
/// @param input Schema DSL string describing the query request shape.
|
|
13
14
|
/// @param output Schema DSL string describing the query response shape.
|
|
14
|
-
|
|
15
|
-
event Query(uint indexed host, string name, string input, string output, uint qid);
|
|
15
|
+
event Query(uint indexed host, uint id, string name, string input, string output);
|
|
16
16
|
|
|
17
17
|
constructor() {
|
|
18
18
|
emit EventAbi(ABI);
|
package/events/Withdraw.sol
CHANGED
|
@@ -3,7 +3,7 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import { EventEmitter } from "./Emitter.sol";
|
|
5
5
|
|
|
6
|
-
string constant ABI = "event Withdrawal(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount
|
|
6
|
+
string constant ABI = "event Withdrawal(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount)";
|
|
7
7
|
|
|
8
8
|
/// @notice Emitted when assets are withdrawn from an account.
|
|
9
9
|
abstract contract WithdrawalEvent is EventEmitter {
|
|
@@ -11,8 +11,7 @@ abstract contract WithdrawalEvent is EventEmitter {
|
|
|
11
11
|
/// @param asset Asset identifier.
|
|
12
12
|
/// @param meta Asset metadata slot.
|
|
13
13
|
/// @param amount Amount withdrawn.
|
|
14
|
-
|
|
15
|
-
event Withdrawal(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint cid);
|
|
14
|
+
event Withdrawal(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount);
|
|
16
15
|
|
|
17
16
|
constructor() {
|
|
18
17
|
emit EventAbi(ABI);
|
package/package.json
CHANGED
package/peer/AllowAssets.sol
CHANGED
|
@@ -16,7 +16,7 @@ abstract contract PeerAllowAssets is PeerBase, AllowAssetsHook {
|
|
|
16
16
|
uint internal immutable peerAllowAssetsId = peerId(NAME);
|
|
17
17
|
|
|
18
18
|
constructor() {
|
|
19
|
-
emit Peer(host, NAME, Schemas.Asset,
|
|
19
|
+
emit Peer(host, peerAllowAssetsId, NAME, Schemas.Asset, false);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/// @notice Execute the allow-assets peer call.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {PeerBase} from "./Base.sol";
|
|
5
|
+
import {AllowanceHook} from "../commands/admin/Allowance.sol";
|
|
6
|
+
import {Cursors, Cur, Schemas} from "../Cursors.sol";
|
|
7
|
+
|
|
8
|
+
using Cursors for Cur;
|
|
9
|
+
|
|
10
|
+
string constant NAME = "peerAllowance";
|
|
11
|
+
|
|
12
|
+
/// @title PeerAllowance
|
|
13
|
+
/// @notice Peer that lets a trusted remote host request or refresh its own allowance.
|
|
14
|
+
/// Each AMOUNT block in the request is scoped to `caller()` and passed to the shared
|
|
15
|
+
/// allowance hook as a host-scoped allowance. Restricted to trusted peers.
|
|
16
|
+
abstract contract PeerAllowance is PeerBase, AllowanceHook {
|
|
17
|
+
uint internal immutable peerAllowanceId = peerId(NAME);
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
emit Peer(host, peerAllowanceId, NAME, Schemas.Amount, false);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// @notice Execute the allowance peer call.
|
|
24
|
+
function peerAllowance(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
25
|
+
(Cur memory amounts, , ) = cursor(request, 1);
|
|
26
|
+
uint peer = caller();
|
|
27
|
+
|
|
28
|
+
while (amounts.i < amounts.bound) {
|
|
29
|
+
(bytes32 asset, bytes32 meta, uint amount) = amounts.unpackAmount();
|
|
30
|
+
allowance(peer, asset, meta, amount);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
amounts.complete();
|
|
34
|
+
return "";
|
|
35
|
+
}
|
|
36
|
+
}
|
package/peer/AssetPull.sol
CHANGED
|
@@ -8,35 +8,37 @@ string constant NAME = "peerAssetPull";
|
|
|
8
8
|
|
|
9
9
|
using Cursors for Cur;
|
|
10
10
|
|
|
11
|
+
abstract contract PeerAssetPullHook {
|
|
12
|
+
/// @notice Override to process one incoming amount-based asset pull request from a remote host.
|
|
13
|
+
/// @param peer Host node ID derived from the caller address.
|
|
14
|
+
/// @param asset Requested asset identifier.
|
|
15
|
+
/// @param meta Requested asset metadata slot.
|
|
16
|
+
/// @param amount Requested amount in the asset's native units.
|
|
17
|
+
function peerAssetPull(uint peer, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
18
|
+
}
|
|
19
|
+
|
|
11
20
|
/// @title PeerAssetPull
|
|
12
|
-
/// @notice Peer that pulls requested asset amounts from a remote host into this one.
|
|
13
|
-
/// Each AMOUNT block in the request calls `peerAssetPull(peer, asset, meta, amount)`, where `peer`
|
|
14
|
-
/// is derived from `msg.sender`. Restricted to trusted peers.
|
|
15
|
-
abstract contract PeerAssetPull is PeerBase {
|
|
16
|
-
uint internal immutable peerAssetPullId = peerId(NAME);
|
|
17
|
-
|
|
18
|
-
constructor() {
|
|
19
|
-
emit Peer(host, NAME, Schemas.Amount,
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/// @notice
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
peerAssetPull(peer, asset, meta, amount);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
assets.complete();
|
|
40
|
-
return "";
|
|
41
|
-
}
|
|
42
|
-
}
|
|
21
|
+
/// @notice Peer that pulls requested asset amounts from a remote host into this one.
|
|
22
|
+
/// Each AMOUNT block in the request calls `peerAssetPull(peer, asset, meta, amount)`, where `peer`
|
|
23
|
+
/// is derived from `msg.sender`. Restricted to trusted peers.
|
|
24
|
+
abstract contract PeerAssetPull is PeerBase, PeerAssetPullHook {
|
|
25
|
+
uint internal immutable peerAssetPullId = peerId(NAME);
|
|
26
|
+
|
|
27
|
+
constructor() {
|
|
28
|
+
emit Peer(host, peerAssetPullId, NAME, Schemas.Amount, false);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// @notice Execute the asset-pull peer call.
|
|
32
|
+
function peerAssetPull(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
33
|
+
(Cur memory assets, , ) = cursor(request, 1);
|
|
34
|
+
uint peer = caller();
|
|
35
|
+
|
|
36
|
+
while (assets.i < assets.bound) {
|
|
37
|
+
(bytes32 asset, bytes32 meta, uint amount) = assets.unpackAmount();
|
|
38
|
+
peerAssetPull(peer, asset, meta, amount);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
assets.complete();
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
}
|
package/peer/Base.sol
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { NodeCalls } from "../core/Calls.sol";
|
|
5
5
|
import { PeerEvent } from "../events/Peer.sol";
|
|
6
6
|
import { Ids, Selectors } from "../utils/Ids.sol";
|
|
7
7
|
|
|
@@ -18,11 +18,15 @@ function encodePeerCall(uint target, bytes calldata request) pure returns (bytes
|
|
|
18
18
|
|
|
19
19
|
/// @title PeerBase
|
|
20
20
|
/// @notice Abstract base for all rootzero peer contracts.
|
|
21
|
-
/// Peers handle inter-host
|
|
21
|
+
/// Peers handle inter-host operations and asset allow/deny management
|
|
22
22
|
/// between cooperating hosts. Access is restricted to trusted callers via `onlyPeer`.
|
|
23
|
-
abstract contract PeerBase is
|
|
24
|
-
/// @dev
|
|
23
|
+
abstract contract PeerBase is NodeCalls, PeerEvent {
|
|
24
|
+
/// @dev Thrown when the commander attempts to call a peer entrypoint directly.
|
|
25
|
+
error CommanderNotAllowed();
|
|
26
|
+
|
|
27
|
+
/// @dev Restrict execution to trusted callers, excluding the commander.
|
|
25
28
|
modifier onlyPeer() {
|
|
29
|
+
if (msg.sender == commander) revert CommanderNotAllowed();
|
|
26
30
|
enforceCaller(msg.sender);
|
|
27
31
|
_;
|
|
28
32
|
}
|
package/peer/DenyAssets.sol
CHANGED
|
@@ -16,7 +16,7 @@ abstract contract PeerDenyAssets is PeerBase, DenyAssetsHook {
|
|
|
16
16
|
uint internal immutable peerDenyAssetsId = peerId(NAME);
|
|
17
17
|
|
|
18
18
|
constructor() {
|
|
19
|
-
emit Peer(host, NAME, Schemas.Asset,
|
|
19
|
+
emit Peer(host, peerDenyAssetsId, NAME, Schemas.Asset, false);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/// @notice Execute the deny-assets peer call.
|
package/peer/Settle.sol
CHANGED
|
@@ -3,7 +3,7 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import { PeerBase } from "./Base.sol";
|
|
5
5
|
import { TransferHook } from "../commands/Transfer.sol";
|
|
6
|
-
import { Cursors, Cur,
|
|
6
|
+
import { Cursors, Cur, Schemas } from "../Cursors.sol";
|
|
7
7
|
|
|
8
8
|
using Cursors for Cur;
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ abstract contract PeerSettle is PeerBase, TransferHook {
|
|
|
16
16
|
uint internal immutable peerSettleId = peerId(NAME);
|
|
17
17
|
|
|
18
18
|
constructor() {
|
|
19
|
-
emit Peer(host, NAME, Schemas.Transaction,
|
|
19
|
+
emit Peer(host, peerSettleId, NAME, Schemas.Transaction, false);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/// @notice Execute the peer-settle call.
|
|
@@ -24,8 +24,7 @@ abstract contract PeerSettle is PeerBase, TransferHook {
|
|
|
24
24
|
(Cur memory state, , ) = cursor(request, 1);
|
|
25
25
|
|
|
26
26
|
while (state.i < state.bound) {
|
|
27
|
-
|
|
28
|
-
transfer(value);
|
|
27
|
+
transfer(state.unpackTxValue());
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
state.complete();
|