@rootzero/contracts 1.14.0 → 1.16.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 (68) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/Codec.sol +1 -1
  3. package/Commands.sol +1 -1
  4. package/Core.sol +8 -5
  5. package/Endpoints.sol +6 -6
  6. package/Events.sol +1 -3
  7. package/README.md +118 -35
  8. package/annotations/Action.sol +17 -0
  9. package/annotations/Label.sol +23 -0
  10. package/annotations/Schema.sol +53 -0
  11. package/codec/Blocks.sol +127 -32
  12. package/codec/Buffers.sol +3 -3
  13. package/codec/Decoders.sol +46 -13
  14. package/codec/Descriptors.sol +0 -1
  15. package/codec/Keys.sol +8 -4
  16. package/codec/Readers.sol +13 -0
  17. package/codec/Schema.sol +12 -3
  18. package/codec/Specs.sol +28 -4
  19. package/codec/Writers.sol +21 -6
  20. package/commands/Base.sol +39 -44
  21. package/commands/Burn.sol +8 -4
  22. package/commands/Credit.sol +35 -3
  23. package/commands/Debit.sol +46 -13
  24. package/commands/Deposit.sol +14 -8
  25. package/commands/Payout.sol +6 -2
  26. package/commands/Provision.sol +4 -4
  27. package/commands/Recover.sol +15 -8
  28. package/commands/Relay.sol +37 -12
  29. package/commands/Settle.sol +77 -0
  30. package/commands/Withdraw.sol +8 -4
  31. package/commands/admin/AllowAssets.sol +2 -2
  32. package/commands/admin/Allowance.sol +2 -2
  33. package/commands/admin/Annotate.sol +36 -0
  34. package/commands/admin/Appoint.sol +6 -5
  35. package/commands/admin/Authorize.sol +2 -2
  36. package/commands/admin/Base.sol +8 -1
  37. package/commands/admin/DenyAssets.sol +2 -2
  38. package/commands/admin/Dismiss.sol +6 -5
  39. package/commands/admin/Execute.sol +5 -4
  40. package/commands/admin/Unauthorize.sol +2 -2
  41. package/core/Access.sol +91 -49
  42. package/core/Calls.sol +27 -22
  43. package/core/Endpoint.sol +36 -46
  44. package/core/Host.sol +63 -21
  45. package/core/Pipeline.sol +6 -6
  46. package/core/Settlement.sol +37 -8
  47. package/core/Types.sol +13 -1
  48. package/docs/Schema.md +68 -7
  49. package/events/Annotation.sol +24 -0
  50. package/events/Guardian.sol +2 -2
  51. package/events/Introduction.sol +3 -2
  52. package/execution/Budget.sol +12 -4
  53. package/execution/Execution.sol +113 -18
  54. package/guards/Base.sol +4 -4
  55. package/package.json +1 -1
  56. package/ports/Base.sol +19 -7
  57. package/ports/Dispatch.sol +6 -6
  58. package/ports/{Settle.sol → Post.sol} +13 -9
  59. package/queries/Base.sol +18 -3
  60. package/utils/Accounts.sol +0 -23
  61. package/utils/Actions.sol +1 -0
  62. package/utils/Cursors.sol +79 -34
  63. package/utils/Layout.sol +0 -2
  64. package/commands/admin/Label.sol +0 -36
  65. package/commands/admin/Schemas.sol +0 -36
  66. package/events/Labeled.sol +0 -21
  67. package/events/Position.sol +0 -22
  68. package/events/Schema.sol +0 -23
package/core/Host.sol CHANGED
@@ -1,15 +1,17 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {AccessControl} from "./Access.sol";
4
+ import {AccessDenied, CallerAccess, CommanderAccess} from "./Access.sol";
5
+ import {Runtime} from "./Runtime.sol";
6
+ import {Annotate} from "../commands/admin/Annotate.sol";
5
7
  import {Appoint} from "../commands/admin/Appoint.sol";
6
8
  import {Authorize} from "../commands/admin/Authorize.sol";
7
9
  import {Dismiss} from "../commands/admin/Dismiss.sol";
8
10
  import {Unauthorize} from "../commands/admin/Unauthorize.sol";
9
11
  import {ExecutePayable} from "../commands/admin/Execute.sol";
