@rootzero/contracts 1.0.1 → 1.1.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 ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ Until the protocol reaches integration-stable status, minor versions may include
4
+ breaking API changes. Breaking changes are called out explicitly.
5
+
6
+ ## 1.1.0
7
+
8
+ ### Breaking Changes
9
+
10
+ - Renamed local execution fields from `value` to `resources` in PIPE, CALL, and STEP schemas.
11
+ - Interprets EVM value as the low 128 bits of packed `resources`.
12
+ - Changed native value APIs and dispatch hooks to use `uint128` for actual EVM value.
13
+ - Replaced the relay-specific hook with shared `DispatchPayableHook`.
14
+ - `RelayPayable` now dispatches an encoded PIPE payload and settles leftover user command value.
package/Endpoints.sol CHANGED
@@ -16,7 +16,7 @@ import { DebitAccount, DebitAccountHook } from "./commands/Debit.sol";
16
16
  import { Deposit, DepositHook, DepositPayable, DepositPayableHook } from "./commands/Deposit.sol";
17
17
  import { Payout, PayoutHook } from "./commands/Payout.sol";
18
18
  import { Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook } from "./commands/Provision.sol";
19
- import { RelayPayable, RelayPayableHook } from "./commands/Relay.sol";
19
+ import { RelayPayable, DispatchPayableHook } from "./commands/Relay.sol";
20
20
  import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
21
21
 
22
22
  // Admin commands
@@ -518,20 +518,20 @@ library Cursors {
518
518
 
519
519
  /// @notice Encode a STEP block.
520
520
  /// @param target Command target identifier.
521
- /// @param value Native value forwarded with the step.
521
+ /// @param resources Chain resources assigned to the step.
522
522
  /// @param request Raw nested request payload.
523
523
  /// @return Encoded STEP block bytes.
524
- function toStepBlock(uint target, uint value, bytes memory request) internal pure returns (bytes memory) {
525
- return createBlock(Keys.Step, bytes.concat(bytes32(target), bytes32(value), toBytesBlock(request)));
524
+ function toStepBlock(uint target, uint resources, bytes memory request) internal pure returns (bytes memory) {
525
+ return createBlock(Keys.Step, bytes.concat(bytes32(target), bytes32(resources), toBytesBlock(request)));
526
526
  }
527
527
 
528
528
  /// @notice Encode a CALL block.
529
529
  /// @param target Target node identifier.
530
- /// @param value Native value forwarded with the call.
530
+ /// @param resources Chain resources assigned to the call.
531
531
  /// @param data Raw calldata payload for the target.
532
532
  /// @return Encoded CALL block bytes.
533
- function toCallBlock(uint target, uint value, bytes memory data) internal pure returns (bytes memory) {
534
- return createBlock(Keys.Call, bytes.concat(bytes32(target), bytes32(value), toBytesBlock(data)));
533
+ function toCallBlock(uint target, uint resources, bytes memory data) internal pure returns (bytes memory) {
534
+ return createBlock(Keys.Call, bytes.concat(bytes32(target), bytes32(resources), toBytesBlock(data)));
535
535
  }
536
536
 
537
537
  /// @notice Encode a CONTEXT block.
@@ -548,37 +548,37 @@ library Cursors {
548
548
  }
549
549
 
550
550
  /// @notice Encode a PIPE block.
551
- /// @param value Native value assigned to the pipe.
551
+ /// @param resources Chain resources assigned to the pipe.
552
552
  /// @param account Command account identifier.
553
553
  /// @param state Embedded state block stream.
554
554
  /// @param steps Embedded step block stream.
555
555
  /// @return Encoded PIPE block bytes.
556
556
  function toPipeBlock(
557
- uint value,
557
+ uint resources,
558
558
  bytes32 account,
559
559
  bytes memory state,
560
560
  bytes memory steps
561
561
  ) internal pure returns (bytes memory) {
562
- return createBlock(Keys.Pipe, bytes.concat(bytes32(value), toContextBlock(account, state, steps)));
563
- }
564
-
565
- /// @notice Encode a RELAY block.
566
- /// @param chain Destination chain node ID.
567
- /// @param resources Chain-adapter-specific resources for the destination pipe.
568
- /// @param steps Nested step block stream.
569
- /// @return Encoded RELAY block bytes.
570
- function toRelayBlock(uint chain, uint resources, bytes memory steps) internal pure returns (bytes memory) {
571
- return createBlock(Keys.Relay, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(steps)));
572
- }
573
-
574
- /// @notice Encode a DISPATCH block.
575
- /// @param chain Destination chain node ID.
576
- /// @param resources Chain-adapter-specific resources for the destination dispatch.
577
- /// @param payload Encoded cross-chain payload.
578
- /// @return Encoded DISPATCH block bytes.
579
- function toDispatchBlock(uint chain, uint resources, bytes memory payload) internal pure returns (bytes memory) {
580
- return createBlock(Keys.Dispatch, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(payload)));
581
- }
562
+ return createBlock(Keys.Pipe, bytes.concat(bytes32(resources), toContextBlock(account, state, steps)));
563
+ }
564
+
565
+ /// @notice Encode a RELAY block.
566
+ /// @param chain Destination chain node ID.
567
+ /// @param resources Chain-adapter-specific resources for the destination pipe.
568
+ /// @param steps Nested step block stream.
569
+ /// @return Encoded RELAY block bytes.
570
+ function toRelayBlock(uint chain, uint resources, bytes memory steps) internal pure returns (bytes memory) {
571
+ return createBlock(Keys.Relay, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(steps)));
572
+ }
573
+
574
+ /// @notice Encode a DISPATCH block.
575
+ /// @param chain Destination chain node ID.
576
+ /// @param resources Chain-adapter-specific resources for the destination dispatch.
577
+ /// @param payload Encoded cross-chain payload.
578
+ /// @return Encoded DISPATCH block bytes.
579
+ function toDispatchBlock(uint chain, uint resources, bytes memory payload) internal pure returns (bytes memory) {
580
+ return createBlock(Keys.Dispatch, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(payload)));
581
+ }
582
582
 
