@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
@@ -1,14 +1,13 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- // Aggregator: re-exports all block stream primitives (Cursors, Writers, Mem, Schema, Keys).
4
+ // Aggregator: re-exports all block stream primitives (Cursors, Writers, Schema, Keys).
5
5
  // Import this file to get access to the full block encoding/decoding surface in one import.
6
6
 
7
7
  import { HostAmount, UserAmount, HostAsset, Tx, AssetAmount } from "./blocks/Schema.sol";
8
8
  import { Keys } from "./blocks/Keys.sol";
9
9
  import { Schemas } from "./blocks/Schema.sol";
10
10
  import { Cursors, Cur } from "./blocks/Cursors.sol";
11
- import { Mem, MemRef } from "./blocks/Mem.sol";
12
11
  import { Writer, Writers } from "./blocks/Writers.sol";
13
12
 
14
13
 
@@ -778,6 +778,15 @@ library Cursors {
778
778
  cur.i += 104;
779
779
  }
780
780
 
781
+ /// @notice Consume a MINIMUM block, assert it matches the expected asset and meta, and require `amount` to satisfy it.
782
+ /// @param cur Cursor; advanced past the block.
783
+ /// @param asset Expected asset identifier.
784
+ /// @param meta Expected metadata slot.
785
+ /// @param amount Actual amount that must be at least the minimum from the block.
786
+ function requireMinimum(Cur memory cur, bytes32 asset, bytes32 meta, uint amount) internal pure {
787
+ if (requireMinimum(cur, asset, meta) > amount) revert UnexpectedValue();
788
+ }
789
+
781
790
  /// @notice Consume a MAXIMUM block and assert it matches the expected asset and meta.
782
791
  /// @param cur Cursor; advanced past the block.
783
792
  /// @param asset Expected asset identifier.
@@ -788,6 +797,15 @@ library Cursors {
788
797
  cur.i += 104;
789
798
  }
790
799
 
800
+ /// @notice Consume a MAXIMUM block, assert it matches the expected asset and meta, and require `amount` to satisfy it.
801
+ /// @param cur Cursor; advanced past the block.
802
+ /// @param asset Expected asset identifier.
803
+ /// @param meta Expected metadata slot.
804
+ /// @param amount Actual amount that must be at most the maximum from the block.
805
+ function requireMaximum(Cur memory cur, bytes32 asset, bytes32 meta, uint amount) internal pure {
806
+ if (requireMaximum(cur, asset, meta) < amount) revert UnexpectedValue();
807
+ }
808
+
791
809
  /// @notice Consume a CUSTODY block and assert it belongs to the expected host.
792
810
  /// @param cur Cursor; advanced past the block.
793
811
  /// @param host Expected host node ID.
