@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.
- package/{Cursors.sol → contracts/Cursors.sol} +1 -2
- package/{blocks → contracts/blocks}/Cursors.sol +18 -0
- package/{blocks → contracts/blocks}/Keys.sol +1 -1
- package/{blocks → contracts/blocks}/Schema.sol +1 -1
- package/{blocks → contracts/blocks}/Writers.sol +2 -2
- package/{commands → contracts/commands}/Provision.sol +1 -3
- package/{commands → contracts/commands}/Settle.sol +4 -8
- package/{commands → contracts/commands}/Transfer.sol +18 -11
- package/{events → contracts/events}/RootZero.sol +2 -3
- package/contracts/peer/Settle.sol +34 -0
- package/contracts/test/TestBorrowHost.sol +72 -0
- package/contracts/test/TestBurnHost.sol +31 -0
- package/contracts/test/TestCreateHost.sol +40 -0
- package/contracts/test/TestCursorHelper.sol +191 -0
- package/contracts/test/TestDiscovery.sol +9 -0
- package/contracts/test/TestECDSA.sol +19 -0
- package/contracts/test/TestHost.sol +218 -0
- package/contracts/test/TestLiquidityHost.sol +167 -0
- package/contracts/test/TestMintHost.sol +50 -0
- package/contracts/test/TestOperation.sol +21 -0
- package/contracts/test/TestPeerHost.sol +57 -0
- package/contracts/test/TestReclaimHost.sol +55 -0
- package/contracts/test/TestRejectEther.sol +11 -0
- package/contracts/test/TestRemoveHost.sol +40 -0
- package/contracts/test/TestSupplyHost.sol +25 -0
- package/contracts/test/TestSwapHost.sol +67 -0
- package/contracts/test/TestUtils.sol +184 -0
- package/contracts/test/TestValidator.sol +13 -0
- package/{utils → contracts/utils}/Accounts.sol +11 -0
- package/package.json +33 -17
- package/blocks/Mem.sol +0 -188
- package/docs/GETTING_STARTED.md +0 -286
- /package/{Commands.sol → contracts/Commands.sol} +0 -0
- /package/{Core.sol → contracts/Core.sol} +0 -0
- /package/{Events.sol → contracts/Events.sol} +0 -0
- /package/{Utils.sol → contracts/Utils.sol} +0 -0
- /package/{commands → contracts/commands}/Base.sol +0 -0
- /package/{commands → contracts/commands}/Borrow.sol +0 -0
- /package/{commands → contracts/commands}/Burn.sol +0 -0
- /package/{commands → contracts/commands}/Create.sol +0 -0
- /package/{commands → contracts/commands}/Credit.sol +0 -0
- /package/{commands → contracts/commands}/Debit.sol +0 -0
- /package/{commands → contracts/commands}/Deposit.sol +0 -0
- /package/{commands → contracts/commands}/Liquidate.sol +0 -0
- /package/{commands → contracts/commands}/Liquidity.sol +0 -0
- /package/{commands → contracts/commands}/Mint.sol +0 -0
- /package/{commands → contracts/commands}/Pipe.sol +0 -0
- /package/{commands → contracts/commands}/Reclaim.sol +0 -0
- /package/{commands → contracts/commands}/Redeem.sol +0 -0
- /package/{commands → contracts/commands}/Remove.sol +0 -0
- /package/{commands → contracts/commands}/Repay.sol +0 -0
- /package/{commands → contracts/commands}/Stake.sol +0 -0
- /package/{commands → contracts/commands}/Supply.sol +0 -0
- /package/{commands → contracts/commands}/Swap.sol +0 -0
- /package/{commands → contracts/commands}/Unstake.sol +0 -0
- /package/{commands → contracts/commands}/Withdraw.sol +0 -0
- /package/{commands → contracts/commands}/admin/Allocate.sol +0 -0
- /package/{commands → contracts/commands}/admin/AllowAssets.sol +0 -0
- /package/{commands → contracts/commands}/admin/Authorize.sol +0 -0
- /package/{commands → contracts/commands}/admin/DenyAssets.sol +0 -0
- /package/{commands → contracts/commands}/admin/Destroy.sol +0 -0
- /package/{commands → contracts/commands}/admin/Init.sol +0 -0
- /package/{commands → contracts/commands}/admin/Relocate.sol +0 -0
- /package/{commands → contracts/commands}/admin/Unauthorize.sol +0 -0
- /package/{core → contracts/core}/Access.sol +0 -0
- /package/{core → contracts/core}/Balances.sol +0 -0
- /package/{core → contracts/core}/Host.sol +0 -0
- /package/{core → contracts/core}/Operation.sol +0 -0
- /package/{core → contracts/core}/Validator.sol +0 -0
- /package/{events → contracts/events}/Access.sol +0 -0
- /package/{events → contracts/events}/Asset.sol +0 -0
- /package/{events → contracts/events}/Balance.sol +0 -0
- /package/{events → contracts/events}/Collateral.sol +0 -0
- /package/{events → contracts/events}/Command.sol +0 -0
- /package/{events → contracts/events}/Debt.sol +0 -0
- /package/{events → contracts/events}/Deposit.sol +0 -0
- /package/{events → contracts/events}/Emitter.sol +0 -0
- /package/{events → contracts/events}/Governed.sol +0 -0
- /package/{events → contracts/events}/HostAnnounced.sol +0 -0
- /package/{events → contracts/events}/Listing.sol +0 -0
- /package/{events → contracts/events}/Peer.sol +0 -0
- /package/{events → contracts/events}/Quote.sol +0 -0
- /package/{events → contracts/events}/Withdraw.sol +0 -0
- /package/{interfaces → contracts/interfaces}/IHostDiscovery.sol +0 -0
- /package/{peer → contracts/peer}/AllowAssets.sol +0 -0
- /package/{peer → contracts/peer}/Base.sol +0 -0
- /package/{peer → contracts/peer}/DenyAssets.sol +0 -0
- /package/{peer → contracts/peer}/Pull.sol +0 -0
- /package/{peer → contracts/peer}/Push.sol +0 -0
- /package/{utils → contracts/utils}/Assets.sol +0 -0
- /package/{utils → contracts/utils}/ECDSA.sol +0 -0
- /package/{utils → contracts/utils}/Ids.sol +0 -0
- /package/{utils → contracts/utils}/Layout.sol +0 -0
- /package/{utils → contracts/utils}/State.sol +0 -0
- /package/{utils → contracts/utils}/Utils.sol +0 -0
- /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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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,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
|
+
|