@rootzero/contracts 1.21.0 → 1.23.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 (54) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/Endpoints.sol +2 -3
  3. package/Events.sol +1 -1
  4. package/README.md +25 -19
  5. package/annotations/Action.sol +1 -1
  6. package/annotations/Label.sol +1 -1
  7. package/annotations/Schema.sol +36 -3
  8. package/codec/Blocks.sol +100 -29
  9. package/codec/Decoders.sol +62 -8
  10. package/codec/Readers.sol +39 -0
  11. package/codec/Schema.sol +44 -35
  12. package/codec/Writers.sol +8 -0
  13. package/commands/Allocate.sol +5 -8
  14. package/commands/Base.sol +29 -13
  15. package/commands/Burn.sol +5 -7
  16. package/commands/Credit.sol +5 -7
  17. package/commands/Debit.sol +5 -7
  18. package/commands/Deposit.sol +10 -14
  19. package/commands/Payout.sol +5 -8
  20. package/commands/Provision.sol +10 -14
  21. package/commands/Recover.sol +4 -6
  22. package/commands/Relay.sol +16 -22
  23. package/commands/Repay.sol +10 -14
  24. package/commands/Settle.sol +10 -14
  25. package/commands/Withdraw.sol +5 -7
  26. package/commands/admin/AllowAssets.sol +5 -7
  27. package/commands/admin/Allowance.sol +5 -7
  28. package/commands/admin/Annotate.sol +5 -7
  29. package/commands/admin/Appoint.sol +5 -7
  30. package/commands/admin/Authorize.sol +5 -7
  31. package/commands/admin/Base.sol +12 -3
  32. package/commands/admin/DenyAssets.sol +5 -7
  33. package/commands/admin/Dismiss.sol +5 -7
  34. package/commands/admin/Execute.sol +5 -7
  35. package/commands/admin/Unauthorize.sol +5 -7
  36. package/core/Calls.sol +72 -3
  37. package/core/Host.sol +7 -10
  38. package/core/Portal.sol +2 -2
  39. package/events/Dispatch.sol +1 -1
  40. package/events/Positioned.sol +22 -0
  41. package/events/Relay.sol +1 -1
  42. package/events/Route.sol +1 -1
  43. package/execution/Execution.sol +124 -4
  44. package/package.json +2 -3
  45. package/ports/Allowance.sol +22 -12
  46. package/ports/Assets.sol +99 -0
  47. package/ports/Dispatch.sol +2 -1
  48. package/utils/Cursors.sol +3 -3
  49. package/utils/Nodes.sol +1 -1
  50. package/utils/Utils.sol +31 -31
  51. package/docs/Schema.md +0 -427
  52. package/events/Commander.sol +0 -19
  53. package/ports/AllowAssets.sol +0 -34
  54. package/ports/DenyAssets.sol +0 -34
@@ -2,35 +2,45 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {PortBase} from "./Base.sol";
5
- import {AllowanceHook} from "../commands/admin/Allowance.sol";
6
5
  import {Specs} from "../Codec.sol";
7
6
  import {Execution, Executions, Lanes} from "../execution/Execution.sol";
8
7
 
9
8
  using Executions for Execution;
10
9
 
