@rootzero/contracts 1.22.0 → 1.24.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 (57) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/Codec.sol +1 -1
  3. package/Commands.sol +1 -1
  4. package/Core.sol +2 -2
  5. package/Endpoints.sol +10 -4
  6. package/Events.sol +1 -1
  7. package/README.md +40 -32
  8. package/Utils.sol +1 -1
  9. package/annotations/Action.sol +1 -1
  10. package/annotations/Label.sol +1 -1
  11. package/annotations/Schema.sol +2 -8
  12. package/codec/Blocks.sol +113 -33
  13. package/codec/Decoders.sol +18 -1
  14. package/codec/Descriptors.sol +3 -1
  15. package/codec/Keys.sol +2 -0
  16. package/codec/Readers.sol +12 -0
  17. package/codec/Schema.sol +5 -4
  18. package/codec/Specs.sol +3 -0
  19. package/codec/Writers.sol +12 -1
  20. package/commands/Allocate.sol +5 -8
  21. package/commands/Base.sol +29 -13
  22. package/commands/Burn.sol +5 -7
  23. package/commands/Credit.sol +5 -7
  24. package/commands/Debit.sol +5 -7
  25. package/commands/Deposit.sol +10 -14
  26. package/commands/Payout.sol +5 -8
  27. package/commands/Provision.sol +10 -14
  28. package/commands/Recover.sol +4 -6
  29. package/commands/Relay.sol +14 -21
  30. package/commands/Repay.sol +120 -24
  31. package/commands/Settle.sol +10 -14
  32. package/commands/Withdraw.sol +5 -7
  33. package/commands/admin/AllowAssets.sol +5 -7
  34. package/commands/admin/Allowance.sol +5 -7
  35. package/commands/admin/Annotate.sol +5 -7
  36. package/commands/admin/Appoint.sol +5 -7
  37. package/commands/admin/Authorize.sol +5 -7
  38. package/commands/admin/Base.sol +12 -3
  39. package/commands/admin/DenyAssets.sol +5 -7
  40. package/commands/admin/Dismiss.sol +5 -7
  41. package/commands/admin/Execute.sol +5 -7
  42. package/commands/admin/Unauthorize.sol +5 -7
  43. package/core/Access.sol +8 -0
  44. package/core/Calls.sol +72 -3
  45. package/core/Portal.sol +2 -2
  46. package/core/Types.sol +8 -0
  47. package/events/Positioned.sol +22 -0
  48. package/execution/Execution.sol +66 -1
  49. package/package.json +1 -1
  50. package/ports/Allowance.sol +22 -12
  51. package/ports/Assets.sol +99 -0
  52. package/utils/Cursors.sol +3 -3
  53. package/utils/Nodes.sol +1 -1
  54. package/utils/Utils.sol +41 -31
  55. package/events/Commander.sol +0 -19
  56. package/ports/AllowAssets.sol +0 -34
  57. package/ports/DenyAssets.sol +0 -34
@@ -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
+ }
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
@@ -10,77 +10,79 @@ error ValueOverflow();
10
10
  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
+ /// @dev Thrown when an address does not contain deployed bytecode.
14
+ error InvalidContract();
13
15
 
