@rootzero/contracts 0.4.0 → 0.5.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 (96) hide show
  1. package/{Cursors.sol → contracts/Cursors.sol} +1 -2
  2. package/{blocks → contracts/blocks}/Cursors.sol +18 -0
  3. package/{blocks → contracts/blocks}/Keys.sol +1 -1
  4. package/{blocks → contracts/blocks}/Schema.sol +1 -1
  5. package/{blocks → contracts/blocks}/Writers.sol +2 -2
  6. package/{commands → contracts/commands}/Provision.sol +1 -3
  7. package/{commands → contracts/commands}/Settle.sol +4 -8
  8. package/{commands → contracts/commands}/Transfer.sol +18 -11
  9. package/{events → contracts/events}/RootZero.sol +2 -3
  10. package/contracts/peer/Settle.sol +34 -0
  11. package/contracts/test/TestBorrowHost.sol +72 -0
  12. package/contracts/test/TestBurnHost.sol +31 -0
  13. package/contracts/test/TestCreateHost.sol +40 -0
  14. package/contracts/test/TestCursorHelper.sol +191 -0
  15. package/contracts/test/TestDiscovery.sol +9 -0
  16. package/contracts/test/TestECDSA.sol +19 -0
  17. package/contracts/test/TestHost.sol +218 -0
  18. package/contracts/test/TestLiquidityHost.sol +167 -0
  19. package/contracts/test/TestMintHost.sol +50 -0
  20. package/contracts/test/TestOperation.sol +21 -0
  21. package/contracts/test/TestPeerHost.sol +57 -0
  22. package/contracts/test/TestReclaimHost.sol +55 -0
  23. package/contracts/test/TestRejectEther.sol +11 -0
  24. package/contracts/test/TestRemoveHost.sol +40 -0
  25. package/contracts/test/TestSupplyHost.sol +25 -0
  26. package/contracts/test/TestSwapHost.sol +67 -0
  27. package/contracts/test/TestUtils.sol +184 -0
  28. package/contracts/test/TestValidator.sol +13 -0
  29. package/{utils → contracts/utils}/Accounts.sol +11 -0
  30. package/package.json +33 -17
  31. package/blocks/Mem.sol +0 -188
  32. package/docs/GETTING_STARTED.md +0 -286
  33. /package/{Commands.sol → contracts/Commands.sol} +0 -0
  34. /package/{Core.sol → contracts/Core.sol} +0 -0
  35. /package/{Events.sol → contracts/Events.sol} +0 -0
  36. /package/{Utils.sol → contracts/Utils.sol} +0 -0
  37. /package/{commands → contracts/commands}/Base.sol +0 -0
  38. /package/{commands → contracts/commands}/Borrow.sol +0 -0
  39. /package/{commands → contracts/commands}/Burn.sol +0 -0
  40. /package/{commands → contracts/commands}/Create.sol +0 -0
  41. /package/{commands → contracts/commands}/Credit.sol +0 -0
  42. /package/{commands → contracts/commands}/Debit.sol +0 -0
  43. /package/{commands → contracts/commands}/Deposit.sol +0 -0
  44. /package/{commands → contracts/commands}/Liquidate.sol +0 -0
  45. /package/{commands → contracts/commands}/Liquidity.sol +0 -0
  46. /package/{commands → contracts/commands}/Mint.sol +0 -0
  47. /package/{commands → contracts/commands}/Pipe.sol +0 -0
  48. /package/{commands → contracts/commands}/Reclaim.sol +0 -0
  49. /package/{commands → contracts/commands}/Redeem.sol +0 -0
  50. /package/{commands → contracts/commands}/Remove.sol +0 -0
  51. /package/{commands → contracts/commands}/Repay.sol +0 -0
  52. /package/{commands → contracts/commands}/Stake.sol +0 -0
  53. /package/{commands → contracts/commands}/Supply.sol +0 -0
  54. /package/{commands → contracts/commands}/Swap.sol +0 -0
  55. /package/{commands → contracts/commands}/Unstake.sol +0 -0
  56. /package/{commands → contracts/commands}/Withdraw.sol +0 -0
  57. /package/{commands → contracts/commands}/admin/Allocate.sol +0 -0
  58. /package/{commands → contracts/commands}/admin/AllowAssets.sol +0 -0
  59. /package/{commands → contracts/commands}/admin/Authorize.sol +0 -0
  60. /package/{commands → contracts/commands}/admin/DenyAssets.sol +0 -0
  61. /package/{commands → contracts/commands}/admin/Destroy.sol +0 -0
  62. /package/{commands → contracts/commands}/admin/Init.sol +0 -0
  63. /package/{commands → contracts/commands}/admin/Relocate.sol +0 -0
  64. /package/{commands → contracts/commands}/admin/Unauthorize.sol +0 -0
  65. /package/{core → contracts/core}/Access.sol +0 -0
  66. /package/{core → contracts/core}/Balances.sol +0 -0
  67. /package/{core → contracts/core}/Host.sol +0 -0
  68. /package/{core → contracts/core}/Operation.sol +0 -0
  69. /package/{core → contracts/core}/Validator.sol +0 -0
  70. /package/{events → contracts/events}/Access.sol +0 -0
  71. /package/{events → contracts/events}/Asset.sol +0 -0
  72. /package/{events → contracts/events}/Balance.sol +0 -0
  73. /package/{events → contracts/events}/Collateral.sol +0 -0
  74. /package/{events → contracts/events}/Command.sol +0 -0
  75. /package/{events → contracts/events}/Debt.sol +0 -0
  76. /package/{events → contracts/events}/Deposit.sol +0 -0
  77. /package/{events → contracts/events}/Emitter.sol +0 -0
  78. /package/{events → contracts/events}/Governed.sol +0 -0
  79. /package/{events → contracts/events}/HostAnnounced.sol +0 -0
  80. /package/{events → contracts/events}/Listing.sol +0 -0
  81. /package/{events → contracts/events}/Peer.sol +0 -0
  82. /package/{events → contracts/events}/Quote.sol +0 -0
  83. /package/{events → contracts/events}/Withdraw.sol +0 -0
  84. /package/{interfaces → contracts/interfaces}/IHostDiscovery.sol +0 -0
  85. /package/{peer → contracts/peer}/AllowAssets.sol +0 -0
  86. /package/{peer → contracts/peer}/Base.sol +0 -0
  87. /package/{peer → contracts/peer}/DenyAssets.sol +0 -0
  88. /package/{peer → contracts/peer}/Pull.sol +0 -0
  89. /package/{peer → contracts/peer}/Push.sol +0 -0
  90. /package/{utils → contracts/utils}/Assets.sol +0 -0
  91. /package/{utils → contracts/utils}/ECDSA.sol +0 -0
  92. /package/{utils → contracts/utils}/Ids.sol +0 -0
  93. /package/{utils → contracts/utils}/Layout.sol +0 -0
  94. /package/{utils → contracts/utils}/State.sol +0 -0
  95. /package/{utils → contracts/utils}/Utils.sol +0 -0
  96. /package/{utils → contracts/utils}/Value.sol +0 -0