10
- import {Label} from "../commands/admin/Label.sol";
11
12
  import {Revoke} from "../guards/Revoke.sol";
12
13
  import {IntroductionEvent} from "../events/Introduction.sol";
14
+ import {Accounts} from "../utils/Accounts.sol";
13
15
  import {Nodes} from "../utils/Nodes.sol";
14
16
 
15
17
  /// @title IHostIntroduction
@@ -21,6 +23,55 @@ interface IHostIntroduction {
21
23
  function introduce(uint peer, uint blocknum) external;
22
24
  }
23
25
 
26
+ /// @title HostIntroduction
27
+ /// @notice Shared deployment-time introduction behavior for rootzero hosts.
28
+ /// Calls a deployed commander during construction without adding an inbound
29
+ /// introduction endpoint to the inheriting host.
30
+ abstract contract HostIntroduction is Runtime {
31
+ /// @param cmdr Commander address to introduce this host to when it is a deployed contract.
32
+ /// @dev Deployment reverts if a contract commander does not accept `introduce(uint,uint)`.
33
+ constructor(address cmdr) {
34
+ if (cmdr == address(0) || cmdr == address(this) || cmdr.code.length == 0) return;
35
+ introduceTo(Nodes.toHost(cmdr));
36
+ }
37
+
38
+ /// @notice Introduce this host to the contract address embedded in a local EVM node ID.
39
+ /// @dev Accepts host and endpoint IDs such as commands, ports, queries, and guards.
40
+ /// Reverts when `node` is not local or embeds the zero address.
41
+ /// @param node Local EVM node ID whose underlying contract receives the introduction.
42
+ function introduceTo(uint node) internal {
43
+ IHostIntroduction(Nodes.addr(node)).introduce(host, block.number);
44
+ }
45
+ }
46
+
47
+ /// @title CommandHost
48
+ /// @notice Minimal host base for commander-only command execution.
49
+ /// Does not include admin commands, peer authorization, guardians, inbound
50
+ /// introductions, generic execution, or a native-token receive function.
51
+ /// Commands using trusted `NodeCalls` must separately compose a `TrustAccess` policy.
52
+ abstract contract CommandHost is CommanderAccess, CallerAccess, HostIntroduction {
53
+ /// @dev Thrown when a commander-only host is deployed without an external commander.
54
+ error InvalidCommander();
55
+
56
+ /// @param cmdr Nonzero address allowed to invoke hosted commands.
57
+ constructor(address cmdr) CommanderAccess(cmdr) HostIntroduction(cmdr) {
58
+ if (cmdr == address(0)) revert InvalidCommander();
59
+ }
60
+
61
+ function enforceCaller(address caller) internal view virtual override returns (address) {
62
+ return enforceCommander(caller);
63
+ }
64
+
65
+ }
66
+
67
+ /// @title Admins
68
+ /// @notice Optional bundle of the default host administration commands.
69
+ abstract contract Admins is Annotate, ExecutePayable, Authorize, Unauthorize {}
70
+
71
+ /// @title Guardians
72
+ /// @notice Optional bundle for guardian management and the default revoke guard.
73
+ abstract contract Guardians is Appoint, Dismiss, Revoke {}
74
+
24
75
  /// @title Host
25
76
  /// @notice Abstract base contract for rootzero host implementations.
26
77
  /// Inherits admin command support (authorize, unauthorize, label, executePayable),