@@ -30,7 +30,7 @@ library Keys {
30
30
  bytes4 constant Party = bytes4(keccak256("party(bytes32 account)"));
31
31
  /// @dev Destination account — (bytes32 account)
32
32
  bytes4 constant Recipient = bytes4(keccak256("recipient(bytes32 account)"));
33
- /// @dev Settled transfer record — (bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)
33
+ /// @dev Transfer record passed through the pipeline — (bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)
34
34
  bytes4 constant Transaction = bytes4(keccak256("tx(bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)"));
35
35
  /// @dev Sub-command invocation — (uint target, uint value, bytes request)
36
36
  bytes4 constant Step = bytes4(keccak256("step(uint target, uint value, bytes request)"));
@@ -143,7 +143,7 @@ struct HostAsset {
143
143
  bytes32 meta;
144
144
  }
145
145
 
146
- /// @notice Settled transfer record written to transaction state.
146
+ /// @notice Transfer payload used across the pipeline and later consumed by settlement.
147
147
  struct Tx {
148
148
  /// @dev Sender account identifier.
149
149
  bytes32 from;
@@ -259,7 +259,7 @@ library Writers {
259
259
  /// @notice Write a TRANSACTION block directly into `dst` at byte offset `i`.
260
260
  /// @param dst Destination buffer; must have at least `i + Sizes.Transaction` bytes.
261
261
  /// @param i Write offset within `dst`.
262
- /// @param value Transaction fields to encode.
262
+ /// @param value Transfer record fields to encode.
263
263
  /// @return next Byte offset immediately after the written block.
264
264
  function writeTxBlock(bytes memory dst, uint i, Tx memory value) internal pure returns (uint next) {
265
265
  next = i + Sizes.Transaction;
@@ -279,7 +279,7 @@ library Writers {
279
279
 
280
280
  /// @notice Append a TRANSACTION block from a struct.
281
281
  /// @param writer Destination writer; `i` is advanced by `Sizes.Transaction`.
282
- /// @param value Transaction fields to encode.
282
+ /// @param value Transfer record fields to encode.
283
283
  function appendTx(Writer memory writer, Tx memory value) internal pure {
284
284
  writer.i = writeTxBlock(writer.dst, writer.i, value);
285
285
  }
@@ -2,7 +2,7 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {CommandContext, CommandBase, State} from "./Base.sol";
5
- import {Cursors, Cur, Keys, Schemas, Writer, Writers} from "../Cursors.sol";
5
+ import {Cursors, Cur, Schemas, Writer, Writers} from "../Cursors.sol";
6
6
  using Cursors for Cur;
7
7
  using Writers for Writer;
8
8
 
@@ -38,8 +38,6 @@ abstract contract Provision is CommandBase, ProvisionHook {
38
38
  CommandContext calldata c
39
39
  ) external payable onlyCommand(provisionId, c.target) returns (bytes memory) {
40
40
  (Cur memory request, uint count, ) = cursor(c.request, 1);
41
- (bytes4 key, ) = request.peek(0);
42
- if (key != Keys.Bundle) revert Writers.EmptyRequest();
43
41
  Writer memory writer = Writers.allocCustodies(count);
44
42
 
45
43
  while (request.i < request.bound) {
@@ -3,31 +3,27 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { CommandContext, CommandBase, State } from "./Base.sol";
5
5
  import { Cursors, Cur, Tx } from "../Cursors.sol";
6
+ import { TransferHook } from "./Transfer.sol";
6
7
  using Cursors for Cur;
7
8
 
8
9
  string constant NAME = "settle";
9
10
 
10
11
  /// @title Settle
11
- /// @notice Command that settles each TRANSACTION state block via a virtual hook.
12
+ /// @notice Command that consumes each TRANSACTION state block and settles it through the shared transfer hook.
12
13
  /// Produces no output state.
13
- abstract contract Settle is CommandBase {
14
+ abstract contract Settle is CommandBase, TransferHook {
14
15
  uint internal immutable settleId = commandId(NAME);
15
16
 
16
17
  constructor() {
17
18
  emit Command(host, NAME, "", settleId, State.Transactions, State.Empty);
18
19
  }
19
20
 
20
- /// @notice Override to settle a single transaction block.
21
- /// Called once per TRANSACTION block in state.
22
- /// @param value Decoded transaction (from, to, asset, meta, amount).
23
- function settle(Tx memory value) internal virtual;
24
-
25
21
  function settle(CommandContext calldata c) external payable onlyCommand(settleId, c.target) returns (bytes memory) {
26
22
  (Cur memory state, , ) = cursor(c.state, 1);
27
23
 
28
24
  while (state.i < state.bound) {
29
25
  Tx memory value = state.unpackTxValue();
30
- settle(value);
26
+ transfer(value);
31
27
  }
32
28
 
33
29
  state.complete();
@@ -2,39 +2,46 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import { CommandContext, CommandBase, State } from "./Base.sol";
5
- import { Cursors, Cur, Schemas } from "../Cursors.sol";
5
+ import { Cursors, Cur, Schemas, Tx } from "../Cursors.sol";
6
+ import { Accounts } from "../utils/Accounts.sol";
6
7
  using Cursors for Cur;
7
8
 
8
9
  string constant NAME = "transfer";
9
10
  string constant INPUT = string.concat(Schemas.Amount, "&", Schemas.Recipient);
10
11
 
12
+ abstract contract TransferHook {
13
+ /// @notice Override to execute a single transfer record from the request pipeline.
14
+ /// Called once per bundled AMOUNT+RECIPIENT pair in the request.
15
+ /// @param value Decoded transfer record (from, to, asset, meta, amount).
16
+ function transfer(Tx memory value) internal virtual;
17
+ }
18
+
11
19
  /// @title Transfer
12
20
  /// @notice Command that transfers assets from a caller to recipients specified in
13
21
  /// bundled AMOUNT+RECIPIENT request blocks. Produces no state output.
14
- /// The virtual `transfer(from, input)` hook is called once per bundle.
15
- abstract contract Transfer is CommandBase {
22
+ /// The virtual `transfer(value)` hook is called once per bundle.
23
+ abstract contract Transfer is CommandBase, TransferHook {
16
24
  uint internal immutable transferId = commandId(NAME);
17
25
 
18
26
  constructor() {
19
27
  emit Command(host, NAME, INPUT, transferId, State.Empty, State.Empty);
20
28
  }
21
29
 
22
- /// @notice Override to execute a single transfer described by the current `input` position.
23
- /// Called once per bundled AMOUNT+RECIPIENT pair in the request.
24
- /// @param from Source account identifier.
25
- /// @param input Live request cursor positioned at the current bundle.
26
- function transfer(bytes32 from, Cur memory input) internal virtual;
27
-
28
30
  /// @notice Override to customize request parsing or batching for transfers.
29
- /// The default implementation iterates bundles and calls `transfer(from, input)` for each.
31
+ /// The default implementation iterates bundles and calls `transfer(value)` for each.
30
32
  /// @param from Source account identifier.
31
33
  /// @param request Full request bytes.
32
34
  /// @return Empty bytes (transfers produce no state output).
33
35
  function transfer(bytes32 from, bytes calldata request) internal virtual returns (bytes memory) {
34
36
  (Cur memory input, , ) = cursor(request, 1);
37
+ Tx memory value;
38
+ value.from = from;
35
39
 
36
40
  while (input.i < input.bound) {
37
- transfer(from, input);
41
+ Cur memory bundle = input.bundle();
42
+ (value.asset, value.meta, value.amount) = bundle.unpackAmount();
43
+ value.to = Accounts.ensure(bundle.unpackRecipient());
44
+ transfer(value);
38
45
  }
39
46
 
40
47
  input.complete();
@@ -3,15 +3,14 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- string constant ABI = "event RootZero(uint indexed host, bytes32 account, uint deadline, uint value)";
6
+ string constant ABI = "event RootZero(bytes32 indexed account, uint deadline, uint value)";
7
7
 
8
8
  /// @notice Emitted for root-level protocol actions (e.g. governance or protocol-wide operations).
9
9
  abstract contract RootZeroEvent is EventEmitter {
10
- /// @param host Host node ID where the action occurred.
11
10
  /// @param account Account identifier associated with the action.
12
11
  /// @param deadline Expiry timestamp of the action.
13
12
  /// @param value Native value associated with the action.
14
- event RootZero(uint indexed host, bytes32 account, uint deadline, uint value);
13
+ event RootZero(bytes32 indexed account, uint deadline, uint value);
15
14
 
16
15
  constructor() {
17
16
  emit EventAbi(ABI);
@@ -0,0 +1,34 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { PeerBase } from "./Base.sol";
5
+ import { TransferHook } from "../commands/Transfer.sol";
6
+ import { Cursors, Cur, Tx, Schemas } from "../Cursors.sol";
7
+
8
+ using Cursors for Cur;
9
+
10
+ string constant NAME = "peerSettle";
11
+
12
+ /// @title PeerSettle
13
+ /// @notice Peer that consumes peer-supplied TRANSACTION blocks through the shared transfer hook.
14
+ /// Each TRANSACTION block in the request calls `transfer(value)`. Restricted to trusted peers.
15
+ abstract contract PeerSettle is PeerBase, TransferHook {
16
+ uint internal immutable peerSettleId = peerId(NAME);
17
+
18
+ constructor() {
19
+ emit Peer(host, NAME, Schemas.Transaction, peerSettleId);
20
+ }
21
+
22
+ /// @notice Execute the peer-settle call.
23
+ function peerSettle(bytes calldata request) external payable onlyPeer returns (bytes memory) {
24
+ (Cur memory state, , ) = cursor(request, 1);
25
+
26
+ while (state.i < state.bound) {
27
+ Tx memory value = state.unpackTxValue();
28
+ transfer(value);
29
+ }
30
+
31
+ state.complete();
32
+ return "";
33
+ }
34
+ }
@@ -0,0 +1,72 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { Host } from "../core/Host.sol";
5
+ import { BorrowAgainstCustodyToBalance } from "../commands/Borrow.sol";
6
+ import { AssetAmount, HostAmount } from "../blocks/Schema.sol";
7
+ import { Cur, Cursors, Keys } from "../Cursors.sol";
8
+ import { Ids } from "../utils/Ids.sol";
9
+
10
+ using Cursors for Cur;
11
+
12
+ contract TestBorrowHost is Host, BorrowAgainstCustodyToBalance {
13
+ event BorrowCalled(bytes32 account, bytes32 asset, bytes32 meta, uint amount, bytes inputData);
14
+
15
+ bytes32 public returnAsset;
16
+ bytes32 public returnMeta;
17
+ uint public returnAmount;
18
+
19
+ constructor(address cmdr) Host(address(0), 1, "test") BorrowAgainstCustodyToBalance("") {
20
+ if (cmdr != address(0)) access(Ids.toHost(cmdr), true);
21
+ }
22
+
23
+ function setReturn(bytes32 asset, bytes32 meta, uint amount) external {
24
+ returnAsset = asset;
25
+ returnMeta = meta;
26
+ returnAmount = amount;
27
+ }
28
+
29
+ function borrowAgainstCustodyToBalance(
30
+ bytes32 account,
31
+ HostAmount memory custody,
32
+ Cur memory request
33
+ ) internal override returns (AssetAmount memory) {
34
+ if (request.i < request.len) {
35
+ bytes calldata inputData;
36
+ (bytes4 key, uint len) = request.peek(request.i);
37
+ if (key == Keys.Bundle) {
38
+ Cur memory bundle = request.bundle();
39
+ (key, len) = bundle.peek(bundle.i);
40
+ if (key == Keys.Route) {
41
+ inputData = bundle.unpackRoute();
42
+ } else {
43
+ uint next = bundle.i + 8 + len;
44
+ inputData = msg.data[bundle.offset + bundle.i:bundle.offset + next];
45
+ bundle.i = next;
46
+ }
47
+ } else if (key == Keys.Route) {
48
+ inputData = request.unpackRoute();
49
+ } else {
50
+ uint next = request.i + 8 + len;
51
+ inputData = msg.data[request.offset + request.i:request.offset + next];
52
+ request.i = next;
53
+ }
54
+ emit BorrowCalled(account, custody.asset, custody.meta, custody.amount, inputData);
55
+ } else {
56
+ emit BorrowCalled(account, custody.asset, custody.meta, custody.amount, "");
57
+ }
58
+ return AssetAmount({asset: returnAsset, meta: returnMeta, amount: returnAmount});
59
+ }
60
+
61
+ function getBorrowId() external view returns (uint) {
62
+ return borrowAgainstCustodyToBalanceId;
63
+ }
64
+
65
+ function getAdminAccount() external view returns (bytes32) {
66
+ return adminAccount;
67
+ }
68
+ }
69
+
70
+
71
+
72
+
@@ -0,0 +1,31 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { Host } from "../core/Host.sol";
5
+ import { Burn } from "../commands/Burn.sol";
6
+ import { Ids } from "../utils/Ids.sol";
7
+
8
+ contract TestBurnHost is Host, Burn {
9
+ event BurnCalled(bytes32 account, bytes32 asset, bytes32 meta, uint amount);
10
+
11
+ constructor(address cmdr)
12
+ Host(address(0), 1, "test")
13
+ Burn()
14
+ {
15
+ if (cmdr != address(0)) access(Ids.toHost(cmdr), true);
16
+ }
17
+
18
+ function burn(bytes32 account, bytes32 asset, bytes32 meta, uint amount)
19
+ internal override
20
+ returns (uint)
21
+ {
22
+ emit BurnCalled(account, asset, meta, amount);
23
+ return amount;
24
+ }
25
+
26
+ function getBurnId() external view returns (uint) { return burnId; }
27
+ function getAdminAccount() external view returns (bytes32) { return adminAccount; }
28
+ }
29
+
30
+
31
+
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { Host } from "../core/Host.sol";
5
+ import { Create } from "../commands/Create.sol";
6
+ import { Cursors, Cur, Keys } from "../Cursors.sol";
7
+ import { Ids } from "../utils/Ids.sol";
8
+
9
+ using Cursors for Cur;
10
+
11
+ contract TestCreateHost is Host, Create {
12
+ event CreateCalled(bytes32 account, bytes inputData);
13
+
14
+ constructor(address cmdr)
15
+ Host(address(0), 1, "test")
16
+ Create("")
17
+ {
18
+ if (cmdr != address(0)) access(Ids.toHost(cmdr), true);
19
+ }
20
+
21
+ function create(bytes32 account, Cur memory input) internal override {
22
+ (bytes4 key, uint len) = input.peek(input.i);
23
+ bytes calldata inputData;
24
+ if (key == Keys.Route) {
25
+ inputData = input.unpackRoute();
26
+ } else {
27
+ uint next = input.i + 8 + len;
28
+ inputData = msg.data[input.offset + input.i:input.offset + next];
29
+ input.i = next;
30
+ }
31
+ emit CreateCalled(account, inputData);
32
+ }
33
+
34
+ function getCreateId() external view returns (uint) { return createId; }
35
+ function getAdminAccount() external view returns (bytes32) { return adminAccount; }
36
+ }
37
+
38
+
39
+
40
+
@@ -0,0 +1,191 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { Tx, Sizes } from "../blocks/Schema.sol";
5
+ import { Cur, Cursors, Writer } from "../Cursors.sol";
6
+ import { Writers } from "../blocks/Writers.sol";
7
+
8
+ using Cursors for Cur;
9
+ using Writers for Writer;
10
+
11
+ contract TestCursorHelper {
12
+ function testBlockHeader(bytes4 key, uint len) external pure returns (uint) {
13
+ return Writers.toBlockHeader(key, len);
14
+ }
15
+
16
+ function testWriteBalanceBlock(bytes32 asset, bytes32 meta, uint amount) external pure returns (bytes memory) {
17
+ Writer memory w = Writers.alloc(Sizes.Balance);
18
+ w.appendBalance(asset, meta, amount);
19
+ return w.dst;
20
+ }
21
+
22
+ function testWriteCustodyBlock(
23
+ uint host_,
24
+ bytes32 asset,
25
+ bytes32 meta,
26
+ uint amount
27
+ ) external pure returns (bytes memory) {
28
+ Writer memory w = Writers.alloc(Sizes.Custody);
29
+ w.appendCustody(host_, asset, meta, amount);
30
+ return w.dst;
31
+ }
32
+
33
+ function testWriteTxBlock(
34
+ bytes32 from_,
35
+ bytes32 to_,
36
+ bytes32 asset,
37
+ bytes32 meta,
38
+ uint amount
39
+ ) external pure returns (bytes memory) {
40
+ Writer memory w = Writers.alloc(Sizes.Transaction);
41
+ w.appendTx(Tx({ from: from_, to: to_, asset: asset, meta: meta, amount: amount }));
42
+ return w.dst;
43
+ }
44
+
45
+ function testToBountyBlock(uint amount, bytes32 relayer) external pure returns (bytes memory) {
46
+ return Cursors.toBountyBlock(amount, relayer);
47
+ }
48
+
49
+ function testToBalanceBlock(bytes32 asset, bytes32 meta, uint amount) external pure returns (bytes memory) {
50
+ return Cursors.toBalanceBlock(asset, meta, amount);
51
+ }
52
+
53
+ function testToCustodyBlock(
54
+ uint host_,
55
+ bytes32 asset,
56
+ bytes32 meta,
57
+ uint amount
58
+ ) external pure returns (bytes memory) {
59
+ return Cursors.toCustodyBlock(host_, asset, meta, amount);
60
+ }
61
+
62
+ function testWriterFinishIncomplete() external pure returns (bytes memory) {
63
+ Writer memory w = Writers.alloc(Sizes.Balance);
64
+ return Writers.finish(w);
65
+ }
66
+
67
+ function testWriterFinish(bytes32 asset, bytes32 meta, uint amount) external pure returns (bytes memory) {
68
+ Writer memory w = Writers.alloc(Sizes.Balance * 2);
69
+ w.appendBalance(asset, meta, amount);
70
+ return Writers.finish(w);
71
+ }
72
+
73
+ function testUnpackBalance(bytes calldata source) external pure returns (bytes32 asset, bytes32 meta, uint amount) {
74
+ Cur memory cur = Cursors.open(source);
75
+ return cur.unpackBalance();
76
+ }
77
+
78
+ function testToTxValue(bytes calldata source) external pure returns (bytes32 from_, bytes32 to_, bytes32 asset, bytes32 meta, uint amount) {
79
+ Cur memory cur = Cursors.open(source);
80
+ Tx memory value = cur.unpackTxValue();
81
+ return (value.from, value.to, value.asset, value.meta, value.amount);
82
+ }
83
+
84
+ function testPrimeRun(bytes calldata source, uint group)
85
+ external
86
+ pure
87
+ returns (bytes4 key, uint count, uint quotient, uint offset, uint i, uint len, uint bound)
88
+ {
89
+ uint sourceOffset;
90
+ assembly ("memory-safe") {
91
+ sourceOffset := source.offset
92
+ }
93
+ Cur memory cur = Cursors.open(source);
94
+ (key, count, quotient) = cur.primeRun(group);
95
+ return (key, count, quotient, cur.offset - sourceOffset, cur.i, cur.len, cur.bound);
96
+ }
97
+
98
+ function testPeek(bytes calldata source, uint i) external pure returns (bytes4 key, uint len) {
99
+ Cur memory cur = Cursors.open(source);
100
+ return cur.peek(i);
101
+ }
102
+
103
+ function testCountRun(bytes calldata source, uint i, bytes4 key) external pure returns (uint total, uint next) {
104
+ Cur memory cur = Cursors.open(source);
105
+ return cur.countRun(i, key);
106
+ }
107
+
108
+ function testBundle(bytes calldata source) external pure returns (uint inputI, uint offset, uint len) {
109
+ uint sourceOffset;
110
+ assembly ("memory-safe") {
111
+ sourceOffset := source.offset
112
+ }
113
+ Cur memory cur = Cursors.open(source);
114
+ Cur memory out = cur.bundle();
115
+ return (cur.i, out.offset - sourceOffset, out.len);
116
+ }
117
+
118
+ function testUnpackStep(bytes calldata source) external pure returns (uint target, uint value, bytes calldata req, uint i) {
119
+ Cur memory cur = Cursors.open(source);
120
+ (target, value, req) = cur.unpackStep();
121
+ return (target, value, req, cur.i);
122
+ }
123
+
124
+ function testRequireAmount(
125
+ bytes calldata source,
126
+ bytes32 asset,
127
+ bytes32 meta
128
+ ) external pure returns (uint amount, uint i) {
129
+ Cur memory cur = Cursors.open(source);
130
+ amount = cur.requireAmount(asset, meta);
131
+ i = cur.i;
132
+ }
133
+
134
+ function testRequireAuth(bytes calldata source, uint cid) external pure returns (uint deadline, bytes calldata proof, uint i) {
135
+ Cur memory cur = Cursors.open(source);
136
+ (deadline, proof) = cur.requireAuth(cid);
137
+ return (deadline, proof, cur.i);
138
+ }
139
+
140
+ function testNodeAfter(bytes calldata source, uint group, uint backup) external pure returns (uint) {
141
+ Cur memory cur = Cursors.open(source);
142
+ cur.primeRun(group);
143
+ return cur.nodeAfter(backup);
144
+ }
145
+
146
+ function testRecipientAfter(bytes calldata source, uint group, bytes32 backup) external pure returns (bytes32) {
147
+ Cur memory cur = Cursors.open(source);
148
+ cur.primeRun(group);
149
+ return cur.recipientAfter(backup);
150
+ }
151
+
152
+ function testAuthLast(
153
+ bytes calldata source,
154
+ uint group,
155
+ uint cid
156
+ ) external pure returns (bytes32 hash, uint deadline, bytes calldata proof) {
157
+ Cur memory cur = Cursors.open(source);
158
+ cur.primeRun(group);
159
+ return cur.authLast(cid);
160
+ }
161
+
162
+ function testCursorCompleteEmpty(bytes calldata source, uint group) external pure returns (bool) {
163
+ Cur memory cur = Cursors.open(source);
164
+ cur.primeRun(group);
165
+ cur.complete();
166
+ return true;
167
+ }
168
+
169
+ function testCursorCompletePartial(bytes calldata source, uint group) external pure returns (bool) {
170
+ Cur memory cur = Cursors.open(source);
171
+ cur.primeRun(group);
172
+ if (cur.bound > 0) {
173
+ (, uint len) = cur.peek(cur.i);
174
+ cur.i += 8 + len;
175
+ }
176
+ cur.complete();
177
+ return true;
178
+ }
179
+
180
+ function testCursorCompleteConsumed(bytes calldata source, uint group) external pure returns (bool) {
181
+ Cur memory cur = Cursors.open(source);
182
+ cur.primeRun(group);
183
+ while (cur.i < cur.bound) {
184
+ (, uint len) = cur.peek(cur.i);
185
+ cur.i += 8 + len;
186
+ }
187
+ cur.complete();
188
+ return true;
189
+ }
190
+
191
+ }
@@ -0,0 +1,9 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { HostDiscovery } from "../core/Host.sol";
5
+
6
+ contract TestDiscovery is HostDiscovery {}
7
+
8
+
9
+
@@ -0,0 +1,19 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { ECDSA } from "../utils/ECDSA.sol";
5
+
6
+ contract TestECDSA {
7
+ using ECDSA for bytes32;
8
+
9
+ function testToEthSignedMessageHash(bytes32 hash) external pure returns (bytes32) {
10
+ return hash.toEthSignedMessageHash();
11
+ }
12
+
13
+ function testTryRecoverCalldata(bytes32 hash, bytes calldata signature) external pure returns (address) {
14
+ return hash.tryRecoverCalldata(signature);
15
+ }
16
+ }
17
+
18
+
19
+