14
- /// @notice Assert that `value` fits in uint8 and return it unchanged.
15
- function max8(uint value) pure returns (uint) {
16
+ /// @notice Assert that `value` fits in uint8 and return it as uint8.
17
+ function max8(uint value) pure returns (uint8) {
16
18
  if (value > type(uint8).max) {
17
19
  revert ValueOverflow();
18
20
  }
19
- return value;
21
+ return uint8(value);
20
22
  }
21
23
 
22
- /// @notice Assert that `value` fits in uint16 and return it unchanged.
23
- function max16(uint value) pure returns (uint) {
24
+ /// @notice Assert that `value` fits in uint16 and return it as uint16.
25
+ function max16(uint value) pure returns (uint16) {
24
26
  if (value > type(uint16).max) {
25
27
  revert ValueOverflow();
26
28
  }
27
- return value;
29
+ return uint16(value);
28
30
  }
29
31
 
30
- /// @notice Assert that `value` fits in uint24 and return it unchanged.
31
- function max24(uint value) pure returns (uint) {
32
+ /// @notice Assert that `value` fits in uint24 and return it as uint24.
33
+ function max24(uint value) pure returns (uint24) {
32
34
  if (value > type(uint24).max) {
33
35
  revert ValueOverflow();
34
36
  }
35
- return value;
37
+ return uint24(value);
36
38
  }
37
39
 
38
- /// @notice Assert that `value` fits in uint32 and return it unchanged.
39
- function max32(uint value) pure returns (uint) {
40
+ /// @notice Assert that `value` fits in uint32 and return it as uint32.
41
+ function max32(uint value) pure returns (uint32) {
40
42
  if (value > type(uint32).max) {
41
43
  revert ValueOverflow();
42
44
  }
43
- return value;
45
+ return uint32(value);
44
46
  }
45
47
 
46
- /// @notice Assert that `value` fits in uint40 and return it unchanged.
47
- function max40(uint value) pure returns (uint) {
48
+ /// @notice Assert that `value` fits in uint40 and return it as uint40.
49
+ function max40(uint value) pure returns (uint40) {
48
50
  if (value > type(uint40).max) {
49
51
  revert ValueOverflow();
50
52
  }
51
- return value;
53
+ return uint40(value);
52
54
  }
53
55
 
54
- /// @notice Assert that `value` fits in uint64 and return it unchanged.
55
- function max64(uint value) pure returns (uint) {
56
+ /// @notice Assert that `value` fits in uint64 and return it as uint64.
57
+ function max64(uint value) pure returns (uint64) {
56
58
  if (value > type(uint64).max) {
57
59
  revert ValueOverflow();
58
60
  }
59
- return value;
61
+ return uint64(value);
60
62
  }
61
63
 
62
- /// @notice Assert that `value` fits in uint96 and return it unchanged.
63
- function max96(uint value) pure returns (uint) {
64
+ /// @notice Assert that `value` fits in uint96 and return it as uint96.
65
+ function max96(uint value) pure returns (uint96) {
64
66
  if (value > type(uint96).max) {
65
67
  revert ValueOverflow();
66
68
  }
67
- return value;
69
+ return uint96(value);
68
70
  }
69
71
 
70
- /// @notice Assert that `value` fits in uint128 and return it unchanged.
71
- function max128(uint value) pure returns (uint) {
72
+ /// @notice Assert that `value` fits in uint128 and return it as uint128.
73
+ function max128(uint value) pure returns (uint128) {
72
74
  if (value > type(uint128).max) {
73
75
  revert ValueOverflow();
74
76
  }
75
- return value;
77
+ return uint128(value);
76
78
  }
77
79
 
78
- /// @notice Assert that `value` fits in uint160 and return it unchanged.
79
- function max160(uint value) pure returns (uint) {
80
+ /// @notice Assert that `value` fits in uint160 and return it as uint160.
81
+ function max160(uint value) pure returns (uint160) {
80
82
  if (value > type(uint160).max) {
81
83
  revert ValueOverflow();
82
84
  }
83
- return value;
85
+ return uint160(value);
84
86
  }
85
87
 
86
88
  // Packed fields
@@ -108,25 +110,25 @@ function clear64(uint value, uint shift) pure returns (uint) {
108
110
  /// @notice Replace the 8-bit field beginning at `shift` with `field`.
109
111
  /// @dev Reverts when `field` does not fit in 8 bits.
110
112
  function replace8(uint value, uint shift, uint field) pure returns (uint) {
111
- return clear8(value, shift) | (max8(field) << shift);
113
+ return clear8(value, shift) | (uint(max8(field)) << shift);
112
114
  }
113
115
 
114
116
  /// @notice Replace the 16-bit field beginning at `shift` with `field`.
115
117
  /// @dev Reverts when `field` does not fit in 16 bits.
116
118
  function replace16(uint value, uint shift, uint field) pure returns (uint) {
117
- return clear16(value, shift) | (max16(field) << shift);
119
+ return clear16(value, shift) | (uint(max16(field)) << shift);
118
120
  }
119
121
 
120
122
  /// @notice Replace the 32-bit field beginning at `shift` with `field`.
121
123
  /// @dev Reverts when `field` does not fit in 32 bits.
122
124
  function replace32(uint value, uint shift, uint field) pure returns (uint) {
123
- return clear32(value, shift) | (max32(field) << shift);
125
+ return clear32(value, shift) | (uint(max32(field)) << shift);
124
126
  }
125
127
 
126
128
  /// @notice Replace the 64-bit field beginning at `shift` with `field`.
127
129
  /// @dev Reverts when `field` does not fit in 64 bits.
128
130
  function replace64(uint value, uint shift, uint field) pure returns (uint) {
129
- return clear64(value, shift) | (max64(field) << shift);
131
+ return clear64(value, shift) | (uint(max64(field)) << shift);
130
132
  }
131
133
 
132
134
  /// @notice Assert that `n` is evenly divisible by `divisor`.
@@ -146,6 +148,14 @@ function ensureAddr(address addr) pure returns (address) {
146
148
  return addr;
147
149
  }
148
150
 
151
+ /// @notice Assert that `target` contains deployed bytecode and return it unchanged.
152
+ /// @dev Rejects EOAs, zero and future deployment addresses, contracts currently
153
+ /// under construction, and precompiles whose code length is zero.
154
+ function ensureContract(address target) view returns (address) {
155
+ if (target.code.length == 0) revert InvalidContract();
156
+ return target;
157
+ }
158
+
149
159
  /// @notice Convert a signed integer to its 32-byte two's-complement representation.
150
160
  function intToBytes32(int value) pure returns (bytes32) {
151
161
  return bytes32(uint(value));
@@ -1,19 +0,0 @@
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 when a commander is announced for a chain/domain.
7
- abstract contract CommanderEvent is EventEmitter {
8
- string private constant ABI = "event Commander(uint indexed host, uint chain, bytes32 native, bytes32 admin)";
9
-
10
- /// @param host Commander host node ID for the chain.
11
- /// @param chain Chain/domain node ID.
12
- /// @param native Native asset ID for the chain.
13
- /// @param admin Admin account for the commander host on the chain.
14
- event Commander(uint indexed host, uint chain, bytes32 native, bytes32 admin);
15
-
16
- constructor() {
17
- emit EventAbi(ABI);
18
- }
19
- }
@@ -1,34 +0,0 @@
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 {Specs} from "../Codec.sol";
7
- import {Execution, Executions, Lanes} from "../execution/Execution.sol";
8
-
9
- using Executions for Execution;
10
-
11
- /// @title AllowAssetsPort
12
- /// @notice Port that permits a list of assets on behalf of a peer host.
13
- /// Each ASSET block in the input calls `allowAsset`. Restricted to trusted peers.
14
- abstract contract AllowAssetsPort is PortBase, AllowAssetsHook {
15
- uint private immutable descriptor;
16
-
17
- constructor() {
18
- (, descriptor) = port("portAllowAssets", Specs.Asset, Specs.Empty, 0);
19
- }
20
-
21
- /// @notice Execute the allow-assets peer call.
22
- /// @param data ASSET block stream supplied by the trusted peer.
23
- /// @return Empty response bytes.
24
- function portAllowAssets(bytes calldata data) external onlyPeer returns (bytes memory) {
25
- Execution memory exec = openInput(data, descriptor, 0);
26
-
27
- while (exec.more()) {
28
- bytes32 asset = exec.unpackAsset(Lanes.Input);
29
- allowAsset(asset);
30
- }
31
-
32
- return "";
33
- }
34
- }
@@ -1,34 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- import {PortBase} from "./Base.sol";
5
- import {DenyAssetsHook} from "../commands/admin/DenyAssets.sol";
6
- import {Specs} from "../Codec.sol";
7
- import {Execution, Executions, Lanes} from "../execution/Execution.sol";
8
-
9
- using Executions for Execution;
10
-
11
- /// @title DenyAssetsPort
12
- /// @notice Port that blocks a list of assets on behalf of a peer host.
13
- /// Each ASSET block in the input calls `denyAsset`. Restricted to trusted peers.
14
- abstract contract DenyAssetsPort is PortBase, DenyAssetsHook {
15
- uint private immutable descriptor;
16
-
17
- constructor() {
18
- (, descriptor) = port("portDenyAssets", Specs.Asset, Specs.Empty, 0);
19
- }
20
-
21
- /// @notice Execute the deny-assets peer call.
22
- /// @param data ASSET block stream supplied by the trusted peer.
23
- /// @return Empty response bytes.
24
- function portDenyAssets(bytes calldata data) external onlyPeer returns (bytes memory) {
25
- Execution memory exec = openInput(data, descriptor, 0);
26
-
27
- while (exec.more()) {
28
- bytes32 asset = exec.unpackAsset(Lanes.Input);
29
- denyAsset(asset);
30
- }
31
-
32
- return "";
33
- }
34
- }