@rootzero/contracts 1.4.0 → 1.6.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 +40 -0
- package/Core.sol +4 -2
- package/Endpoints.sol +5 -3
- package/Events.sol +2 -1
- package/README.md +58 -31
- package/Utils.sol +4 -3
- package/blocks/Cursors.sol +107 -143
- package/blocks/Keys.sol +15 -15
- package/blocks/Schema.sol +27 -28
- package/blocks/Writers.sol +26 -33
- package/commands/Base.sol +2 -2
- package/commands/Burn.sol +3 -4
- package/commands/Credit.sol +3 -4
- package/commands/Debit.sol +4 -5
- package/commands/Deposit.sol +8 -10
- package/commands/Payout.sol +3 -6
- package/commands/Withdraw.sol +3 -4
- package/commands/admin/AllowAssets.sol +7 -9
- package/commands/admin/Allowance.sol +5 -7
- package/commands/admin/Appoint.sol +2 -3
- package/commands/admin/Authorize.sol +2 -3
- package/commands/admin/Base.sol +9 -0
- package/commands/admin/DenyAssets.sol +7 -9
- package/commands/admin/Destroy.sol +2 -3
- package/commands/admin/Dismiss.sol +2 -3
- package/commands/admin/Execute.sol +4 -5
- package/commands/admin/Init.sol +2 -3
- package/commands/admin/Label.sol +2 -3
- package/commands/admin/Unauthorize.sol +2 -3
- package/core/Access.sol +2 -2
- package/core/Balances.sol +10 -11
- package/core/Calls.sol +7 -7
- package/core/Commitments.sol +19 -0
- package/core/Escrows.sol +34 -0
- package/core/Host.sol +2 -2
- package/core/Runtime.sol +11 -6
- package/core/Types.sol +0 -14
- package/docs/Schema.md +29 -10
- package/events/Asset.sol +17 -3
- package/events/Balance.sol +2 -3
- package/events/Commitment.sol +19 -0
- package/events/Locked.sol +2 -3
- package/events/Position.sol +2 -3
- package/events/Received.sol +2 -3
- package/events/Spent.sol +2 -3
- package/events/Unlocked.sol +2 -3
- package/guards/Base.sol +4 -4
- package/package.json +1 -1
- package/peer/AllowAssets.sol +3 -3
- package/peer/Allowance.sol +2 -2
- package/peer/Base.sol +4 -4
- package/peer/Credit.sol +10 -10
- package/peer/Debit.sol +10 -10
- package/peer/DenyAssets.sol +3 -3
- package/peer/Recover.sol +51 -0
- package/peer/Redeem.sol +48 -0
- package/peer/Settle.sol +3 -3
- package/queries/Assets.sol +7 -8
- package/queries/Balances.sol +8 -9
- package/queries/Base.sol +4 -4
- package/queries/Positions.sol +4 -6
- package/utils/Accounts.sol +76 -58
- package/utils/Assets.sol +55 -115
- package/utils/Ids.sol +33 -233
- package/utils/Layout.sol +11 -17
- package/utils/Nodes.sol +263 -0
- package/utils/Utils.sol +9 -24
- package/peer/BalancePull.sol +0 -49
package/events/Position.sol
CHANGED
|
@@ -6,16 +6,15 @@ import {EventEmitter} from "./Emitter.sol";
|
|
|
6
6
|
/// @notice Emitted when the reported value of an asset-backed position changes or is observed.
|
|
7
7
|
/// A value of 0 should be interpreted as a closed position.
|
|
8
8
|
abstract contract PositionEvent is EventEmitter {
|
|
9
|
-
string private constant ABI = "event Position(bytes32 indexed account, bytes32 asset,
|
|
9
|
+
string private constant ABI = "event Position(bytes32 indexed account, bytes32 asset, uint value, uint32 action, uint context, uint queryId)";
|
|
10
10
|
|
|
11
11
|
/// @param account Account identifier that owns or is associated with the position.
|
|
12
12
|
/// @param asset Asset identifier for the asset class.
|
|
13
|
-
/// @param meta Asset metadata slot carrying the position context.
|
|
14
13
|
/// @param value Context-specific position value; 0 indicates a closed position.
|
|
15
14
|
/// @param action Primary operation hint from `Actions`.
|
|
16
15
|
/// @param context Reserved context value for future use.
|
|
17
16
|
/// @param queryId Query ID associated with the position lookup or reporting context.
|
|
18
|
-
event Position(bytes32 indexed account, bytes32 asset,
|
|
17
|
+
event Position(bytes32 indexed account, bytes32 asset, uint value, uint32 action, uint context, uint queryId);
|
|
19
18
|
|
|
20
19
|
constructor() {
|
|
21
20
|
emit EventAbi(ABI);
|
package/events/Received.sol
CHANGED
|
@@ -5,15 +5,14 @@ import { EventEmitter } from "./Emitter.sol";
|
|
|
5
5
|
|
|
6
6
|
/// @notice Emitted when an account receives an asset in a protocol operation.
|
|
7
7
|
abstract contract ReceivedEvent is EventEmitter {
|
|
8
|
-
string private constant ABI = "event Received(bytes32 indexed account, bytes32 asset,
|
|
8
|
+
string private constant ABI = "event Received(bytes32 indexed account, bytes32 asset, uint amount, uint32 action, uint context)";
|
|
9
9
|
|
|
10
10
|
/// @param account Account identifier that received the asset.
|
|
11
11
|
/// @param asset Asset identifier.
|
|
12
|
-
/// @param meta Asset metadata slot.
|
|
13
12
|
/// @param amount Amount received.
|
|
14
13
|
/// @param action Primary operation hint from `Actions`.
|
|
15
14
|
/// @param context Reserved context value for future use.
|
|
16
|
-
event Received(bytes32 indexed account, bytes32 asset,
|
|
15
|
+
event Received(bytes32 indexed account, bytes32 asset, uint amount, uint32 action, uint context);
|
|
17
16
|
|
|
18
17
|
constructor() {
|
|
19
18
|
emit EventAbi(ABI);
|
package/events/Spent.sol
CHANGED
|
@@ -5,15 +5,14 @@ import { EventEmitter } from "./Emitter.sol";
|
|
|
5
5
|
|
|
6
6
|
/// @notice Emitted when an account spends an asset in a protocol operation.
|
|
7
7
|
abstract contract SpentEvent is EventEmitter {
|
|
8
|
-
string private constant ABI = "event Spent(bytes32 indexed account, bytes32 asset,
|
|
8
|
+
string private constant ABI = "event Spent(bytes32 indexed account, bytes32 asset, uint amount, uint32 action, uint context)";
|
|
9
9
|
|
|
10
10
|
/// @param account Account identifier that spent the asset.
|
|
11
11
|
/// @param asset Asset identifier.
|
|
12
|
-
/// @param meta Asset metadata slot.
|
|
13
12
|
/// @param amount Amount spent.
|
|
14
13
|
/// @param action Primary operation hint from `Actions`.
|
|
15
14
|
/// @param context Reserved context value for future use.
|
|
16
|
-
event Spent(bytes32 indexed account, bytes32 asset,
|
|
15
|
+
event Spent(bytes32 indexed account, bytes32 asset, uint amount, uint32 action, uint context);
|
|
17
16
|
|
|
18
17
|
constructor() {
|
|
19
18
|
emit EventAbi(ABI);
|
package/events/Unlocked.sol
CHANGED
|
@@ -5,15 +5,14 @@ import { EventEmitter } from "./Emitter.sol";
|
|
|
5
5
|
|
|
6
6
|
/// @notice Emitted when an account unlocks an asset in a protocol operation.
|
|
7
7
|
abstract contract UnlockedEvent is EventEmitter {
|
|
8
|
-
string private constant ABI = "event Unlocked(bytes32 indexed account, bytes32 asset,
|
|
8
|
+
string private constant ABI = "event Unlocked(bytes32 indexed account, bytes32 asset, uint amount, uint32 action, uint context)";
|
|
9
9
|
|
|
10
10
|
/// @param account Account identifier that unlocked the asset.
|
|
11
11
|
/// @param asset Asset identifier.
|
|
12
|
-
/// @param meta Asset metadata slot.
|
|
13
12
|
/// @param amount Amount unlocked.
|
|
14
13
|
/// @param action Primary operation hint from `Actions`.
|
|
15
14
|
/// @param context Reserved context value for future use.
|
|
16
|
-
event Unlocked(bytes32 indexed account, bytes32 asset,
|
|
15
|
+
event Unlocked(bytes32 indexed account, bytes32 asset, uint amount, uint32 action, uint context);
|
|
17
16
|
|
|
18
17
|
constructor() {
|
|
19
18
|
emit EventAbi(ABI);
|
package/guards/Base.sol
CHANGED
|
@@ -4,16 +4,16 @@ pragma solidity ^0.8.33;
|
|
|
4
4
|
import {AccessControl} from "../core/Access.sol";
|
|
5
5
|
import {GuardEvent} from "../events/Guard.sol";
|
|
6
6
|
import {LabeledEvent} from "../events/Labeled.sol";
|
|
7
|
-
import {
|
|
7
|
+
import {Nodes} from "../utils/Nodes.sol";
|
|
8
8
|
|
|
9
9
|
/// @notice ABI-encode a guard action call from a target guard ID and request block stream.
|
|
10
|
-
/// @dev Derives the function selector from `target` via `
|
|
10
|
+
/// @dev Derives the function selector from `target` via `Nodes.guardSelector(target)`.
|
|
11
11
|
/// Reverts if `target` is not a valid guard ID.
|
|
12
12
|
/// @param target Destination guard action node ID embedding the target selector.
|
|
13
13
|
/// @param request Input block stream for the guard invocation.
|
|
14
14
|
/// @return ABI-encoded calldata for the guard action entry point.
|
|
15
15
|
function encodeGuardCall(uint target, bytes calldata request) pure returns (bytes memory) {
|
|
16
|
-
bytes4 selector =
|
|
16
|
+
bytes4 selector = Nodes.guardSelector(target);
|
|
17
17
|
return abi.encodeWithSelector(selector, request);
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -31,6 +31,6 @@ abstract contract GuardBase is AccessControl, GuardEvent, LabeledEvent {
|
|
|
31
31
|
/// @param selector Guard action entrypoint selector.
|
|
32
32
|
/// @return Guard action node ID.
|
|
33
33
|
function guardId(bytes4 selector) internal view returns (uint) {
|
|
34
|
-
return
|
|
34
|
+
return Nodes.toGuard(selector, address(this));
|
|
35
35
|
}
|
|
36
36
|
}
|
package/package.json
CHANGED
package/peer/AllowAssets.sol
CHANGED
|
@@ -12,7 +12,7 @@ interface IPeerAllowAssets {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/// @title PeerAllowAssets
|
|
15
|
-
/// @notice Peer that permits a list of
|
|
15
|
+
/// @notice Peer that permits a list of assets on behalf of a peer host.
|
|
16
16
|
/// Each ASSET block in the request calls `allowAsset`. Restricted to trusted peers.
|
|
17
17
|
abstract contract PeerAllowAssets is PeerBase, AllowAssetsHook, IPeerAllowAssets {
|
|
18
18
|
uint internal immutable peerAllowAssetsId = peerId(this.peerAllowAssets.selector);
|
|
@@ -29,8 +29,8 @@ abstract contract PeerAllowAssets is PeerBase, AllowAssetsHook, IPeerAllowAssets
|
|
|
29
29
|
(Cur memory assets, , ) = Cursors.init(request, 1);
|
|
30
30
|
|
|
31
31
|
while (assets.i < assets.len) {
|
|
32
|
-
|
|
33
|
-
allowAsset(asset
|
|
32
|
+
bytes32 asset = assets.unpackAsset();
|
|
33
|
+
allowAsset(asset);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
assets.complete();
|
package/peer/Allowance.sol
CHANGED
|
@@ -31,8 +31,8 @@ abstract contract PeerAllowance is PeerBase, AllowanceHook, IPeerAllowance {
|
|
|
31
31
|
uint peer = caller();
|
|
32
32
|
|
|
33
33
|
while (amounts.i < amounts.len) {
|
|
34
|
-
(bytes32 asset,
|
|
35
|
-
allowance(peer, asset,
|
|
34
|
+
(bytes32 asset, uint amount) = amounts.unpackAmount();
|
|
35
|
+
allowance(peer, asset, amount);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
amounts.complete();
|
package/peer/Base.sol
CHANGED
|
@@ -4,16 +4,16 @@ pragma solidity ^0.8.33;
|
|
|
4
4
|
import { NodeCalls } from "../core/Calls.sol";
|
|
5
5
|
import { PeerEvent } from "../events/Peer.sol";
|
|
6
6
|
import { LabeledEvent } from "../events/Labeled.sol";
|
|
7
|
-
import {
|
|
7
|
+
import { Nodes } from "../utils/Nodes.sol";
|
|
8
8
|
|
|
9
9
|
/// @notice ABI-encode a peer call from a target peer ID and request block stream.
|
|
10
|
-
/// @dev Derives the function selector from `target` via `
|
|
10
|
+
/// @dev Derives the function selector from `target` via `Nodes.peerSelector(target)`.
|
|
11
11
|
/// Reverts if `target` is not a valid peer ID.
|
|
12
12
|
/// @param target Destination peer node ID embedding the target selector.
|
|
13
13
|
/// @param request Input block stream for the peer invocation.
|
|
14
14
|
/// @return ABI-encoded calldata for the peer entry point.
|
|
15
15
|
function encodePeerCall(uint target, bytes calldata request) pure returns (bytes memory) {
|
|
16
|
-
bytes4 selector =
|
|
16
|
+
bytes4 selector = Nodes.peerSelector(target);
|
|
17
17
|
return abi.encodeWithSelector(selector, request);
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -36,6 +36,6 @@ abstract contract PeerBase is NodeCalls, PeerEvent, LabeledEvent {
|
|
|
36
36
|
/// @param selector Peer entrypoint selector.
|
|
37
37
|
/// @return Peer node ID.
|
|
38
38
|
function peerId(bytes4 selector) internal view returns (uint) {
|
|
39
|
-
return
|
|
39
|
+
return Nodes.toPeer(selector, address(this));
|
|
40
40
|
}
|
|
41
41
|
}
|
package/peer/Credit.sol
CHANGED
|
@@ -7,30 +7,30 @@ import { Cursors, Cur, Forms } from "../Cursors.sol";
|
|
|
7
7
|
|
|
8
8
|
using Cursors for Cur;
|
|
9
9
|
|
|
10
|
-
interface
|
|
11
|
-
function
|
|
10
|
+
interface IPeerCreditAccount {
|
|
11
|
+
function peerCreditAccount(bytes calldata request) external returns (bytes memory);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/// @title
|
|
14
|
+
/// @title PeerCreditAccount
|
|
15
15
|
/// @notice Peer that lets a trusted peer credit supplied accounts directly.
|
|
16
16
|
/// Each ACCOUNT_AMOUNT block calls `creditAccount` for its account.
|
|
17
|
-
abstract contract
|
|
18
|
-
uint internal immutable
|
|
17
|
+
abstract contract PeerCreditAccount is PeerBase, CreditAccountHook, IPeerCreditAccount {
|
|
18
|
+
uint internal immutable peerCreditAccountId = peerId(this.peerCreditAccount.selector);
|
|
19
19
|
|
|
20
20
|
constructor() {
|
|
21
|
-
emit Peer(host,
|
|
22
|
-
emit Labeled(
|
|
21
|
+
emit Peer(host, peerCreditAccountId, "1:0", Forms.AccountAmount, "", false);
|
|
22
|
+
emit Labeled(peerCreditAccountId, bytes32(0), "peerCreditAccount");
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/// @notice Execute the peer-credit call.
|
|
26
26
|
/// @param request ACCOUNT_AMOUNT block stream supplied by the trusted peer.
|
|
27
27
|
/// @return Empty response bytes.
|
|
28
|
-
function
|
|
28
|
+
function peerCreditAccount(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
29
29
|
(Cur memory amounts, , ) = Cursors.init(request, 1);
|
|
30
30
|
|
|
31
31
|
while (amounts.i < amounts.len) {
|
|
32
|
-
(bytes32 account, bytes32 asset,
|
|
33
|
-
creditAccount(account, asset,
|
|
32
|
+
(bytes32 account, bytes32 asset, uint amount) = amounts.unpackAccountAmount();
|
|
33
|
+
creditAccount(account, asset, amount);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
amounts.complete();
|
package/peer/Debit.sol
CHANGED
|
@@ -7,30 +7,30 @@ import { Cursors, Cur, Forms } from "../Cursors.sol";
|
|
|
7
7
|
|
|
8
8
|
using Cursors for Cur;
|
|
9
9
|
|
|
10
|
-
interface
|
|
11
|
-
function
|
|
10
|
+
interface IPeerDebitAccount {
|
|
11
|
+
function peerDebitAccount(bytes calldata request) external returns (bytes memory);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/// @title
|
|
14
|
+
/// @title PeerDebitAccount
|
|
15
15
|
/// @notice Peer that lets a trusted peer debit supplied accounts directly.
|
|
16
16
|
/// Each ACCOUNT_AMOUNT block calls `debitAccount` for its account.
|
|
17
|
-
abstract contract
|
|
18
|
-
uint internal immutable
|
|
17
|
+
abstract contract PeerDebitAccount is PeerBase, DebitAccountHook, IPeerDebitAccount {
|
|
18
|
+
uint internal immutable peerDebitAccountId = peerId(this.peerDebitAccount.selector);
|
|
19
19
|
|
|
20
20
|
constructor() {
|
|
21
|
-
emit Peer(host,
|
|
22
|
-
emit Labeled(
|
|
21
|
+
emit Peer(host, peerDebitAccountId, "1:0", Forms.AccountAmount, "", false);
|
|
22
|
+
emit Labeled(peerDebitAccountId, bytes32(0), "peerDebitAccount");
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/// @notice Execute the peer-debit call.
|
|
26
26
|
/// @param request ACCOUNT_AMOUNT block stream supplied by the trusted peer.
|
|
27
27
|
/// @return Empty response bytes.
|
|
28
|
-
function
|
|
28
|
+
function peerDebitAccount(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
29
29
|
(Cur memory amounts, , ) = Cursors.init(request, 1);
|
|
30
30
|
|
|
31
31
|
while (amounts.i < amounts.len) {
|
|
32
|
-
(bytes32 account, bytes32 asset,
|
|
33
|
-
debitAccount(account, asset,
|
|
32
|
+
(bytes32 account, bytes32 asset, uint amount) = amounts.unpackAccountAmount();
|
|
33
|
+
debitAccount(account, asset, amount);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
amounts.complete();
|
package/peer/DenyAssets.sol
CHANGED
|
@@ -12,7 +12,7 @@ interface IPeerDenyAssets {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/// @title PeerDenyAssets
|
|
15
|
-
/// @notice Peer that blocks a list of
|
|
15
|
+
/// @notice Peer that blocks a list of assets on behalf of a peer host.
|
|
16
16
|
/// Each ASSET block in the request calls `denyAsset`. Restricted to trusted peers.
|
|
17
17
|
abstract contract PeerDenyAssets is PeerBase, DenyAssetsHook, IPeerDenyAssets {
|
|
18
18
|
uint internal immutable peerDenyAssetsId = peerId(this.peerDenyAssets.selector);
|
|
@@ -29,8 +29,8 @@ abstract contract PeerDenyAssets is PeerBase, DenyAssetsHook, IPeerDenyAssets {
|
|
|
29
29
|
(Cur memory assets, , ) = Cursors.init(request, 1);
|
|
30
30
|
|
|
31
31
|
while (assets.i < assets.len) {
|
|
32
|
-
|
|
33
|
-
denyAsset(asset
|
|
32
|
+
bytes32 asset = assets.unpackAsset();
|
|
33
|
+
denyAsset(asset);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
assets.complete();
|
package/peer/Recover.sol
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {PeerBase} from "./Base.sol";
|
|
5
|
+
import {Cursors, Cur, Schemas} from "../Cursors.sol";
|
|
6
|
+
|
|
7
|
+
using Cursors for Cur;
|
|
8
|
+
|
|
9
|
+
interface IPeerRecover {
|
|
10
|
+
function peerRecover(bytes calldata request) external returns (bytes memory);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
abstract contract RecoverHook {
|
|
14
|
+
/// @notice Override to recover one incoming pipe context from a peer host.
|
|
15
|
+
/// @dev Implementations may refund, retry, compensate, reconcile, or otherwise
|
|
16
|
+
/// handle the supplied state and remaining steps.
|
|
17
|
+
/// @param account Account identifier for the recovery context.
|
|
18
|
+
/// @param state Embedded recovery state block stream.
|
|
19
|
+
/// @param steps Embedded recovery step block stream.
|
|
20
|
+
function recover(bytes32 account, bytes calldata state, bytes calldata steps) internal virtual;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// @title PeerRecover
|
|
24
|
+
/// @notice Peer endpoint for recovering an interrupted or failed pipe context.
|
|
25
|
+
/// @dev Commonly used when a cross-chain pipe fails at its destination, but the
|
|
26
|
+
/// hook is host-defined and may implement any recovery strategy. Each PIPE
|
|
27
|
+
/// block carries chain resources plus a CONTEXT block; the nested context
|
|
28
|
+
/// is passed to the recovery hook and resources are not allocated.
|
|
29
|
+
abstract contract PeerRecover is PeerBase, RecoverHook, IPeerRecover {
|
|
30
|
+
uint internal immutable peerRecoverId = peerId(this.peerRecover.selector);
|
|
31
|
+
|
|
32
|
+
constructor() {
|
|
33
|
+
emit Peer(host, peerRecoverId, "1:0", Schemas.Pipe, "", false);
|
|
34
|
+
emit Labeled(peerRecoverId, bytes32(0), "peerRecover");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// @notice Forward peer-supplied recovery pipes to the host-defined recovery hook.
|
|
38
|
+
/// @param request PIPE block stream supplied by the trusted peer.
|
|
39
|
+
/// @return Empty response bytes.
|
|
40
|
+
function peerRecover(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
41
|
+
(Cur memory input, , ) = Cursors.init(request, 1);
|
|
42
|
+
|
|
43
|
+
while (input.i < input.len) {
|
|
44
|
+
(, bytes32 account, bytes calldata state, bytes calldata steps) = input.unpackPipe();
|
|
45
|
+
recover(account, state, steps);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
input.complete();
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
}
|
package/peer/Redeem.sol
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {PeerBase} from "./Base.sol";
|
|
5
|
+
import {Cursors, Cur, Schemas} from "../Cursors.sol";
|
|
6
|
+
|
|
7
|
+
using Cursors for Cur;
|
|
8
|
+
|
|
9
|
+
interface IPeerRedeemBalance {
|
|
10
|
+
function peerRedeemBalance(bytes calldata request) external returns (bytes memory);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
abstract contract RedeemBalanceHook {
|
|
14
|
+
/// @notice Override to redeem one balance claim from a peer host into local assets.
|
|
15
|
+
/// @param peer Peer host node ID for this request.
|
|
16
|
+
/// @param asset Asset identifier to redeem locally.
|
|
17
|
+
/// @param amount Amount to redeem in the asset's native units.
|
|
18
|
+
function redeemBalance(uint peer, bytes32 asset, uint amount) internal virtual;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// @title PeerRedeemBalance
|
|
22
|
+
/// @notice Peer that redeems balance state from a peer host into local assets.
|
|
23
|
+
/// Each BALANCE block in the request calls `redeemBalance(peer, asset, amount)`.
|
|
24
|
+
/// Restricted to trusted peers.
|
|
25
|
+
abstract contract PeerRedeemBalance is PeerBase, RedeemBalanceHook, IPeerRedeemBalance {
|
|
26
|
+
uint internal immutable peerRedeemBalanceId = peerId(this.peerRedeemBalance.selector);
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
emit Peer(host, peerRedeemBalanceId, "1:0", Schemas.Balance, "", false);
|
|
30
|
+
emit Labeled(peerRedeemBalanceId, bytes32(0), "peerRedeemBalance");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// @notice Execute the balance redemption peer call.
|
|
34
|
+
/// @param request BALANCE block stream supplied by the trusted peer.
|
|
35
|
+
/// @return Empty response bytes.
|
|
36
|
+
function peerRedeemBalance(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
37
|
+
(Cur memory input, , ) = Cursors.init(request, 1);
|
|
38
|
+
uint peer = caller();
|
|
39
|
+
|
|
40
|
+
while (input.i < input.len) {
|
|
41
|
+
(bytes32 asset, uint amount) = input.unpackBalance();
|
|
42
|
+
redeemBalance(peer, asset, amount);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
input.complete();
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
}
|
package/peer/Settle.sol
CHANGED
|
@@ -30,9 +30,9 @@ abstract contract PeerSettle is PeerBase, DebitAccountHook, CreditAccountHook, I
|
|
|
30
30
|
(Cur memory state, , ) = Cursors.init(request, 1);
|
|
31
31
|
|
|
32
32
|
while (state.i < state.len) {
|
|
33
|
-
(bytes32 from, bytes32 to, bytes32 asset,
|
|
34
|
-
if (from != 0) debitAccount(from, asset,
|
|
35
|
-
if (to != 0) creditAccount(to, asset,
|
|
33
|
+
(bytes32 from, bytes32 to, bytes32 asset, uint amount) = state.unpackTransaction();
|
|
34
|
+
if (from != 0) debitAccount(from, asset, amount);
|
|
35
|
+
if (to != 0) creditAccount(to, asset, amount);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
state.complete();
|
package/queries/Assets.sol
CHANGED
|
@@ -9,16 +9,15 @@ using Cursors for Cur;
|
|
|
9
9
|
using Writers for Writer;
|
|
10
10
|
|
|
11
11
|
abstract contract AssetStatusHook {
|
|
12
|
-
/// @notice Resolve support status for one asset
|
|
12
|
+
/// @notice Resolve support status for one asset.
|
|
13
13
|
/// Concrete implementations define the support policy and optional context codes.
|
|
14
14
|
/// @param asset Requested asset identifier.
|
|
15
|
-
/// @param meta Requested asset metadata slot.
|
|
16
15
|
/// @return status Asset support status. Zero means unsupported; nonzero means supported.
|
|
17
|
-
function assetStatus(bytes32 asset
|
|
16
|
+
function assetStatus(bytes32 asset) internal view virtual returns (uint status);
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
/// @title AssetStatus
|
|
21
|
-
/// @notice Rootzero query that checks support status for one or more
|
|
20
|
+
/// @notice Rootzero query that checks support status for one or more assets.
|
|
22
21
|
/// The request is a run of `ASSET` blocks.
|
|
23
22
|
/// The response returns one `STATUS` form block per query entry, preserving request order.
|
|
24
23
|
abstract contract AssetStatus is QueryBase, AssetStatusHook {
|
|
@@ -29,16 +28,16 @@ abstract contract AssetStatus is QueryBase, AssetStatusHook {
|
|
|
29
28
|
emit Labeled(assetStatusId, bytes32(0), "assetStatus");
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
/// @notice Resolve asset support status for a run of requested
|
|
33
|
-
/// @param request Block-stream request consisting of `#asset { bytes32 asset
|
|
31
|
+
/// @notice Resolve asset support status for a run of requested assets.
|
|
32
|
+
/// @param request Block-stream request consisting of `#asset { bytes32 asset }` blocks.
|
|
34
33
|
/// @return Block-stream response containing one `#status { uint code }` per asset block.
|
|
35
34
|
function assetStatus(bytes calldata request) external view returns (bytes memory) {
|
|
36
35
|
(Cur memory query, uint groups, ) = Cursors.init(request, 1);
|
|
37
36
|
Writer memory response = Writers.allocStatuses(groups);
|
|
38
37
|
|
|
39
38
|
while (query.i < query.len) {
|
|
40
|
-
|
|
41
|
-
uint status = assetStatus(asset
|
|
39
|
+
bytes32 asset = query.unpackAsset();
|
|
40
|
+
uint status = assetStatus(asset);
|
|
42
41
|
response.appendStatus(status);
|
|
43
42
|
}
|
|
44
43
|
|
package/queries/Balances.sol
CHANGED
|
@@ -12,13 +12,12 @@ abstract contract GetBalancesHook {
|
|
|
12
12
|
/// Concrete implementations define how assets are resolved.
|
|
13
13
|
/// @param account Account identifier carried by the query payload.
|
|
14
14
|
/// @param asset Requested asset identifier.
|
|
15
|
-
/// @param meta Requested asset metadata slot.
|
|
16
15
|
/// @return amount Current balance in the asset's native units.
|
|
17
|
-
function getBalance(bytes32 account, bytes32 asset
|
|
16
|
+
function getBalance(bytes32 account, bytes32 asset) internal view virtual returns (uint amount);
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
/// @title GetBalances
|
|
21
|
-
/// @notice Rootzero query that resolves balances for one or more `(account, asset
|
|
20
|
+
/// @notice Rootzero query that resolves balances for one or more `(account, asset)` tuples.
|
|
22
21
|
/// The request is a run of `ACCOUNT_ASSET` form blocks.
|
|
23
22
|
/// The response returns one `ACCOUNT_AMOUNT` form block per requested position, preserving request order.
|
|
24
23
|
abstract contract GetBalances is QueryBase, GetBalancesHook {
|
|
@@ -29,17 +28,17 @@ abstract contract GetBalances is QueryBase, GetBalancesHook {
|
|
|
29
28
|
emit Labeled(getBalancesId, bytes32(0), "getBalances");
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
/// @notice Resolve balances for a run of requested `(account, asset
|
|
33
|
-
/// @param request Block-stream request consisting of `accountAsset(account, asset
|
|
34
|
-
/// @return Block-stream response containing one `accountAmount(account, asset,
|
|
31
|
+
/// @notice Resolve balances for a run of requested `(account, asset)` tuples.
|
|
32
|
+
/// @param request Block-stream request consisting of `accountAsset(account, asset)*`.
|
|
33
|
+
/// @return Block-stream response containing one `accountAmount(account, asset, amount)` block per request block.
|
|
35
34
|
function getBalances(bytes calldata request) external view returns (bytes memory) {
|
|
36
35
|
(Cur memory query, uint groups, ) = Cursors.init(request, 1);
|
|
37
36
|
Writer memory response = Writers.allocAccountAmounts(groups);
|
|
38
37
|
|
|
39
38
|
while (query.i < query.len) {
|
|
40
|
-
(bytes32 account, bytes32 asset
|
|
41
|
-
uint amount = getBalance(account, asset
|
|
42
|
-
response.appendAccountAmount(account, asset,
|
|
39
|
+
(bytes32 account, bytes32 asset) = query.unpackAccountAsset();
|
|
40
|
+
uint amount = getBalance(account, asset);
|
|
41
|
+
response.appendAccountAmount(account, asset, amount);
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
query.complete();
|
package/queries/Base.sol
CHANGED
|
@@ -4,16 +4,16 @@ pragma solidity ^0.8.33;
|
|
|
4
4
|
import { Runtime } from "../core/Runtime.sol";
|
|
5
5
|
import { LabeledEvent } from "../events/Labeled.sol";
|
|
6
6
|
import { QueryEvent } from "../events/Query.sol";
|
|
7
|
-
import {
|
|
7
|
+
import { Nodes } from "../utils/Nodes.sol";
|
|
8
8
|
|
|
9
9
|
/// @notice ABI-encode a query call from a target query ID and request block stream.
|
|
10
|
-
/// @dev Derives the function selector from `target` via `
|
|
10
|
+
/// @dev Derives the function selector from `target` via `Nodes.querySelector(target)`.
|
|
11
11
|
/// Reverts if `target` is not a valid query ID.
|
|
12
12
|
/// @param target Destination query node ID embedding the target selector.
|
|
13
13
|
/// @param request Input block stream for the query invocation.
|
|
14
14
|
/// @return ABI-encoded calldata for the query entry point.
|
|
15
15
|
function encodeQueryCall(uint target, bytes calldata request) pure returns (bytes memory) {
|
|
16
|
-
bytes4 selector =
|
|
16
|
+
bytes4 selector = Nodes.querySelector(target);
|
|
17
17
|
return abi.encodeWithSelector(selector, request);
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -29,6 +29,6 @@ abstract contract QueryBase is Runtime, QueryEvent, LabeledEvent {
|
|
|
29
29
|
/// @param selector Query entrypoint selector.
|
|
30
30
|
/// @return Query node ID.
|
|
31
31
|
function queryId(bytes4 selector) internal view returns (uint) {
|
|
32
|
-
return
|
|
32
|
+
return Nodes.toQuery(selector, address(this));
|
|
33
33
|
}
|
|
34
34
|
}
|
package/queries/Positions.sol
CHANGED
|
@@ -14,12 +14,10 @@ abstract contract GetPositionHook {
|
|
|
14
14
|
/// the query output schema.
|
|
15
15
|
/// @param account Requested account identifier.
|
|
16
16
|
/// @param asset Requested asset identifier.
|
|
17
|
-
/// @param meta Requested asset metadata slot.
|
|
18
17
|
/// @param response Destination writer for the response stream.
|
|
19
18
|
function appendPosition(
|
|
20
19
|
bytes32 account,
|
|
21
20
|
bytes32 asset,
|
|
22
|
-
bytes32 meta,
|
|
23
21
|
Writer memory response
|
|
24
22
|
) internal view virtual;
|
|
25
23
|
}
|
|
@@ -36,17 +34,17 @@ abstract contract GetPosition is QueryBase, GetPositionHook {
|
|
|
36
34
|
emit Labeled(getPositionId, bytes32(0), "getPosition");
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
/// @notice Resolve positions for a run of requested `(account, asset
|
|
37
|
+
/// @notice Resolve positions for a run of requested `(account, asset)` tuples.
|
|
40
38
|
/// @dev Allocates from a per-block capacity hint and grows when position outputs exceed it.
|
|
41
|
-
/// @param request Block-stream request consisting of `accountAsset(account, asset
|
|
39
|
+
/// @param request Block-stream request consisting of `accountAsset(account, asset)*`.
|
|
42
40
|
/// @return Block-stream response containing one output-schema block per position block.
|
|
43
41
|
function getPosition(bytes calldata request) external view returns (bytes memory) {
|
|
44
42
|
(Cur memory query, uint groups, ) = Cursors.init(request, 1);
|
|
45
43
|
Writer memory response = Writers.allocAny(groups);
|
|
46
44
|
|
|
47
45
|
while (query.i < query.len) {
|
|
48
|
-
(bytes32 account, bytes32 asset
|
|
49
|
-
appendPosition(account, asset,
|
|
46
|
+
(bytes32 account, bytes32 asset) = query.unpackAccountAsset();
|
|
47
|
+
appendPosition(account, asset, response);
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
query.complete();
|