@@ -0,0 +1,67 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { Host } from "../core/Host.sol";
5
+ import { SwapExactBalanceToBalance } from "../commands/Swap.sol";
6
+ import { AssetAmount, Cur, Cursors, Cursors, Keys } from "../Cursors.sol";
7
+
8
+ using Cursors for Cur;
9
+
10
+ contract TestSwapHost is Host, SwapExactBalanceToBalance {
11
+ event SwapMapped(bytes32 account, bytes32 asset, bytes32 meta, uint amount, bytes inputData);
12
+ event SwapMinimum(bytes32 asset, bytes32 meta, uint amount);
13
+
14
+ constructor(address rootzero)
15
+ Host(rootzero, 1, "test")
16
+ SwapExactBalanceToBalance("route(bytes data)")
17
+ {}
18
+
19
+ function swapExactBalanceToBalance(
20
+ bytes32 account,
21
+ AssetAmount memory balance,
22
+ Cur memory request
23
+ ) internal override returns (AssetAmount memory out) {
24
+ if (request.i == request.len) revert Cursors.InvalidBlock();
25
+
26
+ Cur memory input = request;
27
+ (bytes4 key, uint len) = request.peek(request.i);
28
+ if (key == Keys.Bundle) input = request.bundle();
29
+
30
+ bytes calldata inputData;
31
+ (key, len) = input.peek(input.i);
32
+ if (key == Keys.Route) {
33
+ inputData = input.unpackRoute();
34
+ } else {
35
+ uint next = input.i + 8 + len;
36
+ inputData = msg.data[input.offset + input.i:input.offset + next];
37
+ input.i = next;
38
+ }
39
+ emit SwapMapped(account, balance.asset, balance.meta, balance.amount, inputData);
40
+
41
+ if (input.i < input.len) {
42
+ (key, ) = input.peek(input.i);
43
+ }
44
+ if (input.i < input.len && key == Keys.Minimum) {
45
+ (bytes32 minAsset, bytes32 minMeta, uint minAmount) = input.unpackMinimum();
46
+ emit SwapMinimum(minAsset, minMeta, minAmount);
47
+ }
48
+
49
+ return AssetAmount({
50
+ asset: balance.asset,
51
+ meta: bytes32(inputData.length),
52
+ amount: balance.amount + inputData.length
53
+ });
54
+ }
55
+
56
+ function getSwapExactInAsset32Id() external view returns (uint) {
57
+ return swapExactBalanceToBalanceId;
58
+ }
59
+
60
+ function getAdminAccount() external view returns (bytes32) {
61
+ return adminAccount;
62
+ }
63
+ }
64
+
65
+
66
+
67
+
@@ -0,0 +1,184 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { Accounts } from "../utils/Accounts.sol";
5
+ import { Amounts, Assets } from "../utils/Assets.sol";
6
+ import { Ids, Selectors } from "../utils/Ids.sol";
7
+ import { addrOr, applyBps, beforeBps, bytes32ToString, isFamily, isLocal, isLocalFamily, matchesBase, toLocalBase, toUnspecifiedBase, max8, max16, max32, max64, max128, max160 } from "../utils/Utils.sol";
8
+ import { Values } from "../utils/Value.sol";
9
+
10
+ contract TestUtils {
11
+ function testAddrOr(address addr, address or_) external pure returns (address) {
12
+ return addrOr(addr, or_);
13
+ }
14
+
15
+ function testToAdminAccount(address addr) external view returns (bytes32) {
16
+ return Accounts.toAdmin(addr);
17
+ }
18
+
19
+ function testToUserAccount(address addr) external pure returns (bytes32) {
20
+ return Accounts.toUser(addr);
21
+ }
22
+
23
+ function testAccountEvmAddr(bytes32 account) external pure returns (address) {
24
+ return Accounts.addrEvm(account);
25
+ }
26
+
27
+ function testIsAdminAccount(bytes32 account) external pure returns (bool) {
28
+ return Accounts.isAdmin(account);
29
+ }
30
+
31
+ function testIsKeccakAccount(bytes32 account) external pure returns (bool) {
32
+ return Accounts.isKeccak(account);
33
+ }
34
+
35
+ function testToKeccakAccount(bytes calldata raw) external pure returns (bytes32) {
36
+ return Accounts.toKeccak(raw);
37
+ }
38
+
39
+ function testMatchesKeccakAccount(bytes32 account, bytes calldata raw) external pure returns (bool) {
40
+ return Accounts.matchesKeccak(account, raw);
41
+ }
42
+
43
+ function testToValueAsset() external view returns (bytes32) {
44
+ return Assets.toValue();
45
+ }
46
+
47
+ function testToErc20Asset(address addr) external view returns (bytes32) {
48
+ return Assets.toErc20(addr);
49
+ }
50
+
51
+ function testToErc721Asset(address addr) external view returns (bytes32) {
52
+ return Assets.toErc721(addr);
53
+ }
54
+
55
+ function testIsAsset32(bytes32 asset) external pure returns (bool) {
56
+ return Assets.is32(asset);
57
+ }
58
+
59
+ function testResolveAmount(uint available, uint min, uint max) external pure returns (uint) {
60
+ return Amounts.resolve(available, min, max);
61
+ }
62
+
63
+ function testEnsureAmount(uint amount) external pure returns (uint) {
64
+ return Amounts.ensure(amount);
65
+ }
66
+
67
+ function testEnsureAmountRange(uint amount, uint min, uint max) external pure returns (uint) {
68
+ return Amounts.ensure(amount, min, max);
69
+ }
70
+
71
+ function testAssetKey(bytes32 asset, bytes32 meta) external pure returns (bytes32) {
72
+ return Assets.key(asset, meta);
73
+ }
74
+
75
+ function testLocalErc20Addr(bytes32 asset) external view returns (address) {
76
+ return Assets.erc20Addr(asset);
77
+ }
78
+
79
+ function testLocalErc721Issuer(bytes32 asset) external view returns (address) {
80
+ return Assets.erc721Issuer(asset);
81
+ }
82
+
83
+ function testToHostId(address addr) external view returns (uint) {
84
+ return Ids.toHost(addr);
85
+ }
86
+
87
+ function testToCommandId(bytes32 name, address addr) external view returns (uint) {
88
+ return Ids.toCommand(Selectors.command(bytes32ToString(name)), addr);
89
+ }
90
+
91
+ function testToCommandSelector(bytes32 name) external pure returns (bytes4) {
92
+ return Selectors.command(bytes32ToString(name));
93
+ }
94
+
95
+ function testIsHost(uint id) external pure returns (bool) {
96
+ return Ids.isHost(id);
97
+ }
98
+
99
+ function testIsCommand(uint id) external pure returns (bool) {
100
+ return Ids.isCommand(id);
101
+ }
102
+
103
+ function testLocalNodeAddr(uint node) external view returns (address) {
104
+ return Ids.nodeAddr(node);
105
+ }
106
+
107
+ function testLocalHostAddr(uint host) external view returns (address) {
108
+ return Ids.hostAddr(host);
109
+ }
110
+
111
+ function testEnsureHost(uint id, address addr) external view returns (uint) {
112
+ return Ids.host(id, addr);
113
+ }
114
+
115
+ function testEnsureCommand(uint id) external pure returns (uint) {
116
+ return Ids.command(id);
117
+ }
118
+
119
+ function testApplyBps(uint amount, uint16 bps) external pure returns (uint) {
120
+ return applyBps(amount, bps);
121
+ }
122
+
123
+ function testBeforeBps(uint amount, uint16 bps) external pure returns (uint) {
124
+ return beforeBps(amount, bps);
125
+ }
126
+
127
+ function testIsFamily(uint value, uint24 family) external pure returns (bool) {
128
+ return isFamily(value, family);
129
+ }
130
+
131
+ function testIsLocal(uint value) external view returns (bool) {
132
+ return isLocal(value);
133
+ }
134
+
135
+ function testMatchesBase(bytes32 value, uint base) external pure returns (bool) {
136
+ return matchesBase(value, base);
137
+ }
138
+
139
+ function testToLocalBase(uint32 prefix) external view returns (uint) {
140
+ return toLocalBase(prefix);
141
+ }
142
+
143
+ function testMsgValue() external payable returns (uint) {
144
+ Values.Budget memory budget = Values.fromMsg();
145
+ return budget.remaining;
146
+ }
147
+
148
+ function testUseValue(uint amount, uint remaining) external pure returns (uint spent, uint remainingAfter) {
149
+ Values.Budget memory budget = Values.Budget({remaining: remaining});
150
+ spent = Values.use(budget, amount);
151
+ remainingAfter = budget.remaining;
152
+ }
153
+
154
+ function testBytes32ToString(bytes32 value) external pure returns (string memory) {
155
+ return bytes32ToString(value);
156
+ }
157
+
158
+ function testMax8(uint value) external pure returns (uint) {
159
+ return max8(value);
160
+ }
161
+
162
+ function testMax16(uint value) external pure returns (uint) {
163
+ return max16(value);
164
+ }
165
+
166
+ function testMax32(uint value) external pure returns (uint) {
167
+ return max32(value);
168
+ }
169
+
170
+ function testMax64(uint value) external pure returns (uint) {
171
+ return max64(value);
172
+ }
173
+
174
+ function testMax128(uint value) external pure returns (uint) {
175
+ return max128(value);
176
+ }
177
+
178
+ function testMax160(uint value) external pure returns (uint) {
179
+ return max160(value);
180
+ }
181
+ }
182
+
183
+
184
+
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { Validator } from "../core/Validator.sol";
5
+
6
+ contract TestValidator is Validator {
7
+ function testVerify(bytes32 hash, uint192 nonce, bytes calldata proof) external returns (address) {
8
+ return verify(hash, nonce, proof);
9
+ }
10
+ }
11
+
12
+
13
+
@@ -70,6 +70,17 @@ library Accounts {
70
70
  return account == toKeccak(raw);
71
71
  }