11
- /// @title AllowancePort
12
- /// @notice Port that lets a trusted peer host input or refresh its own allowance.
13
- /// Each AMOUNT block in the input is scoped to the peer host and passed to the
14
- /// shared allowance hook as a host-scoped allowance. Restricted to trusted peers.
15
- abstract contract AllowancePort is PortBase, AllowanceHook {
10
+ /// @notice Hook implemented by hosts that handle allowance requests from peers.
11
+ abstract contract RequestAllowanceHook {
12
+ /// @notice Override to handle one allowance request from a peer host.
13
+ /// @dev The implementation is responsible for validating the request and
14
+ /// deciding what allowance, if any, to grant.
15
+ /// @param peer Peer host node ID requesting the allowance.
16
+ /// @param asset Asset identifier supplied by the peer.
17
+ /// @param amount Allowance amount requested in the asset's native units.
18
+ function requestAllowance(uint peer, bytes32 asset, uint amount) internal virtual;
19
+ }
20
+
21
+ /// @title RequestAllowancePort
22
+ /// @notice Port that lets trusted peers request their own asset allowances.
23
+ /// Each AMOUNT block is scoped to the caller and passed unchanged to
24
+ /// `requestAllowance(peer, asset, amount)`.
25
+ abstract contract RequestAllowancePort is PortBase, RequestAllowanceHook {
16
26
  uint private immutable descriptor;
17
27
 
18
28
  constructor() {
19
- (, descriptor) = port("portAllowance", Specs.Amount, Specs.Empty, 0);
29
+ (, descriptor) = port("portRequestAllowance", Specs.Amount, Specs.Empty, 0);
20
30
  }
21
31
 
22
- /// @notice Execute the allowance port call.
23
- /// @param data AMOUNT block stream requested by the trusted peer.
32
+ /// @notice Request asset allowances for the calling peer.
33
+ /// @param data AMOUNT block stream supplied by the trusted peer.
24
34
  /// @return Empty response bytes.
25
- function portAllowance(bytes calldata data) external onlyPeer returns (bytes memory) {
35
+ function portRequestAllowance(bytes calldata data) external onlyPeer returns (bytes memory) {
26
36
  Execution memory exec = openInput(data, descriptor, 0);
27
37
  uint peer = caller();
28
38
 
29
39
  while (exec.more()) {
30
40
  (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
31
- allowance(peer, asset, amount);
41
+ requestAllowance(peer, asset, amount);
32
42
  }
33
-
43
+
34
44
  return "";
35
45
  }
36
46
  }
@@ -0,0 +1,99 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {PortBase} from "./Base.sol";
5
+ import {AllowAssetsHook} from "../commands/admin/AllowAssets.sol";
6
+ import {DenyAssetsHook} from "../commands/admin/DenyAssets.sol";
7
+ import {Specs} from "../Codec.sol";
8
+ import {Execution, Executions, Lanes} from "../execution/Execution.sol";
9
+
10
+ using Executions for Execution;
11
+
12
+ /// @title AllowAssetsPort
13
+ /// @notice Port that permits a list of assets on behalf of a peer host.
14
+ /// Each ASSET block in the input calls `allowAsset`. Restricted to trusted peers.
15
+ abstract contract AllowAssetsPort is PortBase, AllowAssetsHook {
16
+ uint private immutable descriptor;
17
+
18
+ constructor() {
19
+ (, descriptor) = port("portAllowAssets", Specs.Asset, Specs.Empty, 0);
20
+ }
21
+
22
+ /// @notice Execute the allow-assets peer call.
23
+ /// @param data ASSET block stream supplied by the trusted peer.
24
+ /// @return Empty response bytes.
25
+ function portAllowAssets(bytes calldata data) external onlyPeer returns (bytes memory) {
26
+ Execution memory exec = openInput(data, descriptor, 0);
27
+
28
+ while (exec.more()) {
29
+ bytes32 asset = exec.unpackAsset(Lanes.Input);
30
+ allowAsset(asset);
31
+ }
32
+
33
+ return "";
34
+ }
35
+ }
36
+
37
+ /// @title DenyAssetsPort
38
+ /// @notice Port that blocks a list of assets on behalf of a peer host.
39
+ /// Each ASSET block in the input calls `denyAsset`. Restricted to trusted peers.
40
+ abstract contract DenyAssetsPort is PortBase, DenyAssetsHook {
41
+ uint private immutable descriptor;
42
+
43
+ constructor() {
44
+ (, descriptor) = port("portDenyAssets", Specs.Asset, Specs.Empty, 0);
45
+ }
46
+
47
+ /// @notice Execute the deny-assets peer call.
48
+ /// @param data ASSET block stream supplied by the trusted peer.
49
+ /// @return Empty response bytes.
50
+ function portDenyAssets(bytes calldata data) external onlyPeer returns (bytes memory) {
51
+ Execution memory exec = openInput(data, descriptor, 0);
52
+
53
+ while (exec.more()) {
54
+ bytes32 asset = exec.unpackAsset(Lanes.Input);
55
+ denyAsset(asset);
56
+ }
57
+
58
+ return "";
59
+ }
60
+ }
61
+
62
+ /// @notice Hook implemented by hosts that fulfill asset requests from peers.
63
+ abstract contract RequestAssetHook {
64
+ /// @notice Override to handle one asset request from a peer host.
65
+ /// @dev The implementation is responsible for validating `asset`, enforcing
66
+ /// requester policy, and sending the approved amount to the requester.
67
+ /// @param peer Peer host node ID for this request.
68
+ /// @param asset Asset identifier supplied by the peer.
69
+ /// @param amount Amount requested in the asset's native units.
70
+ function requestAsset(uint peer, bytes32 asset, uint amount) internal virtual;
71
+ }
72
+
73
+ /// @title RequestAssetPort
74
+ /// @notice Port that lets trusted peers request assets from the receiving host.
75
+ /// Each AMOUNT block is scoped to the caller and passed unchanged to
76
+ /// `requestAsset(peer, asset, amount)`. The hook validates support and performs
77
+ /// any accounting and transfer required by the host.
78
+ abstract contract RequestAssetPort is PortBase, RequestAssetHook {
79
+ uint private immutable descriptor;
80
+
81
+ constructor() {
82
+ (, descriptor) = port("portRequestAsset", Specs.Amount, Specs.Empty, 0);
83
+ }
84
+
85
+ /// @notice Request assets for the calling peer.
86
+ /// @param data AMOUNT block stream supplied by the trusted peer.
87
+ /// @return Empty response bytes.
88
+ function portRequestAsset(bytes calldata data) external onlyPeer returns (bytes memory) {
89
+ Execution memory exec = openInput(data, descriptor, 0);
90
+ uint peer = caller();
91
+
92
+ while (exec.more()) {
93
+ (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
94
+ requestAsset(peer, asset, amount);
95
+ }
96
+
97
+ return "";
98
+ }
99
+ }
@@ -11,7 +11,8 @@ using Executions for Execution;
11
11
  /// @notice Hook implemented by hosts that forward funded dispatch payloads.
12
12
  abstract contract DispatchPayableHook {
13
13
  /// @notice Override to dispatch an encoded payload to `portal`.
14
- /// @param portal Destination portal identifier, often the destination host ID.
14
+ /// @param portal Destination portal implementation's host ID. Implementations
15
+ /// may validate or resolve it for their transport.
15
16
  /// @param resources Chain-specific destination resources. EVM adapters
16
17
  /// may interpret this as packed execution gas and destination value.
17
18
  /// @param payload Encoded payload ready for the transport layer.
package/utils/Cursors.sol CHANGED
@@ -65,9 +65,9 @@ library Cursors {
65
65
  /// @param tag Cursor identity tag.
66
66
  /// @return cur Packed cursor.
67
67
  function create(uint offset, uint len, uint items, uint8 flags, uint8 tag) internal pure returns (uint cur) {
68
- cur |= max32(offset) << 32;
69
- cur |= max32(len) << 64;
70
- cur |= max16(items) << 96;
68
+ cur |= uint(max32(offset)) << 32;
69
+ cur |= uint(max32(len)) << 64;
70
+ cur |= uint(max16(items)) << 96;
71
71
  cur |= uint(flags) << 112;
72
72
  cur |= uint(tag) << 120;
73
73
  }
package/utils/Nodes.sol CHANGED
@@ -198,7 +198,7 @@ library Nodes {
198
198
  /// @return node Command node ID embedding both the selector and address.
199
199
  function toCommand(string memory name, address target) internal view returns (uint node) {
200
200
  node = toLocalBase(Command) | uint(uint160(target));
201
- node |= uint(uint32(toSelector(name, "(bytes32,bytes,bytes)"))) << 160;
201
+ node |= uint(uint32(toSelector(name, "(bytes)"))) << 160;
202
202
  }
203
203
 
204
204
  /// @notice Build a chain-local port ID for the given endpoint name and contract.
package/utils/Utils.sol CHANGED
@@ -11,76 +11,76 @@ error NotDivisible();
11
11
  /// @dev Thrown when an ID claims to carry an address but the embedded address is zero.
12
12
  error ZeroAddress();
13
13
 
14
- /// @notice Assert that `value` fits in uint8 and return it unchanged.
15
- function max8(uint value) pure returns (uint) {
14
+ /// @notice Assert that `value` fits in uint8 and return it as uint8.
15
+ function max8(uint value) pure returns (uint8) {
16
16
  if (value > type(uint8).max) {
17
17
  revert ValueOverflow();
18
18
  }
19
- return value;
19
+ return uint8(value);
20
20
  }
21
21
 
22
- /// @notice Assert that `value` fits in uint16 and return it unchanged.
23
- function max16(uint value) pure returns (uint) {
22
+ /// @notice Assert that `value` fits in uint16 and return it as uint16.
23
+ function max16(uint value) pure returns (uint16) {
24
24
  if (value > type(uint16).max) {
25
25
  revert ValueOverflow();
26
26
  }
27
- return value;
27
+ return uint16(value);
28
28
  }
29
29
 
30
- /// @notice Assert that `value` fits in uint24 and return it unchanged.
31
- function max24(uint value) pure returns (uint) {
30
+ /// @notice Assert that `value` fits in uint24 and return it as uint24.
31
+ function max24(uint value) pure returns (uint24) {
32
32
  if (value > type(uint24).max) {
33
33
  revert ValueOverflow();
34
34
  }
35
- return value;
35
+ return uint24(value);
36
36
  }
37
37
 
38
- /// @notice Assert that `value` fits in uint32 and return it unchanged.
39
- function max32(uint value) pure returns (uint) {
38
+ /// @notice Assert that `value` fits in uint32 and return it as uint32.
39
+ function max32(uint value) pure returns (uint32) {
40
40
  if (value > type(uint32).max) {
41
41
  revert ValueOverflow();
42
42
  }
43
- return value;
43
+ return uint32(value);
44
44
  }
45
45
 
46
- /// @notice Assert that `value` fits in uint40 and return it unchanged.
47
- function max40(uint value) pure returns (uint) {
46
+ /// @notice Assert that `value` fits in uint40 and return it as uint40.
47
+ function max40(uint value) pure returns (uint40) {
48
48
  if (value > type(uint40).max) {
49
49
  revert ValueOverflow();
50
50
  }
51
- return value;
51
+ return uint40(value);
52
52
  }
53
53
 
54
- /// @notice Assert that `value` fits in uint64 and return it unchanged.
55
- function max64(uint value) pure returns (uint) {
54
+ /// @notice Assert that `value` fits in uint64 and return it as uint64.
55
+ function max64(uint value) pure returns (uint64) {
56
56
  if (value > type(uint64).max) {
57
57
  revert ValueOverflow();
58
58
  }
59
- return value;
59
+ return uint64(value);
60
60
  }
61
61
 
62
- /// @notice Assert that `value` fits in uint96 and return it unchanged.
63
- function max96(uint value) pure returns (uint) {
62
+ /// @notice Assert that `value` fits in uint96 and return it as uint96.
63
+ function max96(uint value) pure returns (uint96) {
64
64
  if (value > type(uint96).max) {
65
65
  revert ValueOverflow();
66
66
  }
67
- return value;
67
+ return uint96(value);
68
68
  }
69
69
 
70
- /// @notice Assert that `value` fits in uint128 and return it unchanged.
71
- function max128(uint value) pure returns (uint) {
70
+ /// @notice Assert that `value` fits in uint128 and return it as uint128.
71
+ function max128(uint value) pure returns (uint128) {
72
72
  if (value > type(uint128).max) {
73
73
  revert ValueOverflow();
74
74
  }
75
- return value;
75
+ return uint128(value);
76
76
  }
77
77
 
78
- /// @notice Assert that `value` fits in uint160 and return it unchanged.
79
- function max160(uint value) pure returns (uint) {
78
+ /// @notice Assert that `value` fits in uint160 and return it as uint160.
79
+ function max160(uint value) pure returns (uint160) {
80
80
  if (value > type(uint160).max) {
81
81
  revert ValueOverflow();
82
82
  }
83
- return value;
83
+ return uint160(value);
84
84
  }
85
85
 
86
86
  // Packed fields
@@ -108,25 +108,25 @@ function clear64(uint value, uint shift) pure returns (uint) {
108
108
  /// @notice Replace the 8-bit field beginning at `shift` with `field`.
109
109
  /// @dev Reverts when `field` does not fit in 8 bits.
110
110
  function replace8(uint value, uint shift, uint field) pure returns (uint) {
111
- return clear8(value, shift) | (max8(field) << shift);
111
+ return clear8(value, shift) | (uint(max8(field)) << shift);
112
112
  }
113
113
 
114
114
  /// @notice Replace the 16-bit field beginning at `shift` with `field`.
115
115
  /// @dev Reverts when `field` does not fit in 16 bits.
116
116
  function replace16(uint value, uint shift, uint field) pure returns (uint) {
117
- return clear16(value, shift) | (max16(field) << shift);
117
+ return clear16(value, shift) | (uint(max16(field)) << shift);
118
118
  }
119
119
 
120
120
  /// @notice Replace the 32-bit field beginning at `shift` with `field`.
121
121
  /// @dev Reverts when `field` does not fit in 32 bits.
122
122
  function replace32(uint value, uint shift, uint field) pure returns (uint) {
123
- return clear32(value, shift) | (max32(field) << shift);
123
+ return clear32(value, shift) | (uint(max32(field)) << shift);
124
124
  }
125
125
 
126
126
  /// @notice Replace the 64-bit field beginning at `shift` with `field`.
127
127
  /// @dev Reverts when `field` does not fit in 64 bits.
128
128
  function replace64(uint value, uint shift, uint field) pure returns (uint) {
129
- return clear64(value, shift) | (max64(field) << shift);
129
+ return clear64(value, shift) | (uint(max64(field)) << shift);
130
130
  }
131
131
 
132
132
  /// @notice Assert that `n` is evenly divisible by `divisor`.