583
583
  // -------------------------------------------------------------------------
584
584
  // Raw calldata loaders
@@ -590,31 +590,31 @@ library Cursors {
590
590
  /// @param cur Cursor whose current position is advanced by `n` bytes.
591
591
  /// @param n Number of bytes to advance.
592
592
  /// @return value Loaded word.
593
- function read(Cur memory cur, uint n) internal pure returns (bytes32 value) {
594
- uint abs = cur.offset + cur.i;
595
- assembly ("memory-safe") {
596
- value := calldataload(abs)
597
- }
598
- cur.i += n;
599
- }
600
-
601
- /// @notice Read the next 4 bytes from the cursor and advance by 4 bytes.
602
- /// @dev Performs no bounds, key, length, or cursor checks.
603
- /// @param cur Cursor whose current position is advanced by 4 bytes.
604
- /// @return value Loaded bytes4 value.
605
- function read4(Cur memory cur) internal pure returns (bytes4 value) {
606
- uint abs = cur.offset + cur.i;
607
- assembly ("memory-safe") {
608
- value := calldataload(abs)
609
- }
610
- cur.i += 4;
611
- }
612
-
613
- /// @notice Read the next 16 bytes from the cursor and advance by 16 bytes.
614
- /// @dev Performs no bounds, key, length, or cursor checks.
615
- /// @param cur Cursor whose current position is advanced by 16 bytes.
616
- /// @return value Loaded bytes16 value.
617
- function read16(Cur memory cur) internal pure returns (bytes16 value) {
593
+ function read(Cur memory cur, uint n) internal pure returns (bytes32 value) {
594
+ uint abs = cur.offset + cur.i;
595
+ assembly ("memory-safe") {
596
+ value := calldataload(abs)
597
+ }
598
+ cur.i += n;
599
+ }
600
+
601
+ /// @notice Read the next 4 bytes from the cursor and advance by 4 bytes.
602
+ /// @dev Performs no bounds, key, length, or cursor checks.
603
+ /// @param cur Cursor whose current position is advanced by 4 bytes.
604
+ /// @return value Loaded bytes4 value.
605
+ function read4(Cur memory cur) internal pure returns (bytes4 value) {
606
+ uint abs = cur.offset + cur.i;
607
+ assembly ("memory-safe") {
608
+ value := calldataload(abs)
609
+ }
610
+ cur.i += 4;
611
+ }
612
+
613
+ /// @notice Read the next 16 bytes from the cursor and advance by 16 bytes.
614
+ /// @dev Performs no bounds, key, length, or cursor checks.
615
+ /// @param cur Cursor whose current position is advanced by 16 bytes.
616
+ /// @return value Loaded bytes16 value.
617
+ function read16(Cur memory cur) internal pure returns (bytes16 value) {
618
618
  uint abs = cur.offset + cur.i;
619
619
  assembly ("memory-safe") {
620
620
  value := calldataload(abs)
@@ -626,30 +626,30 @@ library Cursors {
626
626
  /// @dev Performs no bounds, key, length, or cursor checks.
627
627
  /// @param cur Cursor whose current position is advanced by 32 bytes.
628
628
  /// @return value Loaded word.
629
- function read32(Cur memory cur) internal pure returns (bytes32 value) {
630
- uint abs = cur.offset + cur.i;
631
- assembly ("memory-safe") {
632
- value := calldataload(abs)
633
- }
634
- cur.i += 32;
635
- }
636
-
637
- /// @notice Read the next uint from the cursor and advance by one word.
638
- /// @dev Performs no bounds, key, length, or cursor checks.
639
- /// @param cur Cursor whose current position is advanced by 32 bytes.
640
- /// @return value Loaded uint value.
641
- function readUint(Cur memory cur) internal pure returns (uint value) {
642
- uint abs = cur.offset + cur.i;
643
- assembly ("memory-safe") {
644
- value := calldataload(abs)
645
- }
646
- cur.i += 32;
647
- }
648
-
649
- /// @notice Read the next two 32-byte words from the cursor and advance by 64 bytes.
650
- /// @dev Performs no bounds, key, length, or cursor checks.
651
- /// @param cur Cursor whose current position is advanced by 64 bytes.
652
- /// @return a First loaded word.
629
+ function read32(Cur memory cur) internal pure returns (bytes32 value) {
630
+ uint abs = cur.offset + cur.i;
631
+ assembly ("memory-safe") {
632
+ value := calldataload(abs)
633
+ }
634
+ cur.i += 32;
635
+ }
636
+
637
+ /// @notice Read the next uint from the cursor and advance by one word.
638
+ /// @dev Performs no bounds, key, length, or cursor checks.
639
+ /// @param cur Cursor whose current position is advanced by 32 bytes.
640
+ /// @return value Loaded uint value.
641
+ function readUint(Cur memory cur) internal pure returns (uint value) {
642
+ uint abs = cur.offset + cur.i;
643
+ assembly ("memory-safe") {
644
+ value := calldataload(abs)
645
+ }
646
+ cur.i += 32;
647
+ }
648
+
649
+ /// @notice Read the next two 32-byte words from the cursor and advance by 64 bytes.
650
+ /// @dev Performs no bounds, key, length, or cursor checks.
651
+ /// @param cur Cursor whose current position is advanced by 64 bytes.
652
+ /// @return a First loaded word.
653
653
  /// @return b Second loaded word.
654
654
  function read64(Cur memory cur) internal pure returns (bytes32 a, bytes32 b) {
655
655
  uint abs = cur.offset + cur.i;
@@ -1079,12 +1079,12 @@ library Cursors {
1079
1079
  /// The `req` slice is the raw payload of the block's required BYTES child.
1080
1080
  /// @param cur Cursor; advanced past the block.
1081
1081
  /// @return target Destination node ID for the sub-command.
1082
- /// @return value Native value to forward with the call.
1082
+ /// @return resources Chain resources assigned to the step.
1083
1083
  /// @return req Embedded request bytes for the sub-command.
1084
- function unpackStep(Cur memory cur) internal pure returns (uint target, uint value, bytes calldata req) {
1084
+ function unpackStep(Cur memory cur) internal pure returns (uint target, uint resources, bytes calldata req) {
1085
1085
  uint end = cur.enter(Keys.Step, 64 + Sizes.Header, 0);
1086
1086
  target = uint(cur.read32());
1087
- value = uint(cur.read32());
1087
+ resources = uint(cur.read32());
1088
1088
  req = cur.unpackBytes();
1089
1089
  cur.exit(end);
1090
1090
  }
@@ -1093,12 +1093,12 @@ library Cursors {
1093
1093
  /// The `data` slice is the raw payload of the block's required BYTES child.
1094
1094
  /// @param cur Cursor; advanced past the block.
1095
1095
  /// @return target Target node ID to call.
1096
- /// @return value Native value to forward with the call.
1096
+ /// @return resources Chain resources assigned to the call.
1097
1097
  /// @return data Raw calldata payload for the target.
1098
- function unpackCall(Cur memory cur) internal pure returns (uint target, uint value, bytes calldata data) {
1098
+ function unpackCall(Cur memory cur) internal pure returns (uint target, uint resources, bytes calldata data) {
1099
1099
  uint end = cur.enter(Keys.Call, 64 + Sizes.Header, 0);
1100
1100
  target = uint(cur.read32());
1101
- value = uint(cur.read32());
1101
+ resources = uint(cur.read32());
1102
1102
  data = cur.unpackBytes();
1103
1103
  cur.exit(end);
1104
1104
  }
@@ -1119,50 +1119,50 @@ library Cursors {
1119
1119
  cur.exit(end);
1120
1120
  }
1121
1121
 
1122
- /// @notice Consume a PIPE block and return its value and context fields.
1122
+ /// @notice Consume a PIPE block and return its resources and context fields.
1123
1123
  /// @param cur Cursor; advanced past the block.
1124
- /// @return value Native value assigned to the pipe.
1124
+ /// @return resources Chain resources assigned to the pipe.
1125
1125
  /// @return account Command account identifier.
1126
1126
  /// @return state Embedded state block stream.
1127
1127
  /// @return steps Embedded step block stream.
1128
1128
  function unpackPipe(
1129
1129
  Cur memory cur
1130
- ) internal pure returns (uint value, bytes32 account, bytes calldata state, bytes calldata steps) {
1130
+ ) internal pure returns (uint resources, bytes32 account, bytes calldata state, bytes calldata steps) {
1131
1131
  uint end = cur.enter(Keys.Pipe, 32 + Sizes.Header + 32 + 2 * Sizes.Header, 0);
1132
- value = uint(cur.read32());
1132
+ resources = uint(cur.read32());
1133
1133
  (account, state, steps) = cur.unpackContext();
1134
1134
  cur.exit(end);
1135
1135
  }
1136
1136
 
1137
- /// @notice Consume a RELAY block and return its destination chain, resources, and step stream.
1138
- /// @param cur Cursor; advanced past the block.
1139
- /// @return chain Destination chain node ID.
1140
- /// @return resources Chain-adapter-specific resources for the destination pipe.
1141
- /// @return steps Embedded step block stream.
1142
- function unpackRelay(
1143
- Cur memory cur
1144
- ) internal pure returns (uint chain, uint resources, bytes calldata steps) {
1145
- uint end = cur.enter(Keys.Relay, 64 + Sizes.Header, 0);
1146
- chain = cur.readUint();
1147
- resources = cur.readUint();
1148
- steps = cur.unpackBytes();
1149
- cur.exit(end);
1150
- }
1151
-
1152
- /// @notice Consume a DISPATCH block and return its destination chain, resources, and payload.
1153
- /// @param cur Cursor; advanced past the block.
1154
- /// @return chain Destination chain node ID.
1155
- /// @return resources Chain-adapter-specific resources for the destination dispatch.
1156
- /// @return payload Encoded cross-chain payload.
1157
- function unpackDispatch(
1158
- Cur memory cur
1159
- ) internal pure returns (uint chain, uint resources, bytes calldata payload) {
1160
- uint end = cur.enter(Keys.Dispatch, 64 + Sizes.Header, 0);
1161
- chain = cur.readUint();
1162
- resources = cur.readUint();
1163
- payload = cur.unpackBytes();
1164
- cur.exit(end);
1165
- }
1137
+ /// @notice Consume a RELAY block and return its destination chain, resources, and step stream.
1138
+ /// @param cur Cursor; advanced past the block.
1139
+ /// @return chain Destination chain node ID.
1140
+ /// @return resources Chain-adapter-specific resources for the destination pipe.
1141
+ /// @return steps Embedded step block stream.
1142
+ function unpackRelay(
1143
+ Cur memory cur
1144
+ ) internal pure returns (uint chain, uint resources, bytes calldata steps) {
1145
+ uint end = cur.enter(Keys.Relay, 64 + Sizes.Header, 0);
1146
+ chain = cur.readUint();
1147
+ resources = cur.readUint();
1148
+ steps = cur.unpackBytes();
1149
+ cur.exit(end);
1150
+ }
1151
+
1152
+ /// @notice Consume a DISPATCH block and return its destination chain, resources, and payload.
1153
+ /// @param cur Cursor; advanced past the block.
1154
+ /// @return chain Destination chain node ID.
1155
+ /// @return resources Chain-adapter-specific resources for the destination dispatch.
1156
+ /// @return payload Encoded cross-chain payload.
1157
+ function unpackDispatch(
1158
+ Cur memory cur
1159
+ ) internal pure returns (uint chain, uint resources, bytes calldata payload) {
1160
+ uint end = cur.enter(Keys.Dispatch, 64 + Sizes.Header, 0);
1161
+ chain = cur.readUint();
1162
+ resources = cur.readUint();
1163
+ payload = cur.unpackBytes();
1164
+ cur.exit(end);
1165
+ }
1166
1166
 
1167
1167
  // Type-specific validators
1168
1168
 
@@ -1385,6 +1385,27 @@ library Cursors {
1385
1385
  if (uint(bytes32(msg.data[abs + 128:abs + 160])) < amount) revert UnexpectedValue();
1386
1386
  }
1387
1387
 
1388
+ // -------------------------------------------------------------------------
1389
+ // Transform helpers
1390
+ // -------------------------------------------------------------------------
1391
+
1392
+ /// @notice Consume a RELAY block and encode its destination pipe payload.
1393
+ /// @param cur Cursor; advanced past the RELAY block.
1394
+ /// @param account Account identifier to embed in the destination pipe context.
1395
+ /// @param state State block stream to embed in the destination pipe context.
1396
+ /// @return chain Destination chain node ID.
1397
+ /// @return resources Chain resources assigned to the destination pipe.
1398
+ /// @return pipe Encoded PIPE block containing `account`, `state`, and relay steps.
1399
+ function relayToPipe(
1400
+ Cur memory cur,
1401
+ bytes32 account,
1402
+ bytes calldata state
1403
+ ) internal pure returns (uint chain, uint resources, bytes memory pipe) {
1404
+ bytes calldata steps;
1405
+ (chain, resources, steps) = cur.unpackRelay();
1406
+ pipe = toPipeBlock(resources, account, bytes(state), bytes(steps));
1407
+ }
1408
+
1388
1409
  // -------------------------------------------------------------------------
1389
1410
  // Search helpers
1390
1411
  // -------------------------------------------------------------------------
package/blocks/Keys.sol CHANGED
@@ -37,17 +37,17 @@ library Keys {
37
37
  bytes4 constant Account = bytes4(keccak256("#account"));
38
38
  /// @dev Transfer record passed through the pipeline - (bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)
39
39
  bytes4 constant Transaction = bytes4(keccak256("#transaction"));
40
- /// @dev Sub-command invocation - (uint target, uint value, #bytes as request)
40
+ /// @dev Sub-command invocation - (uint target, uint resources, #bytes as request)
41
41
  bytes4 constant Step = bytes4(keccak256("#step"));
42
- /// @dev Cross-chain pipe relay - (uint chain, uint resources, #bytes as steps)
43
- bytes4 constant Relay = bytes4(keccak256("#relay"));
44
- /// @dev Cross-chain encoded payload dispatch - (uint chain, uint resources, #bytes as payload)
45
- bytes4 constant Dispatch = bytes4(keccak256("#dispatch"));
46
- /// @dev Raw external call - (uint target, uint value, #bytes as payload)
42
+ /// @dev Cross-chain pipe relay - (uint chain, uint resources, #bytes as steps)
43
+ bytes4 constant Relay = bytes4(keccak256("#relay"));
44
+ /// @dev Cross-chain encoded payload dispatch - (uint chain, uint resources, #bytes as payload)
45
+ bytes4 constant Dispatch = bytes4(keccak256("#dispatch"));
46
+ /// @dev Raw external call - (uint target, uint resources, #bytes as payload)
47
47
  bytes4 constant Call = bytes4(keccak256("#call"));
48
48
  /// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
49
49
  bytes4 constant Context = bytes4(keccak256("#context"));
50
- /// @dev Pipeline invocation - (uint value, #context)
50
+ /// @dev Pipeline invocation - (uint resources, #context)
51
51
  bytes4 constant Pipe = bytes4(keccak256("#pipe"));
52
52
  /// @dev Authentication proof - (uint cid, uint deadline, #bytes as proof); must appear last in its segment
53
53
  bytes4 constant Auth = bytes4(keccak256("#auth"));
package/blocks/Schema.sol CHANGED
@@ -18,6 +18,9 @@ pragma solidity ^0.8.33;
18
18
  // - run items may repeat at top level for batching
19
19
  // - `maybe #x { ... }` marks an optional block item
20
20
  // - `many #x { ... }` emits one generic list block containing repeated `#x` items
21
+ // - `resources` fields are chain-specific resource words; one chain type may
22
+ // pack them differently from another, but a given chain type must use one
23
+ // stable format everywhere. EVM resources use the low 128 bits as native value.
21
24
  // - fixed fields are packed in declaration order
22
25
  // - blocks have fixed fields followed by a dynamic child-block tail
23
26
  // - child block tails are embedded directly, without an extra stream wrapper
@@ -62,11 +65,11 @@ library Schemas {
62
65
  string constant Allowance = "#allowance { uint host, bytes32 asset, bytes32 meta, uint amount }";
63
66
  string constant Transaction = "#transaction { bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount }";
64
67
  string constant Context = "#context { bytes32 account, #bytes as state, #bytes as request }";
65
- string constant Pipe = "#pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as steps } }";
66
- string constant Call = "#call { uint target, uint value, #bytes as payload }";
67
- string constant Step = "#step { uint target, uint value, #bytes as request }";
68
- string constant Relay = "#relay { uint chain, uint resources, #bytes as steps }";
69
- string constant Dispatch = "#dispatch { uint chain, uint resources, #bytes as payload }";
68
+ string constant Pipe = "#pipe { uint resources, #context { bytes32 account, #bytes as state, #bytes as steps } }";
69
+ string constant Call = "#call { uint target, uint resources, #bytes as payload }";
70
+ string constant Step = "#step { uint target, uint resources, #bytes as request }";
71
+ string constant Relay = "#relay { uint chain, uint resources, #bytes as steps }";
72
+ string constant Dispatch = "#dispatch { uint chain, uint resources, #bytes as payload }";
70
73
  string constant Bounty = "#bounty { uint amount, bytes32 relayer }";
71
74
  string constant Fee = "#fee { uint amount }";
72
75
  string constant Auth = "#auth { uint cid, uint deadline, #bytes as proof }";
@@ -865,19 +865,19 @@ library Writers {
865
865
  /// @notice Append a STEP block with a nested request BYTES payload.
866
866
  /// @param writer Destination writer; `i` is advanced by the encoded STEP block length.
867
867
  /// @param target Command target identifier.
868
- /// @param value Native value forwarded with the step.
868
+ /// @param resources Chain resources assigned to the step.
869
869
  /// @param request Raw nested request payload.
870
- function appendStep(Writer memory writer, uint target, uint value, bytes memory request) internal pure {
871
- appendBlock64Bytes(writer, Keys.Step, bytes32(target), bytes32(value), request);
870
+ function appendStep(Writer memory writer, uint target, uint resources, bytes memory request) internal pure {
871
+ appendBlock64Bytes(writer, Keys.Step, bytes32(target), bytes32(resources), request);
872
872
  }
873
873
 
874
874
  /// @notice Append a CALL block with a nested payload BYTES block.
875
875
  /// @param writer Destination writer; `i` is advanced by the encoded CALL block length.
876
876
  /// @param target Call target identifier.
877
- /// @param value Native value forwarded with the call.
877
+ /// @param resources Chain resources assigned to the call.
878
878
  /// @param data Raw nested call payload.
879
- function appendCall(Writer memory writer, uint target, uint value, bytes memory data) internal pure {
880
- appendBlock64Bytes(writer, Keys.Call, bytes32(target), bytes32(value), data);
879
+ function appendCall(Writer memory writer, uint target, uint resources, bytes memory data) internal pure {
880
+ appendBlock64Bytes(writer, Keys.Call, bytes32(target), bytes32(resources), data);
881
881
  }
882
882
 
883
883
  /// @notice Append a CONTEXT block with nested state/request BYTES payloads.
@@ -891,13 +891,13 @@ library Writers {
891
891
 
892
892
  /// @notice Append a PIPE block with a nested CONTEXT block.
893
893
  /// @param writer Destination writer; `i` is advanced by the encoded PIPE block length.
894
- /// @param value Native value assigned to the pipe.
894
+ /// @param resources Chain resources assigned to the pipe.
895
895
  /// @param account Command account identifier.
896
896
  /// @param state Raw nested state payload.
897
897
  /// @param steps Raw nested step payload.
898
898
  function appendPipe(
899
899
  Writer memory writer,
900
- uint value,
900
+ uint resources,
901
901
  bytes32 account,
902
902
  bytes memory state,
903
903
  bytes memory steps
@@ -909,7 +909,7 @@ library Writers {
909
909
 
910
910
  uint p = writeHeader(writer.dst, i, Keys.Pipe, uint32(max32(len)));
911
911
  assembly ("memory-safe") {
912
- mstore(add(p, 0x08), value)
912
+ mstore(add(p, 0x08), resources)
913
913
  }
914
914
 
915
915
  writeBlock32BytesBytes(writer.dst, i + Sizes.Header + 32, Keys.Context, account, state, steps);
@@ -8,24 +8,15 @@ import {Budget} from "../utils/Value.sol";
8
8
 
9
9
  using Cursors for Cur;
10
10
 
11
- abstract contract RelayPayableHook {
12
- /// @notice Override to relay `steps` to `chain` with the current account and state.
13
- /// @param chain Destination chain node ID.
14
- /// @param resources Chain-adapter-specific destination resources. EVM adapters
15
- /// may interpret this as packed execution gas and destination value.
16
- /// @param account Command account identifier.
17
- /// @param state Current command state block stream.
18
- /// @param steps Embedded destination step block stream.
19
- /// @param budget Source-chain native-value budget available for transport
20
- /// fees and destination resource funding.
21
- function relay(
22
- uint chain,
23
- uint resources,
24
- bytes32 account,
25
- bytes calldata state,
26
- bytes calldata steps,
27
- Budget memory budget
28
- ) internal virtual;
11
+ abstract contract DispatchPayableHook {
12
+ /// @notice Override to dispatch an encoded payload to `chain`.
13
+ /// @param chain Destination chain node ID.
14
+ /// @param resources Chain-adapter-specific destination resources. EVM adapters
15
+ /// may interpret this as packed execution gas and destination value.
16
+ /// @param payload Encoded payload ready for the transport layer.
17
+ /// @param budget Source-chain native-value budget available for transport
18
+ /// fees and destination resource funding.
19
+ function dispatch(uint chain, uint resources, bytes memory payload, Budget memory budget) internal virtual;
29
20
  }
30
21
 
31
22
  /// @title RelayPayable
@@ -33,7 +24,7 @@ abstract contract RelayPayableHook {
33
24
  /// Reverts unless the request contains exactly one RELAY block, preventing
34
25
  /// the same state from being duplicated across multiple relays.
35
26
  /// Produces no output state.
36
- abstract contract RelayPayable is CommandBase, Payable, RelayPayableHook {
27
+ abstract contract RelayPayable is CommandBase, Payable, DispatchPayableHook {
37
28
  string private constant NAME = "relayPayable";
38
29
 
39
30
  uint internal immutable relayPayableId = commandId(NAME);
@@ -46,12 +37,14 @@ abstract contract RelayPayable is CommandBase, Payable, RelayPayableHook {
46
37
  /// @param c Command context; `c.request` must contain exactly one RELAY block.
47
38
  /// @return output Empty output state.
48
39
  function relayPayable(CommandContext calldata c) external payable onlyCommand returns (bytes memory output) {
49
- (Cur memory request, ) = Cursors.init(c.request, 0, 1, 1);
50
- Budget memory budget = valueBudget();
51
-
52
- (uint chain, uint resources, bytes calldata steps) = request.unpackRelay();
53
- relay(chain, resources, c.account, c.state, steps, budget);
54
- request.complete();
55
- return "";
56
- }
57
- }
40
+ (Cur memory request, ) = Cursors.init(c.request, 0, 1, 1);
41
+ Budget memory budget = valueBudget();
42
+
43
+ (uint chain, uint resources, bytes memory pipe) = request.relayToPipe(c.account, c.state);
44
+ dispatch(chain, resources, pipe, budget);
45
+
46
+ settleValue(c.account, budget);
47
+ request.complete();
48
+ return "";
49
+ }
50
+ }
@@ -12,7 +12,7 @@ using Cursors for Cur;
12
12
 
13
13
  /// @title ExecutePayable
14
14
  /// @notice Admin command that forwards raw calldata to one or more target nodes.
15
- /// Each CALL block specifies a target node ID, native value, and raw calldata payload.
15
+ /// Each CALL block specifies a target node ID, chain resources, and raw calldata payload.
16
16
  /// Only callable by the admin account.
17
17
  /// Unspent top-level `msg.value` remains on this host.
18
18
  abstract contract ExecutePayable is CommandBase, Payable, AdminEvent {
@@ -32,9 +32,9 @@ abstract contract ExecutePayable is CommandBase, Payable, AdminEvent {
32
32
  Budget memory budget = valueBudget();
33
33
 
34
34
  while (request.i < request.len) {
35
- (uint target, uint value, bytes calldata data) = request.unpackCall();
35
+ (uint target, uint resources, bytes calldata data) = request.unpackCall();
36
36
  address addr = Ids.nodeAddr(target);
37
- callAddr(addr, useValue(budget, value), data);
37
+ callAddr(addr, useValue(budget, resources), data);
38
38
  }
39
39
 
40
40
  request.complete();
package/core/Calls.sol CHANGED
@@ -28,7 +28,7 @@ abstract contract NodeCalls is AccessControl {
28
28
  /// @param value Native value to forward in wei.
29
29
  /// @param data Encoded calldata to send.
30
30
  /// @return out Return data from the successful call.
31
- function callAddr(address addr, uint value, bytes memory data) internal returns (bytes memory out) {
31
+ function callAddr(address addr, uint128 value, bytes memory data) internal returns (bytes memory out) {
32
32
  bool success;
33
33
  (success, out) = payable(addr).call{value: value}(data);
34
34
  if (!success) revert FailedCall(addr, bytes4(data), out);
@@ -53,7 +53,7 @@ abstract contract NodeCalls is AccessControl {
53
53
  /// @param value Native value to forward in wei.
54
54
  /// @param data Encoded calldata to send.
55
55
  /// @return out Return data from the successful call.
56
- function callTo(uint node, uint value, bytes memory data) internal returns (bytes memory out) {
56
+ function callTo(uint node, uint128 value, bytes memory data) internal returns (bytes memory out) {
57
57
  ensureTrusted(node);
58
58
  address addr = Ids.nodeAddr(node);
59
59
  return callAddr(addr, value, data);
@@ -76,7 +76,7 @@ abstract contract NodeCalls is AccessControl {
76
76
  /// @param value Native value to forward in wei.
77
77
  /// @param ctx Command execution context.
78
78
  /// @return Decoded command output block stream.
79
- function callCommand(uint id, uint value, CommandContext memory ctx) internal returns (bytes memory) {
79
+ function callCommand(uint id, uint128 value, CommandContext memory ctx) internal returns (bytes memory) {
80
80
  bytes4 selector = Ids.commandSelector(id);
81
81
  bytes memory data = abi.encodeWithSelector(selector, ctx);
82
82
  return abi.decode(callTo(id, value, data), (bytes));
package/core/Payable.sol CHANGED
@@ -18,20 +18,22 @@ abstract contract Payable {
18
18
  return Budget({remaining: msg.value});
19
19
  }
20
20
 
21
- /// @notice Deduct `amount` from the budget and return it.
21
+ /// @notice Deduct the EVM value lane from a packed resource word and return it.
22
+ /// @dev EVM resources use the low 128 bits as native value/endowment.
22
23
  /// @param budget Mutable budget to deduct from.
23
- /// @param amount Native value to spend.
24
- /// @return The same `amount`, ready to forward to a callee.
25
- function useValue(Budget memory budget, uint amount) internal pure returns (uint) {
26
- return Values.use(budget, amount);
24
+ /// @param resources Packed chain resources.
25
+ /// @return value Native value to forward in wei.
26
+ function useValue(Budget memory budget, uint resources) internal pure returns (uint128 value) {
27
+ return Values.use(budget, uint128(resources));
27
28
  }
28
29
 
29
- /// @notice Deduct `amount` from the budget and return it as a new sub-budget.
30
+ /// @notice Deduct the EVM value lane from a packed resource word as a new sub-budget.
31
+ /// @dev EVM resources use the low 128 bits as native value/endowment.
30
32
  /// @param budget Mutable parent budget to deduct from.
31
- /// @param amount Native value to assign to the sub-budget.
32
- /// @return A new budget with `amount` remaining.
33
- function allocateValue(Budget memory budget, uint amount) internal pure returns (Budget memory) {
34
- return Values.allocate(budget, amount);
33
+ /// @param resources Packed chain resources.
34
+ /// @return A new budget with the EVM value lane remaining.
35
+ function allocateValue(Budget memory budget, uint resources) internal pure returns (Budget memory) {
36
+ return Values.allocate(budget, uint128(resources));
35
37
  }
36
38
 
37
39
  /// @notice Drains the budget and settles any remaining native value.
package/core/Pipeline.sol CHANGED
@@ -20,14 +20,14 @@ abstract contract Pipeline is Payable {
20
20
  /// @param account Account identifier for the piped context.
21
21
  /// @param state Current threaded state block stream.
22
22
  /// @param request Step request block stream.
23
- /// @param value Native value assigned to this step.
23
+ /// @param value Native EVM value assigned to this step.
24
24
  /// @return Updated state block stream for the next step.
25
25
  function dispatch(
26
26
  uint target,
27
27
  bytes32 account,
28
28
  bytes memory state,
29
29
  bytes calldata request,
30
- uint value
30
+ uint128 value
31
31
  ) internal virtual returns (bytes memory);
32
32
 
33
33
  /// @notice Execute a STEP block stream through the pipeline.
@@ -45,8 +45,8 @@ abstract contract Pipeline is Payable {
45
45
  (Cur memory input, , ) = Cursors.init(steps, 0, 1);
46
46
 
47
47
  while (input.i < input.len) {
48
- (uint target, uint value, bytes calldata request) = input.unpackStep();
49
- state = dispatch(target, account, state, request, useValue(budget, value));
48
+ (uint target, uint resources, bytes calldata request) = input.unpackStep();
49
+ state = dispatch(target, account, state, request, useValue(budget, resources));
50
50
  }
51
51
 
52
52
  if (state.length != 0) revert UnexpectedState();
package/docs/Schema.md CHANGED
@@ -56,9 +56,9 @@ A block payload has fixed fields first, followed by an optional child-block tail
56
56
  Once a child block appears, no more fixed fields may follow.
57
57
 
58
58
  ```txt
59
- #call { uint target, uint value, #bytes as payload }
59
+ #call { uint target, uint resources, #bytes as payload }
60
60
  #context { bytes32 account, #bytes as state, #bytes as request }
61
- #pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as request } }
61
+ #pipe { uint resources, #context { bytes32 account, #bytes as state, #bytes as steps } }
62
62
  ```
63
63
 
64
64
  The tail is embedded directly as child block bytes. There is no wrapper around a
@@ -108,7 +108,7 @@ or runtime keys.
108
108
 
109
109
  ```txt
110
110
  maybe #account { bytes32 account } as recipient
111
- #call { uint target, uint value, #bytes as payload }
111
+ #call { uint target, uint resources, #bytes as payload }
112
112
  ```
113
113
 
114
114
  Aliases may be used on any block item, including child blocks and prime items.
@@ -131,6 +131,13 @@ Integers are encoded big-endian. Signed integers use two's-complement encoding
131
131
  for their declared width. `bool` is one byte: `0x00` for false and `0x01` for
132
132
  true. `bytesN` values are encoded as exactly `N` bytes with no padding.
133
133
 
134
+ ## Chain Resources
135
+
136
+ Fields named `resources` are chain-specific resource words. Different chain
137
+ types may pack these words differently, but a given chain type must use one
138
+ stable format everywhere. For EVM chains, the low 128 bits are native value /
139
+ endowment in wei; higher bits are reserved for execution resources such as gas.
140
+
134
141
  ## Identifiers
135
142
 
136
143
  Block names, field names, and aliases use lower camelCase ASCII identifiers:
@@ -185,10 +192,10 @@ Common protocol schemas live in `contracts/blocks/Schema.sol`:
185
192
  #amount { bytes32 asset, bytes32 meta, uint amount }
186
193
  #balance { bytes32 asset, bytes32 meta, uint amount }
187
194
  #custody { uint host, bytes32 asset, bytes32 meta, uint amount }
188
- #call { uint target, uint value, #bytes as payload }
189
- #step { uint target, uint value, #bytes as request }
195
+ #call { uint target, uint resources, #bytes as payload }
196
+ #step { uint target, uint resources, #bytes as request }
190
197
  #context { bytes32 account, #bytes as state, #bytes as request }
191
- #pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as request } }
198
+ #pipe { uint resources, #context { bytes32 account, #bytes as state, #bytes as steps } }
192
199
  #auth { uint cid, uint deadline, #bytes as proof }
193
200
  ```
194
201
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootzero/contracts",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Solidity contracts and protocol building blocks for rootzero hosts and commands.",
5
5
  "private": false,
6
6
  "license": "GPL-3.0-only",
@@ -8,6 +8,7 @@
8
8
  "files": [
9
9
  "**/*.sol",
10
10
  "README.md",
11
+ "CHANGELOG.md",
11
12
  "LICENSE",
12
13
  "docs/Schema.md"
13
14
  ],
package/peer/Dispatch.sol CHANGED
@@ -4,24 +4,14 @@ pragma solidity ^0.8.33;
4
4
  import { PeerBase } from "./Base.sol";
5
5
  import { Payable } from "../core/Payable.sol";
6
6
  import { Cursors, Cur, Schemas } from "../Cursors.sol";
7
+ import { DispatchPayableHook } from "../commands/Relay.sol";
7
8
  import { Budget } from "../utils/Value.sol";
8
9
 
9
10
  using Cursors for Cur;
10
11
 
11
- abstract contract PeerDispatchPayableHook {
12
- /// @notice Override to dispatch an already encoded payload to `chain`.
13
- /// @param chain Destination chain node ID.
14
- /// @param resources Chain-adapter-specific destination resources. EVM adapters
15
- /// may interpret this as packed execution gas and destination value.
16
- /// @param payload Encoded payload ready for the transport layer.
17
- /// @param budget Source-chain native-value budget available for transport
18
- /// fees and destination resource funding.
19
- function dispatch(uint chain, uint resources, bytes calldata payload, Budget memory budget) internal virtual;
20
- }
21
-
22
12
  /// @title PeerDispatchPayable
23
13
  /// @notice Peer endpoint that forwards DISPATCH blocks to a host-defined dispatch hook.
24
- abstract contract PeerDispatchPayable is PeerBase, Payable, PeerDispatchPayableHook {
14
+ abstract contract PeerDispatchPayable is PeerBase, Payable, DispatchPayableHook {
25
15
  string private constant NAME = "peerDispatchPayable";
26
16
  uint internal immutable peerDispatchPayableId = peerId(NAME);
27
17
 
@@ -36,14 +26,14 @@ abstract contract PeerDispatchPayable is PeerBase, Payable, PeerDispatchPayableH
36
26
  /// @return output Empty response bytes.
37
27
  function peerDispatchPayable(bytes calldata request) external payable onlyPeer returns (bytes memory output) {
38
28
  (Cur memory input, , ) = Cursors.init(request, 0, 1);
39
- Budget memory budget = valueBudget();
40
-
41
- while (input.i < input.len) {
42
- (uint chain, uint resources, bytes calldata payload) = input.unpackDispatch();
43
- dispatch(chain, resources, payload, budget);
44
- }
45
-
46
- input.complete();
29
+ Budget memory budget = valueBudget();
30
+
31
+ while (input.i < input.len) {
32
+ (uint chain, uint resources, bytes calldata payload) = input.unpackDispatch();
33
+ dispatch(chain, resources, bytes(payload), budget);
34
+ }
35
+
36
+ input.complete();
47
37
  return "";
48
38
  }
49
39
 
package/peer/Pipe.sol CHANGED
@@ -10,7 +10,7 @@ using Cursors for Cur;
10
10
 
11
11
  /// @title PeerPipePayable
12
12
  /// @notice Peer that consumes PIPE blocks and executes each context step stream.
13
- /// Each PIPE block carries a value budget plus a CONTEXT block; the nested
13
+ /// Each PIPE block carries chain resources plus a CONTEXT block; the nested
14
14
  /// context steps are passed to the shared pipeline as the step stream.
15
15
  abstract contract PeerPipePayable is PeerBase, Pipeline {
16
16
  string private constant NAME = "peerPipePayable";
@@ -21,7 +21,7 @@ abstract contract PeerPipePayable is PeerBase, Pipeline {
21
21
  }
22
22
 
23
23
  /// @notice Execute peer-supplied pipes through the shared payable pipe.
24
- /// @dev Each pipe receives its own explicit value sub-budget. Any top-level
24
+ /// @dev Each pipe receives its own explicit EVM value sub-budget. Any top-level
25
25
  /// `msg.value` not assigned to a pipe remains on this host.
26
26
  /// @param request PIPE block stream supplied by the trusted peer.
27
27
  /// @return Empty response bytes.
@@ -30,8 +30,8 @@ abstract contract PeerPipePayable is PeerBase, Pipeline {
30
30
  Budget memory budget = valueBudget();
31
31
 
32
32
  while (input.i < input.len) {
33
- (uint value, bytes32 account, bytes calldata state, bytes calldata steps) = input.unpackPipe();
34
- pipe(account, state, steps, allocateValue(budget, value));
33
+ (uint resources, bytes32 account, bytes calldata state, bytes calldata steps) = input.unpackPipe();
34
+ pipe(account, state, steps, allocateValue(budget, resources));
35
35
  }
36
36
 
37
37
  input.complete();
package/utils/Value.sol CHANGED
@@ -18,9 +18,10 @@ library Values {
18
18
  /// @param budget Mutable budget to deduct from.
19
19
  /// @param amount Native value to spend in wei.
20
20
  /// @return The same `amount`, ready to forward to a callee.
21
- function use(Budget memory budget, uint amount) internal pure returns (uint) {
22
- if (amount > budget.remaining) revert InsufficientValue();
23
- budget.remaining -= amount;
21
+ function use(Budget memory budget, uint128 amount) internal pure returns (uint128) {
22
+ uint value = uint(amount);
23
+ if (value > budget.remaining) revert InsufficientValue();
24
+ budget.remaining -= value;
24
25
  return amount;
25
26
  }
26
27
 
@@ -29,7 +30,7 @@ library Values {
29
30
  /// @param budget Mutable parent budget to deduct from.
30
31
  /// @param amount Native value to assign to the sub-budget, in wei.
31
32
  /// @return A new budget with `amount` remaining.
32
- function allocate(Budget memory budget, uint amount) internal pure returns (Budget memory) {
33
+ function allocate(Budget memory budget, uint128 amount) internal pure returns (Budget memory) {
33
34
  return Budget({remaining: use(budget, amount)});
34
35
  }
35
36
  }