@@ -28,30 +79,21 @@ interface IHostIntroduction {
28
79
  /// optionally introduces itself to a commander host at deployment.
29
80
  /// Accepts native ETH payments via the `receive` function.
30
81
  abstract contract Host is
31
- Authorize,
32
- Unauthorize,
33
- Revoke,
34
- Appoint,
35
- Dismiss,
36
- Label,
37
- ExecutePayable,
82
+ Admins,
83
+ Guardians,
84
+ HostIntroduction,
38
85
  IntroductionEvent,
39
86
  IHostIntroduction
40
87
  {
41
- /// @param cmdr Commander address; passed to `AccessControl`.
88
+ /// @param cmdr Commander address; used by the composed access capabilities.
42
89
  /// If `cmdr` is a deployed contract, the host calls `introduce`
43
90
  /// on it during construction.
44
- constructor(address cmdr) AccessControl(cmdr) {
45
- if (cmdr == address(0) || cmdr == address(this) || cmdr.code.length == 0) return;
46
- introduceTo(Nodes.toHost(cmdr));
47
- }
91
+ constructor(address cmdr) CommanderAccess(cmdr) HostIntroduction(cmdr) {}
48
92
 
49
- /// @notice Introduce this host to the contract address embedded in a local EVM node ID.
50
- /// @dev Accepts host and endpoint IDs such as commands, ports, queries, and guards.
51
- /// Reverts when `node` is not local or embeds the zero address.
52
- /// @param node Local EVM node ID whose underlying contract receives the introduction.
53
- function introduceTo(uint node) internal {
54
- IHostIntroduction(Nodes.addr(node)).introduce(host, block.number);
93
+ /// @notice Assert that `caller` may invoke commands on a peer-aware host.
94
+ function enforceCaller(address caller) internal view virtual override returns (address) {
95
+ if (caller == address(0) || !isTrustedCaller(caller)) revert AccessDenied();
96
+ return caller;
55
97
  }
56
98
 
57
99
  /// @notice Record a host introduction claim.
@@ -59,7 +101,7 @@ abstract contract Host is
59
101
  /// @param peer Host node ID being introduced.
60
102
  /// @param blocknum Block number at which the host was deployed.
61
103
  function introduce(uint peer, uint blocknum) external {
62
- emit Introduction(host, Nodes.matchHost(peer, msg.sender), blocknum);
104
+ emit Introduction(host, Nodes.matchHost(peer, msg.sender), Accounts.toUser(tx.origin), blocknum);
63
105
  }
64
106
 
65
107
  /// @notice Accept native ETH transfers (e.g. from command value flows).
package/core/Pipeline.sol CHANGED
@@ -2,7 +2,7 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {Decoders, Cur, Readers, Reader} from "../Codec.sol";
5
- import {Settlement} from "./Settlement.sol";
5
+ import {PostHook} from "./Settlement.sol";
6
6
  import {Budget, Budgets} from "../execution/Budget.sol";
7
7
 
8
8
  using Decoders for Cur;
@@ -11,14 +11,14 @@ using Budgets for Budget;
11
11
 
12
12
  /// @title Pipeline
13
13
  /// @notice Core pipeline functionality shared by higher-level surfaces.
14
- abstract contract Pipeline is Settlement {
14
+ abstract contract Pipeline is PostHook {
15
15
  /// @dev Thrown when the pipeline finishes with non-empty threaded state.
16
16
  error UnexpectedState();
17
17
 
18
18
  /// @notice Override to dispatch one piped step.
19
19
  /// Called once per STEP block. The returned state becomes the state passed to
20
20
  /// the next step, and the final returned state must be empty. Returned
21
- /// transactions are decoded and passed individually to `settle` before the next step runs.
21
+ /// transactions are decoded and passed individually to `post` before the next step runs.
22
22
  /// @param cmd Command node ID to invoke or handle.
23
23
  /// @param account Account identifier for the piped context.
24
24
  /// @param state Current threaded state block stream.
@@ -42,16 +42,16 @@ abstract contract Pipeline is Settlement {
42
42
  /// @param steps STEP block stream to execute.
43
43
  /// @param budget Mutable native-value budget shared across all steps.
44
44
  function pipe(bytes32 account, bytes memory state, bytes calldata steps, Budget memory budget) internal {
45
- Cur memory cur = Decoders.open(steps, 1);
45
+ Cur memory cur = Decoders.open(steps);
46
46
 
47
47
  while (cur.more()) {
48
48
  (uint cmd, uint resources, bytes calldata input) = cur.unpackStep();
49
49
  Reader memory txs;
50
- (state, txs.source) = dispatch(cmd, account, state, input, budget.use(resources));
50
+ (state, txs.source) = dispatch(cmd, account, state, input, budget.useResourceValue(resources));
51
51
 
52
52
  while (txs.more()) {
53
53
  (bytes32 from, bytes32 to, bytes32 asset, uint amount) = txs.unpackTransaction();
54
- settle(from, to, asset, amount);
54
+ post(from, to, asset, amount);
55
55
  }
56
56
  }
57
57
 
@@ -21,19 +21,48 @@ abstract contract CreditAccountHook {
21
21
  function creditAccount(bytes32 account, bytes32 asset, uint amount) internal virtual;
22
22
  }
23
23
 
24
+ /// @title PostHook
25
+ /// @notice Hook for posting one transaction between accounts.
26
+ abstract contract PostHook {
27
+ /// @notice Override to post one transaction.
28
+ function post(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal virtual;
29
+ }
30
+
31
+ /// @title SettleHook
32
+ /// @notice Hook for settling one asset-liability position.
33
+ abstract contract SettleHook {
34
+ /// @notice Override to settle one position for `account`.
35
+ function settle(
36
+ bytes32 account,
37
+ bytes32 asset,
38
+ uint amount,
39
+ bytes32 liability,
40
+ uint debt
41
+ ) internal virtual;
42
+ }
43
+
24
44
  /// @title Settlement
25
- /// @notice Settles decoded transactions through debit and credit account hooks.
26
- abstract contract Settlement is DebitAccountHook, CreditAccountHook {
27
- /// @notice Settle one transaction by debiting its source and crediting its destination.
45
+ /// @notice Default account-hook implementation for transaction posting and position settlement.
46
+ abstract contract Settlement is PostHook, SettleHook, DebitAccountHook, CreditAccountHook {
47
+ /// @notice Post one transaction by debiting its source and crediting its destination.
28
48
  /// Returns without calling either hook when `amount` is zero and skips either
29
49
  /// operation when the corresponding account is zero.
30
- /// @param from Source account identifier.
31
- /// @param to Destination account identifier.
32
- /// @param asset Asset identifier.
33
- /// @param amount Token amount.
34
- function settle(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal {
50
+ function post(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal virtual override {
35
51
  if (amount == 0) return;
36
52
  if (from != 0) debitAccount(from, asset, amount);
37
53
  if (to != 0) creditAccount(to, asset, amount);
38
54
  }
55
+
56
+ /// @notice Settle one position by crediting its asset and debiting its liability.
57
+ /// Skips either operation when its corresponding amount is zero.
58
+ function settle(
59
+ bytes32 account,
60
+ bytes32 asset,
61
+ uint amount,
62
+ bytes32 liability,
63
+ uint debt
64
+ ) internal virtual override {
65
+ if (amount != 0) creditAccount(account, asset, amount);
66
+ if (debt != 0) debitAccount(account, liability, debt);
67
+ }
39
68
  }
package/core/Types.sol CHANGED
@@ -59,7 +59,19 @@ struct HostAccountAmount {
59
59
  uint amount;
60
60
  }
61
61
 
62
- /// @notice Transfer payload used by transaction blocks and peer settlement.
62
+ /// @notice Asset and liability pair threaded as live pipeline state.
63
+ struct Position {
64
+ /// @dev Identifier for the asset side.
65
+ bytes32 asset;
66
+ /// @dev Quantity on the asset side.
67
+ uint amount;
68
+ /// @dev Identifier for the liability side.
69
+ bytes32 liability;
70
+ /// @dev Quantity owed on the liability side.
71
+ uint debt;
72
+ }
73
+
74
+ /// @notice Transfer payload used by transaction blocks and peer posting.
63
75
  struct Tx {
64
76
  /// @dev Sender account identifier.
65
77
  bytes32 from;
package/docs/Schema.md CHANGED
@@ -27,12 +27,23 @@ For example, the standard `amount` alias uses the key derived from `#amount`
27
27
  and the schema body `{ bytes32 asset, uint amount }`. Custom block keys do not
28
28
  have to be keccak-derived. They
29
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:
30
+ used. A host can publish the meaning of a custom key as an annotation:
31
31
 
32
32
  ```solidity
33
- event Schema(uint indexed host, uint spec, string body, bytes32 name);
33
+ event Annotation(uint indexed entity, bytes data);
34
+ #schema { uint spec, #string as body, bytes32 name }
34
35
  ```
35
36
 
37
+ Annotation merge behavior is defined by the annotation block type rather than
38
+ by the `Annotation` event. A `#schema` annotation is identified by its entity
39
+ and the block key encoded in `spec`: distinct keys accumulate, while the latest
40
+ trusted claim for the same key replaces the earlier one. Other annotation types
41
+ may define additive, historical, or explicitly revocable behavior instead.
42
+
43
+ The standard `#action { uint action }` annotation assigns one primary semantic
44
+ action to an entity. The latest trusted value replaces the previous value, and
45
+ `Actions.None` clears the classification.
46
+
36
47
  For example, a host-specific payment block can use a small literal, the command
37
48
  selector, or any other chosen `bytes4` value as long as that key is not
38
49
  overloaded in the relevant host/schema context.
@@ -150,12 +161,62 @@ with no payload, use a zero-payload block such as `#unit`.
150
161
 
151
162
  Endpoint descriptors currently use a narrower convention than the full block
152
163
  grammar: each state, input, or output lane is a single run of blocks, without
153
- additional global items. Future protocol surfaces may use the more flexible
154
- top-level structure.
164
+ additional global items. Endpoint decoder opening requires that run to consume
165
+ the complete supplied lane; a trailing block with another key is invalid.
166
+ Lower-level cursor scanning may still intentionally open only a prefix run.
167
+ Those lower layers retain only the raw block count; descriptor strides are
168
+ applied and lane groups reconciled once when an endpoint execution opens.
169
+ Future protocol surfaces may use the more flexible top-level structure.
170
+
171
+ For commands, complete-lane validation is also a state-safety rule. State is a
172
+ linear value owned by the current pipeline step, not optional context that a
173
+ command may disregard. Every command must account for the complete supplied
174
+ state by consuming it, transforming and returning it, forwarding it intact, or
175
+ reverting. A command whose descriptor declares an empty state lane must reject
176
+ non-empty state. A command that accepts state must validate the complete stream
177
+ against its declared schema; accepting only a prefix and silently dropping the
178
+ remainder is invalid.
179
+
180
+ ## Live Pipeline State
181
+
182
+ `#balance`, `#custody`, and `#position` are live state carried between command
183
+ steps for the active account. A position atomically pairs an asset side with a
184
+ liability side:
185
+
186
+ ```txt
187
+ position { bytes32 asset, uint amount, bytes32 liability, uint debt }
188
+ ```
189
+
190
+ The pair is deliberately general. The asset side represents value acquired or
191
+ controlled, and the liability side represents value owed or required. Commands
192
+ may preserve or replace either side and return a new position. The terminal
193
+ `settle` command consumes the pair. Position state is transient protocol state;
194
+ rewriting it does not by itself create, discharge, or replace an obligation
195
+ persisted by a host or external protocol. The responsible command hook must
196
+ perform or verify those effects. A command must not ignore a supplied position:
197
+ it must explicitly consume, transform, forward, or reject it, so neither its
198
+ asset nor its debt can disappear accidentally.
199
+
200
+ This representation supports ordinary forward transformations as well as
201
+ backward composition. For example, an exact-output route can carry its desired
202
+ asset while successive hops replace the upstream liability:
203
+
204
+ ```txt
205
+ position(C, 100, C, 100)
206
+ → position(C, 100, B, 50)
207
+ → position(C, 100, A, 25)
208
+ → settle
209
+ ```
210
+
211
+ “Backward” describes how requirements are composed from the desired result
212
+ toward the source. Pipeline execution is not reversed: STEP blocks always run
213
+ forward in their encoded order. Exact-output routing is only an example;
214
+ borrowing, refinancing, collateral transformation, callback obligations,
215
+ cross-host claims, fees, and netting can use the same position state.
155
216
 
156
217
  ## Field Aliases
157
218
 
158
- Block aliases are published in `Schema` events. Field aliases are presentation
219
+ Block aliases are published in `#schema` annotations. Field aliases are presentation
159
220
  metadata for tooling. They do not change payload layout or runtime keys.
160
221
 
161
222
  ```txt
@@ -306,8 +367,8 @@ invalid in any path segment.
306
367
  - `#list`: generic list wrapper emitted by `many`
307
368
 
308
369
  Custom input shapes should define their own context-local block spec and publish
309
- it with a `Schema` event. Endpoint contracts can use `schema(...)` to construct
310
- and publish that spec:
370
+ it with a `#schema` annotation. Endpoint contracts can use `schema(...)` to
371
+ construct and publish that spec:
311
372
 
312
373
  ```solidity
313
374
  uint input = schema(1, 64, 64, 64, "{ bytes32 asset, uint amount }", bytes32(0));
@@ -0,0 +1,24 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {EventEmitter} from "./Emitter.sol";
5
+
6
+ /// @notice Emitted to attach encoded annotation blocks to an entity.
7
+ /// @dev `data` is a protocol block stream. A single block is the conventional
8
+ /// case, but related annotations may be emitted together. Annotations are claims
9
+ /// by the emitting contract, and each block key defines its annotation type.
10
+ /// Consumers process events in log order and blocks in stream order, then apply
11
+ /// the identity and merge rules defined by each annotation type. The event does
12
+ /// not impose a universal replacement policy: a type may replace, accumulate,
13
+ /// preserve history, or define its own revocation convention.
14
+ abstract contract AnnotationEvent is EventEmitter {
15
+ string private constant ABI = "event Annotation(uint indexed entity, bytes data)";
16
+
17
+ /// @param entity Entity being annotated.
18
+ /// @param data Encoded annotation block stream, conventionally containing one block.
19
+ event Annotation(uint indexed entity, bytes data);
20
+
21
+ constructor() {
22
+ emit EventAbi(ABI);
23
+ }
24
+ }
@@ -3,12 +3,12 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- /// @notice Emitted when a guardian account status changes on a host.
6
+ /// @notice Emitted when a user account's guardian role changes on a host.
7
7
  abstract contract GuardianEvent is EventEmitter {
8
8
  string private constant ABI = "event Guardian(uint indexed host, bytes32 account, bool active)";
9
9
 
10
10
  /// @param host Host node ID where the guardian change occurred.
11
- /// @param account Guardian account ID.
11
+ /// @param account User account ID assigned or removed as a guardian.
12
12
  /// @param active True if the guardian is enabled, false if revoked.
13
13
  event Guardian(uint indexed host, bytes32 account, bool active);
14
14
 
@@ -5,12 +5,13 @@ import { EventEmitter } from "./Emitter.sol";
5
5
 
6
6
  /// @notice Emitted when a host introduces itself to another host.
7
7
  abstract contract IntroductionEvent is EventEmitter {
8
- string private constant ABI = "event Introduction(uint indexed host, uint peer, uint blocknum)";
8
+ string private constant ABI = "event Introduction(uint indexed host, uint peer, bytes32 origin, uint blocknum)";
9
9
 
10
10
  /// @param host Host node ID receiving the introduction.
11
11
  /// @param peer Host node ID of the introducing contract.
12
+ /// @param origin Transaction-origin address encoded as a chain-agnostic user account.
12
13
  /// @param blocknum Block number at which the host was deployed.
13
- event Introduction(uint indexed host, uint peer, uint blocknum);
14
+ event Introduction(uint indexed host, uint peer, bytes32 origin, uint blocknum);
14
15
 
15
16
  constructor() {
16
17
  emit EventAbi(ABI);
@@ -19,15 +19,23 @@ library Budgets {
19
19
  budget.remaining = msg.value;
20
20
  }
21
21
 
22
+ /// @notice Deduct an exact native value from `budget`.
23
+ /// @param budget Mutable budget to debit.
24
+ /// @param value Native value to consume in wei.
25
+ /// @return The consumed native value.
26
+ function useValue(Budget memory budget, uint value) internal pure returns (uint) {
27
+ if (value > budget.remaining) revert InsufficientValue();
28
+ budget.remaining -= value;
29
+ return value;
30
+ }
31
+
22
32
  /// @notice Deduct the EVM value lane of `resources` from `budget`.
23
33
  /// @dev EVM resources use the low 128 bits as native value/endowment.
24
34
  /// @param budget Mutable budget to debit.
25
35
  /// @param resources Packed resources whose low 128 bits contain native value.
26
36
  /// @return value Native value to forward in wei.
27
- function use(Budget memory budget, uint resources) internal pure returns (uint128 value) {
28
- value = uint128(resources);
29
- if (value > budget.remaining) revert InsufficientValue();
30
- budget.remaining -= value;
37
+ function useResourceValue(Budget memory budget, uint resources) internal pure returns (uint128) {
38
+ return uint128(useValue(budget, uint128(resources)));
31
39
  }
32
40
 
33
41
  /// @notice Remove and return all remaining value from `budget`.