@rootzero/contracts 0.2.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/LICENSE +648 -0
- package/README.md +135 -0
- package/contracts/Blocks.sol +9 -0
- package/contracts/Commands.sol +41 -0
- package/contracts/Core.sol +10 -0
- package/contracts/Events.sol +18 -0
- package/contracts/Utils.sol +12 -0
- package/contracts/blocks/Blocks.sol +818 -0
- package/contracts/blocks/Keys.sol +24 -0
- package/contracts/blocks/Mem.sol +129 -0
- package/contracts/blocks/Schema.sol +105 -0
- package/contracts/blocks/Writers.sol +209 -0
- package/contracts/combinators/AmountToBalance.sol +25 -0
- package/contracts/combinators/AmountToCustody.sol +36 -0
- package/contracts/combinators/CustodyToBalance.sol +25 -0
- package/contracts/combinators/EachRoute.sol +18 -0
- package/contracts/combinators/MapBalance.sol +25 -0
- package/contracts/combinators/MapCustody.sol +25 -0
- package/contracts/combinators/RouteToBalance.sol +27 -0
- package/contracts/commands/Base.sol +40 -0
- package/contracts/commands/Borrow.sol +89 -0
- package/contracts/commands/Burn.sol +33 -0
- package/contracts/commands/Create.sol +32 -0
- package/contracts/commands/Credit.sol +36 -0
- package/contracts/commands/Debit.sol +46 -0
- package/contracts/commands/Deposit.sol +45 -0
- package/contracts/commands/Liquidate.sol +101 -0
- package/contracts/commands/Liquidity.sol +179 -0
- package/contracts/commands/Mint.sol +42 -0
- package/contracts/commands/Pipe.sol +55 -0
- package/contracts/commands/Provision.sol +73 -0
- package/contracts/commands/Reclaim.sol +48 -0
- package/contracts/commands/Redeem.sol +101 -0
- package/contracts/commands/Remove.sol +32 -0
- package/contracts/commands/Repay.sol +101 -0
- package/contracts/commands/Settle.sol +32 -0
- package/contracts/commands/Stake.sol +121 -0
- package/contracts/commands/Supply.sol +33 -0
- package/contracts/commands/Swap.sol +88 -0
- package/contracts/commands/Transfer.sol +44 -0
- package/contracts/commands/Unstake.sol +49 -0
- package/contracts/commands/Withdraw.sol +37 -0
- package/contracts/commands/admin/Allocate.sol +32 -0
- package/contracts/commands/admin/AllowAssets.sol +34 -0
- package/contracts/commands/admin/Authorize.sol +30 -0
- package/contracts/commands/admin/DenyAssets.sol +34 -0
- package/contracts/commands/admin/Destroy.sol +27 -0
- package/contracts/commands/admin/Init.sol +26 -0
- package/contracts/commands/admin/Relocate.sol +30 -0
- package/contracts/commands/admin/Unauthorize.sol +30 -0
- package/contracts/core/Access.sol +50 -0
- package/contracts/core/Balances.sol +23 -0
- package/contracts/core/Host.sol +25 -0
- package/contracts/core/Operation.sol +32 -0
- package/contracts/core/Validator.sol +31 -0
- package/contracts/events/Access.sol +14 -0
- package/contracts/events/Asset.sol +14 -0
- package/contracts/events/Balance.sol +14 -0
- package/contracts/events/Collateral.sol +15 -0
- package/contracts/events/Command.sol +14 -0
- package/contracts/events/Debt.sol +15 -0
- package/contracts/events/Deposit.sol +14 -0
- package/contracts/events/Emitter.sol +7 -0
- package/contracts/events/Governed.sol +14 -0
- package/contracts/events/HostAnnounced.sol +14 -0
- package/contracts/events/Listing.sol +14 -0
- package/contracts/events/Peer.sol +14 -0
- package/contracts/events/Quote.sol +14 -0
- package/contracts/events/RootZero.sol +14 -0
- package/contracts/events/Withdraw.sol +14 -0
- package/contracts/interfaces/IHostDiscovery.sol +6 -0
- package/contracts/peer/AllowAssets.sol +30 -0
- package/contracts/peer/Base.sol +17 -0
- package/contracts/peer/DenyAssets.sol +30 -0
- package/contracts/peer/Pull.sol +30 -0
- package/contracts/peer/Push.sol +30 -0
- package/contracts/test/TestBlockHelper.sol +261 -0
- package/contracts/test/TestBorrowHost.sol +47 -0
- package/contracts/test/TestBurnHost.sol +28 -0
- package/contracts/test/TestCreateHost.sol +26 -0
- package/contracts/test/TestDiscovery.sol +6 -0
- package/contracts/test/TestECDSA.sol +16 -0
- package/contracts/test/TestHost.sol +199 -0
- package/contracts/test/TestLiquidityHost.sol +145 -0
- package/contracts/test/TestMintHost.sol +40 -0
- package/contracts/test/TestPeerHost.sol +34 -0
- package/contracts/test/TestReclaimHost.sol +48 -0
- package/contracts/test/TestRejectEther.sol +8 -0
- package/contracts/test/TestRemoveHost.sol +26 -0
- package/contracts/test/TestSwapHost.sol +44 -0
- package/contracts/test/TestUtils.sol +169 -0
- package/contracts/test/TestValidator.sol +10 -0
- package/contracts/utils/Accounts.sol +40 -0
- package/contracts/utils/Assets.sol +76 -0
- package/contracts/utils/Channels.sol +11 -0
- package/contracts/utils/ECDSA.sol +36 -0
- package/contracts/utils/Ids.sol +75 -0
- package/contracts/utils/Layout.sol +22 -0
- package/contracts/utils/Utils.sol +126 -0
- package/contracts/utils/Value.sol +20 -0
- package/package.json +33 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandContext, CommandBase, Channels } from "./Base.sol";
|
|
5
|
+
import { Keys, Schemas, Blocks, Block } from "../Blocks.sol";
|
|
6
|
+
using Blocks for Block;
|
|
7
|
+
|
|
8
|
+
string constant NAME = "transfer";
|
|
9
|
+
string constant REQUEST = string.concat(Schemas.Amount, ">", Schemas.Recipient);
|
|
10
|
+
|
|
11
|
+
abstract contract Transfer is CommandBase {
|
|
12
|
+
uint internal immutable transferId = commandId(NAME);
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
emit Command(host, NAME, REQUEST, transferId, Channels.Setup, Channels.Setup);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// @dev Override to transfer funds from `from` to `to`.
|
|
19
|
+
/// Called once per AMOUNT>RECIPIENT pair in the request.
|
|
20
|
+
function transfer(bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
21
|
+
|
|
22
|
+
/// @dev Override to customize request parsing or batching for transfers.
|
|
23
|
+
/// The default implementation iterates AMOUNT>RECIPIENT pairs and calls
|
|
24
|
+
/// `transfer(from, to, asset, meta, amount)` for each one.
|
|
25
|
+
function transfer(bytes32 from, bytes calldata request) internal virtual returns (bytes memory) {
|
|
26
|
+
uint q = 0;
|
|
27
|
+
while (q < request.length) {
|
|
28
|
+
Block memory ref = Blocks.from(request, q);
|
|
29
|
+
if (ref.key != Keys.Amount) break;
|
|
30
|
+
(bytes32 asset, bytes32 meta, uint amount) = ref.unpackAmount();
|
|
31
|
+
bytes32 to = ref.innerRecipientAt(ref.bound);
|
|
32
|
+
transfer(from, to, asset, meta, amount);
|
|
33
|
+
q = ref.cursor;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return done(0, q);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function transfer(
|
|
40
|
+
CommandContext calldata c
|
|
41
|
+
) external payable onlyCommand(transferId, c.target) returns (bytes memory) {
|
|
42
|
+
return transfer(c.account, c.request);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandContext, CommandBase, Channels } from "./Base.sol";
|
|
5
|
+
import { AssetAmount, Blocks, Block, Writers, Writer, Keys } from "../Blocks.sol";
|
|
6
|
+
|
|
7
|
+
string constant UBTB = "unstakeBalanceToBalances";
|
|
8
|
+
|
|
9
|
+
using Blocks for Block;
|
|
10
|
+
using Writers for Writer;
|
|
11
|
+
|
|
12
|
+
abstract contract UnstakeBalanceToBalances is CommandBase {
|
|
13
|
+
uint internal immutable unstakeBalanceToBalancesId = commandId(UBTB);
|
|
14
|
+
uint private immutable outScale;
|
|
15
|
+
|
|
16
|
+
constructor(string memory route, uint scaledRatio) {
|
|
17
|
+
outScale = scaledRatio;
|
|
18
|
+
emit Command(host, UBTB, route, unstakeBalanceToBalancesId, Channels.Balances, Channels.Balances);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// @dev Override to unstake or redeem a balance position.
|
|
22
|
+
/// Implementations may append one or more BALANCE blocks to `out`.
|
|
23
|
+
function unstakeBalanceToBalances(
|
|
24
|
+
bytes32 account,
|
|
25
|
+
AssetAmount memory balance,
|
|
26
|
+
Block memory rawRoute,
|
|
27
|
+
Writer memory out
|
|
28
|
+
) internal virtual;
|
|
29
|
+
|
|
30
|
+
function unstakeBalanceToBalances(
|
|
31
|
+
CommandContext calldata c
|
|
32
|
+
) external payable onlyCommand(unstakeBalanceToBalancesId, c.target) returns (bytes memory) {
|
|
33
|
+
uint i = 0;
|
|
34
|
+
uint q = 0;
|
|
35
|
+
(Writer memory writer, uint end) = Writers.allocScaledBalancesFrom(c.state, i, Keys.Balance, outScale);
|
|
36
|
+
|
|
37
|
+
while (i < end) {
|
|
38
|
+
Block memory route;
|
|
39
|
+
route = Blocks.routeFrom(c.request, q);
|
|
40
|
+
q = route.cursor;
|
|
41
|
+
Block memory ref = Blocks.from(c.state, i);
|
|
42
|
+
AssetAmount memory balance = ref.toBalanceValue();
|
|
43
|
+
unstakeBalanceToBalances(c.account, balance, route, writer);
|
|
44
|
+
i = ref.cursor;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return writer.finish();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandContext, CommandBase, Channels } from "./Base.sol";
|
|
5
|
+
import { Keys, Schemas, Blocks, Block } from "../Blocks.sol";
|
|
6
|
+
using Blocks for Block;
|
|
7
|
+
|
|
8
|
+
string constant NAME = "withdraw";
|
|
9
|
+
|
|
10
|
+
// @dev Use `withdraw` for externally delivered assets; use `creditBalanceToAccount` for internal balance credits.
|
|
11
|
+
abstract contract Withdraw is CommandBase {
|
|
12
|
+
uint internal immutable withdrawId = commandId(NAME);
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
emit Command(host, NAME, Schemas.Recipient, withdrawId, Channels.Balances, Channels.Setup);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// @dev Override to send funds to `account`.
|
|
19
|
+
/// Called once per BALANCE block in state.
|
|
20
|
+
function withdraw(bytes32 account, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
21
|
+
|
|
22
|
+
function withdraw(
|
|
23
|
+
CommandContext calldata c
|
|
24
|
+
) external payable onlyCommand(withdrawId, c.target) returns (bytes memory) {
|
|
25
|
+
bytes32 to = Blocks.resolveRecipient(c.request, 0, c.request.length, c.account);
|
|
26
|
+
uint i = 0;
|
|
27
|
+
while (i < c.state.length) {
|
|
28
|
+
Block memory ref = Blocks.from(c.state, i);
|
|
29
|
+
if (ref.key != Keys.Balance) break;
|
|
30
|
+
(bytes32 asset, bytes32 meta, uint amount) = ref.unpackBalance();
|
|
31
|
+
withdraw(to, asset, meta, amount);
|
|
32
|
+
i = ref.cursor;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return done(0, i);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandBase, CommandContext, Channels } from "../Base.sol";
|
|
5
|
+
import { HostAmount, Keys, Schemas, Blocks, Block } from "../../Blocks.sol";
|
|
6
|
+
using Blocks for Block;
|
|
7
|
+
|
|
8
|
+
string constant NAME = "allocate";
|
|
9
|
+
|
|
10
|
+
abstract contract Allocate is CommandBase {
|
|
11
|
+
uint internal immutable allocateId = commandId(NAME);
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
emit Command(host, NAME, Schemas.Allocation, allocateId, Channels.Setup, Channels.Setup);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/// @dev Override to apply a single allocation entry.
|
|
18
|
+
/// Called once per ALLOCATION block in the request.
|
|
19
|
+
function allocate(uint host, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
20
|
+
|
|
21
|
+
function allocate(CommandContext calldata c) external payable onlyAdmin(c.account) onlyCommand(allocateId, c.target) returns (bytes memory) {
|
|
22
|
+
uint i = 0;
|
|
23
|
+
while (i < c.request.length) {
|
|
24
|
+
Block memory ref = Blocks.from(c.request, i);
|
|
25
|
+
if (ref.key != Keys.Allocation) break;
|
|
26
|
+
HostAmount memory v = ref.toAllocationValue();
|
|
27
|
+
allocate(v.host, v.asset, v.meta, v.amount);
|
|
28
|
+
i = ref.cursor;
|
|
29
|
+
}
|
|
30
|
+
return done(0, i);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandBase, CommandContext, Channels } from "../Base.sol";
|
|
5
|
+
import { Keys, Schemas, Blocks, Block } from "../../Blocks.sol";
|
|
6
|
+
using Blocks for Block;
|
|
7
|
+
|
|
8
|
+
string constant NAME = "allowAssets";
|
|
9
|
+
|
|
10
|
+
abstract contract AllowAssets is CommandBase {
|
|
11
|
+
uint internal immutable allowAssetsId = commandId(NAME);
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
emit Command(host, NAME, Schemas.Asset, allowAssetsId, Channels.Setup, Channels.Setup);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/// @dev Override to allow a single asset/meta pair.
|
|
18
|
+
/// Called once per ASSET block in the request.
|
|
19
|
+
function allowAsset(bytes32 asset, bytes32 meta) internal virtual returns (bool);
|
|
20
|
+
|
|
21
|
+
function allowAssets(
|
|
22
|
+
CommandContext calldata c
|
|
23
|
+
) external payable onlyAdmin(c.account) onlyCommand(allowAssetsId, c.target) returns (bytes memory) {
|
|
24
|
+
uint i = 0;
|
|
25
|
+
while (i < c.request.length) {
|
|
26
|
+
Block memory ref = Blocks.from(c.request, i);
|
|
27
|
+
if (ref.key != Keys.Asset) break;
|
|
28
|
+
(bytes32 asset, bytes32 meta) = ref.unpackAsset();
|
|
29
|
+
allowAsset(asset, meta);
|
|
30
|
+
i = ref.cursor;
|
|
31
|
+
}
|
|
32
|
+
return done(0, i);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandBase, CommandContext, Channels } from "../Base.sol";
|
|
5
|
+
import { Keys, Schemas, Blocks, Block } from "../../Blocks.sol";
|
|
6
|
+
using Blocks for Block;
|
|
7
|
+
|
|
8
|
+
string constant NAME = "authorize";
|
|
9
|
+
|
|
10
|
+
abstract contract Authorize is CommandBase {
|
|
11
|
+
uint internal immutable authorizeId = commandId(NAME);
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
emit Command(host, NAME, Schemas.Node, authorizeId, Channels.Setup, Channels.Setup);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function authorize(
|
|
18
|
+
CommandContext calldata c
|
|
19
|
+
) external payable onlyAdmin(c.account) onlyCommand(authorizeId, c.target) returns (bytes memory) {
|
|
20
|
+
uint i = 0;
|
|
21
|
+
while (i < c.request.length) {
|
|
22
|
+
Block memory ref = Blocks.from(c.request, i);
|
|
23
|
+
if (ref.key != Keys.Node) break;
|
|
24
|
+
uint node = ref.unpackNode();
|
|
25
|
+
access(node, true);
|
|
26
|
+
i = ref.cursor;
|
|
27
|
+
}
|
|
28
|
+
return done(0, i);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandBase, CommandContext, Channels } from "../Base.sol";
|
|
5
|
+
import { Keys, Schemas, Blocks, Block } from "../../Blocks.sol";
|
|
6
|
+
using Blocks for Block;
|
|
7
|
+
|
|
8
|
+
string constant NAME = "denyAssets";
|
|
9
|
+
|
|
10
|
+
abstract contract DenyAssets is CommandBase {
|
|
11
|
+
uint internal immutable denyAssetsId = commandId(NAME);
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
emit Command(host, NAME, Schemas.Asset, denyAssetsId, Channels.Setup, Channels.Setup);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/// @dev Override to deny a single asset/meta pair.
|
|
18
|
+
/// Called once per ASSET block in the request.
|
|
19
|
+
function denyAsset(bytes32 asset, bytes32 meta) internal virtual returns (bool);
|
|
20
|
+
|
|
21
|
+
function denyAssets(
|
|
22
|
+
CommandContext calldata c
|
|
23
|
+
) external payable onlyAdmin(c.account) onlyCommand(denyAssetsId, c.target) returns (bytes memory) {
|
|
24
|
+
uint i = 0;
|
|
25
|
+
while (i < c.request.length) {
|
|
26
|
+
Block memory ref = Blocks.from(c.request, i);
|
|
27
|
+
if (ref.key != Keys.Asset) break;
|
|
28
|
+
(bytes32 asset, bytes32 meta) = ref.unpackAsset();
|
|
29
|
+
denyAsset(asset, meta);
|
|
30
|
+
i = ref.cursor;
|
|
31
|
+
}
|
|
32
|
+
return done(0, i);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandBase, CommandContext, Channels } from "../Base.sol";
|
|
5
|
+
import { Blocks, Block } from "../../Blocks.sol";
|
|
6
|
+
|
|
7
|
+
string constant NAME = "destroy";
|
|
8
|
+
|
|
9
|
+
abstract contract Destroy is CommandBase {
|
|
10
|
+
uint internal immutable destroyId = commandId(NAME);
|
|
11
|
+
|
|
12
|
+
constructor(string memory route) {
|
|
13
|
+
emit Command(host, NAME, route, destroyId, Channels.Setup, Channels.Setup);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// @dev Override to run host teardown or destruction logic using the
|
|
17
|
+
/// decoded route.
|
|
18
|
+
function destroy(Block memory rawRoute) internal virtual;
|
|
19
|
+
|
|
20
|
+
function destroy(
|
|
21
|
+
CommandContext calldata c
|
|
22
|
+
) external payable onlyAdmin(c.account) onlyCommand(destroyId, c.target) returns (bytes memory) {
|
|
23
|
+
Block memory route = Blocks.routeFrom(c.request, 0);
|
|
24
|
+
destroy(route);
|
|
25
|
+
return done(0, route.cursor);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandBase, CommandContext, Channels } from "../Base.sol";
|
|
5
|
+
import { Blocks, Block } from "../../Blocks.sol";
|
|
6
|
+
|
|
7
|
+
string constant NAME = "init";
|
|
8
|
+
|
|
9
|
+
abstract contract Init is CommandBase {
|
|
10
|
+
uint internal immutable initId = commandId(NAME);
|
|
11
|
+
|
|
12
|
+
constructor(string memory route) {
|
|
13
|
+
emit Command(host, NAME, route, initId, Channels.Setup, Channels.Setup);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// @dev Override to run host initialization logic using the decoded route.
|
|
17
|
+
function init(Block memory rawRoute) internal virtual;
|
|
18
|
+
|
|
19
|
+
function init(
|
|
20
|
+
CommandContext calldata c
|
|
21
|
+
) external payable onlyAdmin(c.account) onlyCommand(initId, c.target) returns (bytes memory) {
|
|
22
|
+
Block memory route = Blocks.routeFrom(c.request, 0);
|
|
23
|
+
init(route);
|
|
24
|
+
return done(0, route.cursor);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandBase, CommandContext, Channels } from "../Base.sol";
|
|
5
|
+
import { Keys, Schemas, Blocks, Block } from "../../Blocks.sol";
|
|
6
|
+
using Blocks for Block;
|
|
7
|
+
|
|
8
|
+
string constant NAME = "relocate";
|
|
9
|
+
|
|
10
|
+
abstract contract Relocate is CommandBase {
|
|
11
|
+
uint internal immutable relocateId = commandId(NAME);
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
emit Command(host, NAME, Schemas.Funding, relocateId, Channels.Setup, Channels.Setup);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function relocate(
|
|
18
|
+
CommandContext calldata c
|
|
19
|
+
) external payable onlyAdmin(c.account) onlyCommand(relocateId, c.target) returns (bytes memory) {
|
|
20
|
+
uint i = 0;
|
|
21
|
+
while (i < c.request.length) {
|
|
22
|
+
Block memory ref = Blocks.from(c.request, i);
|
|
23
|
+
if (ref.key != Keys.Funding) break;
|
|
24
|
+
(uint host, uint amount) = ref.unpackFunding();
|
|
25
|
+
callTo(host, amount, "");
|
|
26
|
+
i = ref.cursor;
|
|
27
|
+
}
|
|
28
|
+
return done(0, i);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { CommandBase, CommandContext, Channels } from "../Base.sol";
|
|
5
|
+
import { Keys, Schemas, Blocks, Block } from "../../Blocks.sol";
|
|
6
|
+
using Blocks for Block;
|
|
7
|
+
|
|
8
|
+
string constant NAME = "unauthorize";
|
|
9
|
+
|
|
10
|
+
abstract contract Unauthorize is CommandBase {
|
|
11
|
+
uint internal immutable unauthorizeId = commandId(NAME);
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
emit Command(host, NAME, Schemas.Node, unauthorizeId, Channels.Setup, Channels.Setup);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function unauthorize(
|
|
18
|
+
CommandContext calldata c
|
|
19
|
+
) external payable onlyAdmin(c.account) onlyCommand(unauthorizeId, c.target) returns (bytes memory) {
|
|
20
|
+
uint i = 0;
|
|
21
|
+
while (i < c.request.length) {
|
|
22
|
+
Block memory ref = Blocks.from(c.request, i);
|
|
23
|
+
if (ref.key != Keys.Node) break;
|
|
24
|
+
uint node = ref.unpackNode();
|
|
25
|
+
access(node, false);
|
|
26
|
+
i = ref.cursor;
|
|
27
|
+
}
|
|
28
|
+
return done(0, i);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { AccessEvent } from "../events/Access.sol";
|
|
5
|
+
import { Accounts } from "../utils/Accounts.sol";
|
|
6
|
+
import { Ids } from "../utils/Ids.sol";
|
|
7
|
+
import { addrOr } from "../utils/Utils.sol";
|
|
8
|
+
|
|
9
|
+
abstract contract AccessControl is AccessEvent {
|
|
10
|
+
address internal immutable commander;
|
|
11
|
+
bytes32 internal immutable adminAccount;
|
|
12
|
+
uint public immutable host;
|
|
13
|
+
|
|
14
|
+
mapping(uint => bool) internal authorized;
|
|
15
|
+
|
|
16
|
+
error UnauthorizedNode(uint node);
|
|
17
|
+
error UnauthorizedCaller(address addr);
|
|
18
|
+
|
|
19
|
+
constructor(address cmdr) {
|
|
20
|
+
commander = addrOr(cmdr, address(this));
|
|
21
|
+
adminAccount = Accounts.toAdmin(commander);
|
|
22
|
+
host = Ids.toHost(address(this));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// @dev inbound auth is host-based.
|
|
26
|
+
function access(uint node, bool allow) internal {
|
|
27
|
+
authorized[node] = allow;
|
|
28
|
+
emit Access(host, node, allow);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isTrusted(address caller) internal view returns (bool) {
|
|
32
|
+
return caller == commander || caller == address(this) || authorized[Ids.toHost(caller)];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function enforceCaller(address caller) internal view returns (address) {
|
|
36
|
+
if (caller == address(0) || !isTrusted(caller)) {
|
|
37
|
+
revert UnauthorizedCaller(caller);
|
|
38
|
+
}
|
|
39
|
+
return caller;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// @dev Outbound trust check: accepts any authorized node id (host or COMMAND).
|
|
43
|
+
// Inbound caller auth is host-only via `enforceCaller(msg.sender)`.
|
|
44
|
+
function ensureTrusted(uint node) internal view returns (uint) {
|
|
45
|
+
if (node == 0 || !authorized[node]) {
|
|
46
|
+
revert UnauthorizedNode(node);
|
|
47
|
+
}
|
|
48
|
+
return node;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {BalanceEvent} from "../events/Balance.sol";
|
|
5
|
+
|
|
6
|
+
error InsufficientFunds();
|
|
7
|
+
|
|
8
|
+
abstract contract Balances is BalanceEvent {
|
|
9
|
+
mapping(bytes32 account => mapping(bytes32 ref => uint amount)) internal balances;
|
|
10
|
+
|
|
11
|
+
function debitFrom(bytes32 account, bytes32 ref, uint amount) internal returns (uint balance) {
|
|
12
|
+
balance = balances[account][ref];
|
|
13
|
+
if (balance < amount) revert InsufficientFunds();
|
|
14
|
+
unchecked {
|
|
15
|
+
balance -= amount;
|
|
16
|
+
}
|
|
17
|
+
balances[account][ref] = balance;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function creditTo(bytes32 account, bytes32 ref, uint amount) internal returns (uint balance) {
|
|
21
|
+
balance = balances[account][ref] += amount;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { AccessControl } from "./Access.sol";
|
|
5
|
+
import { Authorize } from "../commands/admin/Authorize.sol";
|
|
6
|
+
import { Unauthorize } from "../commands/admin/Unauthorize.sol";
|
|
7
|
+
import { Relocate } from "../commands/admin/Relocate.sol";
|
|
8
|
+
import { HostAnnouncedEvent } from "../events/HostAnnounced.sol";
|
|
9
|
+
import { IHostDiscovery } from "../interfaces/IHostDiscovery.sol";
|
|
10
|
+
import { Ids } from "../utils/Ids.sol";
|
|
11
|
+
|
|
12
|
+
abstract contract HostDiscovery is HostAnnouncedEvent, IHostDiscovery {
|
|
13
|
+
function announceHost(uint id, uint blocknum, uint16 version, string calldata namespace) external {
|
|
14
|
+
emit HostAnnounced(Ids.host(id, msg.sender), blocknum, version, namespace);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
abstract contract Host is Authorize, Unauthorize, Relocate {
|
|
19
|
+
constructor(address cmdr, uint16 version, string memory namespace) AccessControl(cmdr) {
|
|
20
|
+
if (cmdr == address(0) || cmdr == address(this) || cmdr.code.length == 0) return;
|
|
21
|
+
IHostDiscovery(cmdr).announceHost(host, block.number, version, namespace);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
receive() external payable {}
|
|
25
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { AccessControl } from "./Access.sol";
|
|
5
|
+
import { Assets } from "../utils/Assets.sol";
|
|
6
|
+
import { Ids } from "../utils/Ids.sol";
|
|
7
|
+
|
|
8
|
+
error NoOperation();
|
|
9
|
+
error FailedCall(address addr, uint node, bytes4 selector, bytes err);
|
|
10
|
+
|
|
11
|
+
abstract contract OperationBase is AccessControl {
|
|
12
|
+
bytes32 public immutable valueAsset = Assets.toValue();
|
|
13
|
+
|
|
14
|
+
function done(uint start, uint end) internal pure returns (bytes memory) {
|
|
15
|
+
if (end <= start) revert NoOperation();
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function done(bytes memory state, uint start, uint end) internal pure returns (bytes memory) {
|
|
20
|
+
if (end <= start) revert NoOperation();
|
|
21
|
+
return state;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function callTo(uint node, uint value, bytes memory data) internal returns (bytes memory out) {
|
|
25
|
+
bool success;
|
|
26
|
+
address addr = Ids.nodeAddr(ensureTrusted(node));
|
|
27
|
+
(success, out) = payable(addr).call{value: value}(data);
|
|
28
|
+
if (!success) {
|
|
29
|
+
revert FailedCall(addr, node, bytes4(data), out);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { ECDSA } from "../utils/ECDSA.sol";
|
|
5
|
+
|
|
6
|
+
abstract contract Validator {
|
|
7
|
+
using ECDSA for bytes32;
|
|
8
|
+
|
|
9
|
+
error InvalidProof();
|
|
10
|
+
error InvalidSigner();
|
|
11
|
+
error InvalidNonce();
|
|
12
|
+
|
|
13
|
+
mapping(address account => mapping(uint192 key => uint64)) internal nonces;
|
|
14
|
+
|
|
15
|
+
function recover(bytes32 hash, bytes calldata sig) private pure returns (address) {
|
|
16
|
+
return hash.toEthSignedMessageHash().tryRecoverCalldata(sig);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// @dev proof is (bytes20 signer, bytes65 sig)
|
|
20
|
+
function verify(bytes32 hash, uint192 nonce, bytes calldata proof) internal returns (address) {
|
|
21
|
+
if (proof.length != 85) revert InvalidProof();
|
|
22
|
+
|
|
23
|
+
address account = address(bytes20(proof[0:20]));
|
|
24
|
+
address signer = recover(hash, proof[20:]);
|
|
25
|
+
|
|
26
|
+
if (account == address(0) || signer != account) revert InvalidSigner();
|
|
27
|
+
if (nonces[account][nonce]++ != 0) revert InvalidNonce();
|
|
28
|
+
|
|
29
|
+
return account;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { EventEmitter } from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
string constant ABI = "event Access(uint indexed host, uint node, bool trusted)";
|
|
7
|
+
|
|
8
|
+
abstract contract AccessEvent is EventEmitter {
|
|
9
|
+
event Access(uint indexed host, uint node, bool trusted);
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
emit EventAbi(ABI);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { EventEmitter } from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
string constant ABI = "event Asset(uint indexed host, bytes32 name, uint32 prefix, string format)";
|
|
7
|
+
|
|
8
|
+
abstract contract AssetEvent is EventEmitter {
|
|
9
|
+
event Asset(uint indexed host, bytes32 name, uint32 prefix, string format);
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
emit EventAbi(ABI);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { EventEmitter } from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
string constant ABI = "event Balance(bytes32 indexed account, bytes32 asset, bytes32 meta, uint balance, int change, uint access)";
|
|
7
|
+
|
|
8
|
+
abstract contract BalanceEvent is EventEmitter {
|
|
9
|
+
event Balance(bytes32 indexed account, bytes32 asset, bytes32 meta, uint balance, int change, uint access);
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
emit EventAbi(ABI);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { EventEmitter } from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
string constant ABI = "event Collateral(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint access)";
|
|
7
|
+
|
|
8
|
+
// Query should be provided for the access command to get the exact colleteral.
|
|
9
|
+
abstract contract CollateralEvent is EventEmitter {
|
|
10
|
+
event Collateral(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint access);
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
emit EventAbi(ABI);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { EventEmitter } from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
string constant ABI = "event Command(uint indexed host, string name, string schema, uint cid, uint8 stateIn, uint8 stateOut)";
|
|
7
|
+
|
|
8
|
+
abstract contract CommandEvent is EventEmitter {
|
|
9
|
+
event Command(uint indexed host, string name, string schema, uint cid, uint8 stateIn, uint8 stateOut);
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
emit EventAbi(ABI);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { EventEmitter } from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
string constant ABI = "event Debt(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint mode, uint access)";
|
|
7
|
+
|
|
8
|
+
// Query should be provided for the access command to get the exact debt.
|
|
9
|
+
abstract contract DebtEvent is EventEmitter {
|
|
10
|
+
event Debt(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint mode, uint access);
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
emit EventAbi(ABI);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { EventEmitter } from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
string constant ABI = "event Deposit(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint cid)";
|
|
7
|
+
|
|
8
|
+
abstract contract DepositEvent is EventEmitter {
|
|
9
|
+
event Deposit(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint cid);
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
emit EventAbi(ABI);
|
|
13
|
+
}
|
|
14
|
+
}
|