72
72
 
73
+ /// @notice Assert that `account` uses the Account layout tag and return it unchanged.
74
+ /// Ignores width, chain binding, and subtype details.
75
+ /// @param account Account ID to validate.
76
+ /// @return The same `account` value if valid.
77
+ function ensure(bytes32 account) internal pure returns (bytes32) {
78
+ if (uint8(uint(account) >> 232) != Layout.Account) {
79
+ revert InvalidAccount();
80
+ }
81
+ return account;
82
+ }
83
+
73
84
  /// @notice Assert that `account` belongs to the EVM account family and return it unchanged.
74
85
  /// @param account Account ID to validate.
75
86
  /// @return The same `account` value if valid.
package/package.json CHANGED
@@ -1,17 +1,33 @@
1
- {
2
- "name": "@rootzero/contracts",
3
- "version": "0.4.0",
4
- "description": "Solidity contracts and protocol building blocks for rootzero hosts and commands.",
5
- "private": false,
6
- "license": "GPL-3.0-only",
7
- "type": "module",
8
- "files": [
9
- "**/*.sol",
10
- "README.md",
11
- "LICENSE",
12
- "docs/GETTING_STARTED.md"
13
- ],
14
- "publishConfig": {
15
- "access": "public"
16
- }
17
- }
1
+ {
2
+ "name": "@rootzero/contracts",
3
+ "version": "0.5.0",
4
+ "description": "Solidity contracts and protocol building blocks for rootzero hosts and commands.",
5
+ "private": false,
6
+ "license": "GPL-3.0-only",
7
+ "type": "module",
8
+ "files": [
9
+ "*.sol",
10
+ "contracts/**/*.sol",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "scripts": {
18
+ "compile": "hardhat compile",
19
+ "test": "hardhat test",
20
+ "prepublishOnly": "npm test",
21
+ "prepare:package": "node scripts/prepare-package.mjs",
22
+ "pack:package": "npm run prepare:package && npm pack ./dist/package",
23
+ "publish:package": "npm test && npm run prepare:package && npm publish ./dist/package --access public"
24
+ },
25
+ "devDependencies": {
26
+ "@nomicfoundation/hardhat-mocha": "^3.0.13",
27
+ "chai": "^6.2.2",
28
+ "ethers": "^6.16.0",
29
+ "hardhat": "^3.1.7",
30
+ "mocha": "^11.7.5",
31
+ "typescript": "~5.8.0"
32
+ }
33
+ }
package/blocks/Mem.sol DELETED
@@ -1,188 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- import { HostAmount, Tx, Keys } from "./Schema.sol";
5
- import { Cursors } from "./Cursors.sol";
6
-
7
- /// @notice Reference to a single block inside a `bytes memory` buffer.
8
- /// Positions are byte offsets within the buffer (not absolute memory addresses).
9
- struct MemRef {
10
- /// @dev Block type identifier read from the 4-byte header key.
11
- bytes4 key;
12
- /// @dev Payload start offset (byte immediately after the 8-byte header).
13
- uint i;
14
- /// @dev Payload end offset (equals `i + payloadLen`).
15
- uint end;
16
- }
17
-
18
- /// @title Mem
19
- /// @notice Memory block stream parser for the rootzero protocol.
20
- /// Mirrors the calldata-oriented `Cursors` API but operates on `bytes memory`
21
- /// buffers, using `mcopy`/`mload` assembly instead of `msg.data` slices.
22
- library Mem {
23
- /// @notice Parse a block header at offset `i` within `source`.
24
- /// Returns an empty sentinel `MemRef` (all zeros) when `i` is at end-of-data.
25
- /// @param source In-memory block stream buffer.
26
- /// @param i Byte offset of the block header within `source`.
27
- /// @return ref Parsed block reference with key, payload start, and payload end.
28
- function from(bytes memory source, uint i) internal pure returns (MemRef memory ref) {
29
- uint eod = source.length;
30
- if (i == eod) return MemRef(bytes4(0), i, i);
31
- if (i > eod) revert Cursors.MalformedBlocks();
32
-
33
- unchecked {
34
- ref.i = i + 8;
35
- }
36
- if (ref.i > eod) revert Cursors.MalformedBlocks();
37
-
38
- // Read the 8-byte block header (key + payloadLen) in one mload.
39
- bytes32 w;
40
- assembly ("memory-safe") {
41
- w := mload(add(add(source, 0x20), i))
42
- }
43
-
44
- ref.key = bytes4(w);
45
- ref.end = ref.i + uint32(bytes4(w << 32));
46
- if (ref.end > eod) revert Cursors.MalformedBlocks();
47
- }
48
-
49
- /// @notice Extract a byte range `[start, end)` from `source` into a new buffer.
50
- /// @param source Source buffer.
51
- /// @param start Inclusive start offset.
52
- /// @param end Exclusive end offset.
53
- /// @return out Copied slice as a new `bytes` value.
54
- function slice(bytes memory source, uint start, uint end) internal pure returns (bytes memory out) {
55
- if (end < start || end > source.length) revert Cursors.MalformedBlocks();
56
- uint len = end - start;
57
- out = new bytes(len);
58
- if (len == 0) return out;
59
-
60
- assembly ("memory-safe") {
61
- mcopy(add(out, 0x20), add(add(source, 0x20), start), len)
62
- }
63
- }
64
-
65
- /// @notice Count consecutive blocks of `key` starting at offset `i`.
66
- /// @param source Source buffer.
67
- /// @param i Starting byte offset.
68
- /// @param key Block type to count.
69
- /// @return total Number of consecutive matching blocks.
70
- /// @return cursor Byte offset immediately after the last counted block.
71
- function count(bytes memory source, uint i, bytes4 key) internal pure returns (uint total, uint cursor) {
72
- cursor = i;
73
- while (cursor < source.length) {
74
- MemRef memory ref = from(source, cursor);
75
- if (ref.key != key) break;
76
- unchecked {
77
- ++total;
78
- }
79
- cursor = ref.end;
80
- }
81
- }
82
-
83
- /// @notice Scan forward from `i` up to `limit` for the first block matching `key`.
84
- /// Returns an empty sentinel `MemRef` (key == 0, i == end == limit) if not found.
85
- /// @param source Source buffer.
86
- /// @param i Starting byte offset.
87
- /// @param limit Exclusive upper bound for the search (must be ≤ `source.length`).
88
- /// @param key Block type to find.
89
- /// @return ref Reference to the first matching block, or the sentinel if absent.
90
- function find(bytes memory source, uint i, uint limit, bytes4 key) internal pure returns (MemRef memory ref) {
91
- if (limit > source.length) revert Cursors.MalformedBlocks();
92
- while (i < limit) {
93
- ref = from(source, i);
94
- if (ref.end > limit) revert Cursors.MalformedBlocks();
95
- if (ref.key == key) return ref;
96
- i = ref.end;
97
- }
98
-
99
- return MemRef(bytes4(0), limit, limit);
100
- }
101
-
102
- /// @notice Assert that `ref` points to a block of the expected type.
103
- /// @param ref Block reference to validate.
104
- /// @param key Expected block type key.
105
- function ensure(MemRef memory ref, bytes4 key) internal pure {
106
- if (key == 0 || key != ref.key) revert Cursors.InvalidBlock();
107
- }
108
-
109
- /// @notice Assert that `ref` points to a block of the expected type with exact payload length.
110
- /// @param ref Block reference to validate.
111
- /// @param key Expected block type key.
112
- /// @param len Expected payload byte length.
113
- function ensure(MemRef memory ref, bytes4 key, uint len) internal pure {
114
- if (key == 0 || key != ref.key || len != (ref.end - ref.i)) revert Cursors.InvalidBlock();
115
- }
116
-
117
- /// @notice Assert that `ref` points to a block of the expected type within a length range.
118
- /// @param ref Block reference to validate.
119
- /// @param key Expected block type key.
120
- /// @param min Minimum payload length (inclusive).
121
- /// @param max Maximum payload length (inclusive); 0 means unbounded.
122
- function ensure(MemRef memory ref, bytes4 key, uint min, uint max) internal pure {
123
- uint len = ref.end - ref.i;
124
- if (key == 0 || key != ref.key || len < min || (max != 0 && len > max)) revert Cursors.InvalidBlock();
125
- }
126
-
127
- /// @notice Decode a BALANCE block payload from `source` using the given reference.
128
- /// @param ref Block reference; must point to a BALANCE block with exactly 96 payload bytes.
129
- /// @param source Buffer containing the block.
130
- /// @return asset Asset identifier.
131
- /// @return meta Asset metadata slot.
132
- /// @return amount Token amount.
133
- function unpackBalance(
134
- MemRef memory ref,
135
- bytes memory source
136
- ) internal pure returns (bytes32 asset, bytes32 meta, uint amount) {
137
- ensure(ref, Keys.Balance, 96);
138
- uint i = ref.i;
139
-
140
- // Read three contiguous 32-byte words from the payload.
141
- assembly ("memory-safe") {
142
- let p := add(add(source, 0x20), i)
143
- asset := mload(p)
144
- meta := mload(add(p, 0x20))
145
- amount := mload(add(p, 0x40))
146
- }
147
- }
148
-
149
- /// @notice Decode a CUSTODY block payload from `source` into a `HostAmount` struct.
150
- /// @param ref Block reference; must point to a CUSTODY block with exactly 128 payload bytes.
151
- /// @param source Buffer containing the block.
152
- /// @return value Decoded host, asset, meta, and amount.
153
- function toCustodyValue(
154
- MemRef memory ref,
155
- bytes memory source
156
- ) internal pure returns (HostAmount memory value) {
157
- ensure(ref, Keys.Custody, 128);
158
- uint i = ref.i;
159
-
160
- // Copy four 32-byte payload words directly into the struct memory slots.
161
- assembly ("memory-safe") {
162
- let p := add(add(source, 0x20), i)
163
- mstore(value, mload(p))
164
- mstore(add(value, 0x20), mload(add(p, 0x20)))
165
- mstore(add(value, 0x40), mload(add(p, 0x40)))
166
- mstore(add(value, 0x60), mload(add(p, 0x60)))
167
- }
168
- }
169
-
170
- /// @notice Decode a TRANSACTION block payload from `source` into a `Tx` struct.
171
- /// @param ref Block reference; must point to a TRANSACTION block with exactly 160 payload bytes.
172
- /// @param source Buffer containing the block.
173
- /// @return value Decoded from, to, asset, meta, and amount.
174
- function toTxValue(MemRef memory ref, bytes memory source) internal pure returns (Tx memory value) {
175
- ensure(ref, Keys.Transaction, 160);
176
- uint i = ref.i;
177
-
178
- // Copy five 32-byte payload words directly into the struct memory slots.
179
- assembly ("memory-safe") {
180
- let p := add(add(source, 0x20), i)
181
- mstore(value, mload(p))
182
- mstore(add(value, 0x20), mload(add(p, 0x20)))
183
- mstore(add(value, 0x40), mload(add(p, 0x40)))
184
- mstore(add(value, 0x60), mload(add(p, 0x60)))
185
- mstore(add(value, 0x80), mload(add(p, 0x80)))
186
- }
187
- }
188
- }