@crossecute/protocol 0.0.0 → 0.1.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/README.md +25 -1
- package/abi/Blake2b256.json +1 -0
- package/abi/Blake2bScheme.json +1 -0
- package/abi/ChainRegistry.json +1 -0
- package/abi/Commitment.json +1 -0
- package/abi/Conduits.json +1 -0
- package/abi/DivergentConduits.json +1 -0
- package/abi/DivergentTransceiver.json +1 -0
- package/abi/DivergentTransceiverExtension.json +1 -0
- package/abi/Envelope.json +1 -0
- package/abi/Erc7930.json +1 -0
- package/abi/Executor.json +1 -0
- package/abi/IBootstrapAllowlist.json +1 -0
- package/abi/ICancel.json +1 -0
- package/abi/IChainRegistryRefs.json +1 -0
- package/abi/ICommitFinalize.json +1 -0
- package/abi/ICommitmentScheme.json +1 -0
- package/abi/IConduitReceiverReport.json +1 -0
- package/abi/IConduitTransceiver.json +1 -0
- package/abi/IERC7786GatewaySource.json +1 -0
- package/abi/IERC7786Recipient.json +1 -0
- package/abi/IExecute.json +1 -0
- package/abi/ILzOftConduitFactory.json +1 -0
- package/abi/IProviderIdTable.json +1 -0
- package/abi/IProxy.json +1 -0
- package/abi/IReceiverInit.json +1 -0
- package/abi/IRefValidator.json +1 -0
- package/abi/IReportFloat.json +1 -0
- package/abi/ITransmitterInit.json +1 -0
- package/abi/IVmDeriver.json +1 -0
- package/abi/KeccakScheme.json +1 -0
- package/abi/Move.json +1 -0
- package/abi/MoveValidator.json +1 -0
- package/abi/OpStackTransmitterBase.json +1 -0
- package/abi/OutboundBase.json +1 -0
- package/abi/OwnableTransmitter.json +1 -0
- package/abi/ProviderAddress.json +1 -0
- package/abi/ProviderAttribute.json +1 -0
- package/abi/ProviderChainId.json +1 -0
- package/abi/ProviderReceiver.json +1 -0
- package/abi/ProviderTransceiver.json +1 -0
- package/abi/Proxy.json +1 -0
- package/abi/ProxyDeployer.json +1 -0
- package/abi/ProxyInitCode.json +1 -0
- package/abi/ReceiverBase.json +1 -0
- package/abi/Roles.json +1 -0
- package/abi/RolesEnumerable.json +1 -0
- package/abi/SchemeFold.json +1 -0
- package/abi/Sha256Scheme.json +1 -0
- package/abi/StarknetDerive.json +1 -0
- package/abi/StarknetValidator.json +1 -0
- package/abi/SuiDerive.json +1 -0
- package/abi/TransceiverBase.json +1 -0
- package/abi/TransceiverCore.json +1 -0
- package/abi/TransceiverExtension.json +1 -0
- package/abi/TransmitterBase.json +1 -0
- package/abi/Treasury.json +1 -0
- package/abi/TronConduits.json +1 -0
- package/abi/TronTransceiver.json +1 -0
- package/abi/TronTransceiverExtension.json +1 -0
- package/abi/VmDeriver.json +1 -0
- package/abi/ZkSyncConduits.json +1 -0
- package/abi/ZkSyncTransceiver.json +1 -0
- package/abi/ZkSyncTransceiverExtension.json +1 -0
- package/abi/index.d.ts +63 -0
- package/abi/index.js +63 -0
- package/contracts/addressing/ChainKey.sol +45 -0
- package/contracts/addressing/ChainType.sol +50 -0
- package/contracts/addressing/Erc7930.sol +209 -0
- package/contracts/addressing/Move.sol +212 -0
- package/contracts/conduit/Conduits.sol +43 -0
- package/contracts/conduit/Proxy.sol +144 -0
- package/contracts/conduit/ProxyDeployer.sol +42 -0
- package/contracts/conduit/ProxyInitCode.sol +47 -0
- package/contracts/derivation/AddressDerive.sol +326 -0
- package/contracts/derivation/BitcoinDerive.sol +33 -0
- package/contracts/derivation/Blake2b256.sol +122 -0
- package/contracts/derivation/IVmDeriver.sol +35 -0
- package/contracts/derivation/StarknetDerive.sol +93 -0
- package/contracts/derivation/SuiDerive.sol +102 -0
- package/contracts/derivation/VmDeriver.sol +291 -0
- package/contracts/messaging/Call.sol +43 -0
- package/contracts/messaging/Commitment.sol +131 -0
- package/contracts/messaging/DeliveryGas.sol +18 -0
- package/contracts/messaging/Envelope.sol +123 -0
- package/contracts/messaging/Executor.sol +52 -0
- package/contracts/messaging/IErc7786.sol +68 -0
- package/contracts/messaging/Payload.sol +90 -0
- package/contracts/messaging/Roles.sol +113 -0
- package/contracts/messaging/inbound/ReceiverBase.sol +359 -0
- package/contracts/messaging/outbound/OutboundBase.sol +221 -0
- package/contracts/messaging/outbound/OwnableTransmitter.sol +23 -0
- package/contracts/messaging/outbound/TransmitterBase.sol +604 -0
- package/contracts/messaging/transceiver/DivergentConduits.sol +92 -0
- package/contracts/messaging/transceiver/DivergentTransceiver.sol +97 -0
- package/contracts/messaging/transceiver/IBootstrapAllowlist.sol +8 -0
- package/contracts/messaging/transceiver/TransceiverBase.sol +541 -0
- package/contracts/messaging/transceiver/TransceiverCore.sol +307 -0
- package/contracts/messaging/transceiver/TransceiverExtension.sol +278 -0
- package/contracts/protocols/ProviderAddress.sol +32 -0
- package/contracts/protocols/ProviderAttribute.sol +65 -0
- package/contracts/protocols/ProviderChainId.sol +115 -0
- package/contracts/protocols/ProviderReceiver.sol +24 -0
- package/contracts/protocols/ProviderTransceiver.sol +48 -0
- package/contracts/protocols/layerzero/ILzOftConduitFactory.sol +10 -0
- package/contracts/protocols/op-stack/OpStackTransmitterBase.sol +11 -0
- package/contracts/registry/ChainRegistry.sol +667 -0
- package/contracts/registry/IChainRegistryRefs.sol +81 -0
- package/contracts/registry/ICommitmentScheme.sol +46 -0
- package/contracts/registry/IRefValidator.sol +13 -0
- package/contracts/registry/Provenance.sol +25 -0
- package/contracts/schemes/Blake2bScheme.sol +18 -0
- package/contracts/schemes/KeccakScheme.sol +19 -0
- package/contracts/schemes/Sha256Scheme.sol +15 -0
- package/contracts/treasury/Treasury.sol +76 -0
- package/contracts/validators/MoveValidator.sol +24 -0
- package/contracts/validators/StarknetValidator.sol +20 -0
- package/package.json +34 -3
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {Provenance} from "./Provenance.sol";
|
|
5
|
+
|
|
6
|
+
/// @notice The CREATE2 inputs a message provider's contracts share on every chain.
|
|
7
|
+
///
|
|
8
|
+
/// @dev The caller that deploys a transceiver is per (provider, chain), held by the registry: one
|
|
9
|
+
/// salt and caller put a transceiver at one address, and a rotated deployer moves only the
|
|
10
|
+
/// chains added after it. The salt can be mined for leading zero bytes, which are cheaper in
|
|
11
|
+
/// the calldata that names the address.
|
|
12
|
+
struct ProviderDeployment {
|
|
13
|
+
/// The mined salt every deployer passes to `ProxyDeployer.deploy`.
|
|
14
|
+
bytes32 salt;
|
|
15
|
+
/// keccak256 of `Proxy`'s initcode as solc builds it: transceivers and conduits are
|
|
16
|
+
/// both `Proxy`. Recorded rather than computed, since a zkSync or Tron registry's
|
|
17
|
+
/// own compiler builds a different one.
|
|
18
|
+
bytes32 proxyInitCodeHash;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// @notice Whether sends may reach a provider's transceiver on a chain.
|
|
22
|
+
/// @dev `Pending` is recorded and predicted but not sent to; `Live` is set by the registry's owner
|
|
23
|
+
/// once the deployment there was checked independently of the deployer.
|
|
24
|
+
enum Status {
|
|
25
|
+
None,
|
|
26
|
+
Pending,
|
|
27
|
+
Live
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// @notice The slice of `ChainRegistry` a transceiver needs: where remote things live, and how
|
|
31
|
+
/// much each claim about them is worth.
|
|
32
|
+
///
|
|
33
|
+
/// @dev Routes live on the transceiver. What it reads here is provenance, suspension, derived
|
|
34
|
+
/// counterpart addresses, location validation, and which chains must report their
|
|
35
|
+
/// receivers.
|
|
36
|
+
interface IChainRegistryRefs {
|
|
37
|
+
/// @notice What an address claim about `chainKey` is worth. Chain-scoped, so every
|
|
38
|
+
/// provider's transceiver reads the same answer.
|
|
39
|
+
function provenanceFor(bytes32 chainKey) external view returns (Provenance);
|
|
40
|
+
|
|
41
|
+
/// @notice Whether every transceiver on this chain refuses `chainKey`.
|
|
42
|
+
function isSuspended(bytes32 chainKey) external view returns (bool);
|
|
43
|
+
|
|
44
|
+
/// @notice The transceiver address this registry recomputes for `chainKey`, from the
|
|
45
|
+
/// deriver and inputs recorded for that chain. A transceiver stores the result.
|
|
46
|
+
function expectedTransceiver(bytes32 chainKey) external view returns (bytes memory);
|
|
47
|
+
|
|
48
|
+
/// @notice The CREATE2 inputs `messageProvider`'s contracts share; a zero salt means none is
|
|
49
|
+
/// recorded.
|
|
50
|
+
function providerDeployment(bytes32 messageProvider) external view returns (ProviderDeployment memory);
|
|
51
|
+
|
|
52
|
+
/// @notice Where a provider's transceiver lands on `chainKey`, recomputed from the recorded
|
|
53
|
+
/// factory, that chain's deployer, salt, and initcode hash. Reverts for a chain not
|
|
54
|
+
/// graded `Predetermined`, and for one the provider was never added on.
|
|
55
|
+
function predictTransceiver(bytes32 chainKey, bytes32 messageProvider) external view returns (address);
|
|
56
|
+
|
|
57
|
+
/// @notice Whether sends to `messageProvider`'s transceiver on `chainKey` are allowed.
|
|
58
|
+
function isLive(bytes32 chainKey, bytes32 messageProvider) external view returns (bool);
|
|
59
|
+
|
|
60
|
+
/// @notice Who deployed, or will deploy, `messageProvider`'s transceiver on `chainKey`; zero
|
|
61
|
+
/// where it was never added.
|
|
62
|
+
function deployedBy(bytes32 chainKey, bytes32 messageProvider) external view returns (address);
|
|
63
|
+
|
|
64
|
+
/// @notice The deployer a provider added on a chain from now on is recorded under.
|
|
65
|
+
function currentDeployer() external view returns (address);
|
|
66
|
+
|
|
67
|
+
/// @notice The canonical ERC-7930 chain identifier `chainKey` hashes from.
|
|
68
|
+
function chainIdentifier(bytes32 chainKey) external view returns (bytes memory);
|
|
69
|
+
|
|
70
|
+
/// @notice Reverts unless `interop` is a well-formed address on `chainKey`.
|
|
71
|
+
function validateLocation(bytes32 chainKey, bytes calldata interop) external view;
|
|
72
|
+
|
|
73
|
+
/// @notice The derivation inputs recorded for `chainKey`. Hash this to build the
|
|
74
|
+
/// `paramsCommitment` a `resolveCounterpart` transaction must carry.
|
|
75
|
+
function deriveParams(bytes32 chainKey) external view returns (bytes memory);
|
|
76
|
+
|
|
77
|
+
/// @notice Whether conduits on `chainKey` must report their own address home, which is
|
|
78
|
+
/// the only thing this directory says about receivers. Where one actually landed
|
|
79
|
+
/// is held by the transmitter that sends to it.
|
|
80
|
+
function requiresReceiverCallback(bytes32 chainKey) external view returns (bool);
|
|
81
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
/// @title ICommitmentScheme
|
|
5
|
+
/// @notice A chain's commitment hash primitive, for previewing a commitment on this chain.
|
|
6
|
+
///
|
|
7
|
+
/// @dev The plugin supplies the primitive and `SchemeFold` performs the fold, so a wrong or
|
|
8
|
+
/// hostile plugin can yield a digest the destination refuses but cannot change a
|
|
9
|
+
/// commitment's shape. Nothing on the execution path reads it: a receiver enforces the
|
|
10
|
+
/// fold compiled into `ReceiverBase`.
|
|
11
|
+
///
|
|
12
|
+
/// @dev `view`, not `pure`: Blake2b-256 calls the EIP-152 precompile through `staticcall`.
|
|
13
|
+
interface ICommitmentScheme {
|
|
14
|
+
/// @notice The destination's hash of `data`.
|
|
15
|
+
/// @dev Must be the primitive the destination's receiver applies, checked against a test
|
|
16
|
+
/// corpus. A mismatch leaves an approval outstanding until a `cancel` crosses.
|
|
17
|
+
function hash(bytes calldata data) external view returns (bytes32);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// @title SchemeFold
|
|
21
|
+
/// @notice The commitment fold over a plugin's primitive.
|
|
22
|
+
/// @dev A second copy of `Commitment.hashCalls`'s fold. They cannot share code: `messaging`
|
|
23
|
+
/// imports `registry`, and the primitive is an enum arm in one and an external call in
|
|
24
|
+
/// the other. `test/CommitmentSchemePlugin.t.sol` pins the two equal for every enum
|
|
25
|
+
/// primitive.
|
|
26
|
+
library SchemeFold {
|
|
27
|
+
/// @dev Same selector as `Commitment.EmptyCommitment`.
|
|
28
|
+
error EmptyCommitment();
|
|
29
|
+
|
|
30
|
+
/// @notice The commitment `scheme`'s chain will require over `elements`.
|
|
31
|
+
/// @dev Seeded with the chainKey, so no plugin can bind a commitment to another chain. An
|
|
32
|
+
/// empty array reverts, as in `Commitment`, before the plugin is called.
|
|
33
|
+
function hashCalls(ICommitmentScheme scheme, bytes32 destinationChainKey, bytes[] memory elements)
|
|
34
|
+
internal
|
|
35
|
+
view
|
|
36
|
+
returns (bytes32 hashed)
|
|
37
|
+
{
|
|
38
|
+
uint256 len = elements.length;
|
|
39
|
+
if (len == 0) revert EmptyCommitment();
|
|
40
|
+
hashed = scheme.hash(abi.encode(destinationChainKey));
|
|
41
|
+
for (uint256 i = 0; i < len; i++) {
|
|
42
|
+
// forge-lint: disable-next-line(calls-loop) an owner-registered scheme
|
|
43
|
+
hashed = scheme.hash(abi.encodePacked(hashed, scheme.hash(elements[i])));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
/// @title IRefValidator
|
|
5
|
+
/// @notice The registry's per-chain value-range check on an address.
|
|
6
|
+
/// @dev ERC-7930 fixes structure, not ranges: `parseStrict` accepts 32 canonical bytes but
|
|
7
|
+
/// cannot reject a Starknet address above `L2_ADDRESS_UPPER_BOUND`. Set per chainKey by
|
|
8
|
+
/// `ChainRegistry.setValidator`.
|
|
9
|
+
interface IRefValidator {
|
|
10
|
+
/// @param interop Canonical ERC-7930 bytes, already structurally parsed.
|
|
11
|
+
/// @dev Reverts to reject. Called by `ChainRegistry.validateLocation`.
|
|
12
|
+
function validateRef(bytes calldata interop) external view;
|
|
13
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
/// @notice How much this chain can know about an address on another one.
|
|
5
|
+
///
|
|
6
|
+
/// @dev Grades a chain, not a stored value: every provider's transceiver reads the same answer
|
|
7
|
+
/// from `ChainRegistry.provenanceFor`, so two transceivers cannot disagree about one chain.
|
|
8
|
+
///
|
|
9
|
+
/// @dev Ordered by strength. `Predetermined`: this chain can recompute the address from inputs in a
|
|
10
|
+
/// signed transaction, because that chain's transceivers were deployed through
|
|
11
|
+
/// `ProxyDeployer`, which Arachnid's factory puts at one address, and this chain's
|
|
12
|
+
/// transceiver knows where: from the registry's prediction, the provider's salt under the
|
|
13
|
+
/// deployer recorded for that chain. `Unique`: it cannot, so
|
|
14
|
+
/// the value came over a bridge and is worth that bridge's security. A chain without
|
|
15
|
+
/// Arachnid's factory shares no address with any other, so it is `Unique` in every registry
|
|
16
|
+
/// and grades every other chain `Unique` in its own (#33).
|
|
17
|
+
///
|
|
18
|
+
/// @dev Checks are ordinal comparisons against a bar, and the registry's grades and a
|
|
19
|
+
/// transceiver's `minCounterpartProvenance` persist in storage. Inserting a grade
|
|
20
|
+
/// renumbers every stored value above it after deployment: append, or migrate.
|
|
21
|
+
enum Provenance {
|
|
22
|
+
Unknown,
|
|
23
|
+
Unique,
|
|
24
|
+
Predetermined
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {Blake2b256} from "../derivation/Blake2b256.sol";
|
|
5
|
+
import {ICommitmentScheme} from "../registry/ICommitmentScheme.sol";
|
|
6
|
+
|
|
7
|
+
/// @title Blake2bScheme
|
|
8
|
+
/// @notice Cardano's primitive. `Scheme.Blake2b256Scheme` in the enum the frozen
|
|
9
|
+
/// transmitters carry.
|
|
10
|
+
/// @dev The one that costs `pure`. `Blake2b256` reaches the EIP-152 precompile at 0x09
|
|
11
|
+
/// through `staticcall`, which Solidity forbids inside `pure`, so this member is
|
|
12
|
+
/// why `ICommitmentScheme.hash` is `view`, exactly as it is why the library's
|
|
13
|
+
/// scheme-parameterized overloads are.
|
|
14
|
+
contract Blake2bScheme is ICommitmentScheme {
|
|
15
|
+
function hash(bytes calldata data) external view override returns (bytes32) {
|
|
16
|
+
return Blake2b256.hash(data);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {ICommitmentScheme} from "../registry/ICommitmentScheme.sol";
|
|
5
|
+
|
|
6
|
+
/// @title KeccakScheme
|
|
7
|
+
/// @notice The primitive every EVM destination uses, plus Solana, Aptos, Sui, NEAR, and
|
|
8
|
+
/// Cosmos. `Scheme.Keccak256` in the enum the frozen transmitters carry.
|
|
9
|
+
///
|
|
10
|
+
/// @dev It exists to be the control. An EVM chain never needs the plugin path: its
|
|
11
|
+
/// receiver enforces with the keccak fold compiled into `ReceiverBase`. Registering
|
|
12
|
+
/// this one anyway means `ChainRegistry.commitmentFor` can be checked against
|
|
13
|
+
/// `Commitment.hashCalls` for the same inputs, which is the assertion that the
|
|
14
|
+
/// plugin seam reproduces the frozen path rather than merely resembling it.
|
|
15
|
+
contract KeccakScheme is ICommitmentScheme {
|
|
16
|
+
function hash(bytes calldata data) external pure override returns (bytes32) {
|
|
17
|
+
return keccak256(data);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {ICommitmentScheme} from "../registry/ICommitmentScheme.sol";
|
|
5
|
+
|
|
6
|
+
/// @title Sha256Scheme
|
|
7
|
+
/// @notice TON's primitive. `Scheme.Sha256` in the enum the frozen transmitters carry.
|
|
8
|
+
/// @dev `sha256` is an EVM builtin (precompile 0x02, wrapped by the compiler), so this
|
|
9
|
+
/// stays computable on both sides, which is why TON was expressible from the start
|
|
10
|
+
/// while Starknet was not.
|
|
11
|
+
contract Sha256Scheme is ICommitmentScheme {
|
|
12
|
+
function hash(bytes calldata data) external pure override returns (bytes32) {
|
|
13
|
+
return sha256(data);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
5
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
6
|
+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
7
|
+
|
|
8
|
+
/// @notice A transceiver's report float, which leaves only at its treasury's call.
|
|
9
|
+
interface IReportFloat {
|
|
10
|
+
function withdraw(uint256 amount) external;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/// @title Treasury
|
|
14
|
+
/// @notice Where a chain's outbound fees, bootstrap fees and report float land, and the one contract that can
|
|
15
|
+
/// move them out.
|
|
16
|
+
///
|
|
17
|
+
/// @dev A destination, not an authority: it configures nothing and reaches no conduit. Its one
|
|
18
|
+
/// outgoing call pulls a transceiver's float, which can only come here. Its owner decides
|
|
19
|
+
/// where funds go next; each transceiver's write-once `treasury` decides where they arrive,
|
|
20
|
+
/// so a compromised withdrawal path cannot redirect fees at the source.
|
|
21
|
+
///
|
|
22
|
+
/// @dev One per chain, shared by every provider there. Each transceiver names it once, at
|
|
23
|
+
/// initialization, so a replacement would receive no fees or floats from transceivers
|
|
24
|
+
/// already deployed: this one serves them for their whole life.
|
|
25
|
+
contract Treasury is Ownable {
|
|
26
|
+
using SafeERC20 for IERC20;
|
|
27
|
+
|
|
28
|
+
/// @notice Native currency left this treasury.
|
|
29
|
+
event NativeWithdrawn(address indexed to, uint256 amount);
|
|
30
|
+
|
|
31
|
+
/// @notice An ERC-20 balance left this treasury.
|
|
32
|
+
event TokenWithdrawn(address indexed token, address indexed to, uint256 amount);
|
|
33
|
+
|
|
34
|
+
/// @notice A transceiver's report float was pulled in.
|
|
35
|
+
event FloatCollected(address indexed from, uint256 amount);
|
|
36
|
+
|
|
37
|
+
/// @dev A withdrawal to the zero address would burn the balance.
|
|
38
|
+
error ZeroRecipient();
|
|
39
|
+
|
|
40
|
+
/// @dev The native transfer failed; carries the recipient's revert reason.
|
|
41
|
+
error NativeTransferFailed(address to, uint256 amount, bytes reason);
|
|
42
|
+
|
|
43
|
+
constructor(address initialOwner) Ownable(initialOwner) {}
|
|
44
|
+
|
|
45
|
+
/// @notice Accept the fees transmitters and transceivers collect with a plain `call`.
|
|
46
|
+
receive() external payable {}
|
|
47
|
+
|
|
48
|
+
/// @notice Pull `amount` of a transceiver's report float into this treasury.
|
|
49
|
+
/// @dev The transceiver pays only its treasury, so the owner chooses when, not where.
|
|
50
|
+
function collect(IReportFloat from, uint256 amount) external onlyOwner {
|
|
51
|
+
emit FloatCollected(address(from), amount);
|
|
52
|
+
from.withdraw(amount);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// @notice Send `amount` of native currency to `to`.
|
|
56
|
+
function withdraw(address to, uint256 amount) external onlyOwner {
|
|
57
|
+
if (to == address(0)) revert ZeroRecipient();
|
|
58
|
+
|
|
59
|
+
// `call`, not `transfer`: a msig recipient needs more than the 2300-gas stipend, and
|
|
60
|
+
// there is no state here for a re-entrant call to confuse.
|
|
61
|
+
emit NativeWithdrawn(to, amount);
|
|
62
|
+
|
|
63
|
+
(bool ok, bytes memory reason) = to.call{value: amount}("");
|
|
64
|
+
if (!ok) revert NativeTransferFailed(to, amount, reason);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// @notice Send `amount` of `token` to `to`.
|
|
68
|
+
/// @dev `SafeERC20` for tokens such as USDT whose `transfer` returns nothing.
|
|
69
|
+
function withdrawERC20(IERC20 token, address to, uint256 amount) external onlyOwner {
|
|
70
|
+
if (to == address(0)) revert ZeroRecipient();
|
|
71
|
+
|
|
72
|
+
token.safeTransfer(to, amount);
|
|
73
|
+
|
|
74
|
+
emit TokenWithdrawn(address(token), to, amount);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {Move} from "../addressing/Move.sol";
|
|
5
|
+
import {Erc7930} from "../addressing/Erc7930.sol";
|
|
6
|
+
import {IRefValidator} from "../registry/IRefValidator.sol";
|
|
7
|
+
|
|
8
|
+
/// @title MoveValidator
|
|
9
|
+
/// @notice Per-chain validator for Move references.
|
|
10
|
+
/// @dev Enforces the fixed 32-byte address width. Move addresses have a short display
|
|
11
|
+
/// form (`0x1` and the zero-padded 32-byte form are the same address, AIP-40),
|
|
12
|
+
/// which has caused real production bugs. Accepting a short form here would give
|
|
13
|
+
/// one address two distinct registry keys, so anything but 32 bytes is rejected.
|
|
14
|
+
contract MoveValidator is IRefValidator {
|
|
15
|
+
function validateRef(bytes calldata interop) external pure override {
|
|
16
|
+
Erc7930.Interop memory io = Erc7930.parseStrict(interop);
|
|
17
|
+
if (!Move.isMoveChain(io.chainType)) revert Move.NotMoveChain();
|
|
18
|
+
// Zero-length address is a Chain Identifier, which has no address to check.
|
|
19
|
+
if (io.addr.length == 0) return;
|
|
20
|
+
if (io.addr.length != Move.MOVE_ADDRESS_BYTES) {
|
|
21
|
+
revert Move.BadMoveAddressLength();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {StarknetDerive} from "../derivation/StarknetDerive.sol";
|
|
5
|
+
import {Erc7930} from "../addressing/Erc7930.sol";
|
|
6
|
+
import {IRefValidator} from "../registry/IRefValidator.sol";
|
|
7
|
+
|
|
8
|
+
/// @title StarknetValidator
|
|
9
|
+
/// @notice Rejects Starknet references whose address is a well-formed 32-byte value
|
|
10
|
+
/// that no Starknet contract can ever occupy.
|
|
11
|
+
/// @dev This is the constraint the 7930 envelope structurally cannot catch: length is
|
|
12
|
+
/// correct, framing is canonical, and the value is still impossible.
|
|
13
|
+
contract StarknetValidator is IRefValidator {
|
|
14
|
+
function validateRef(bytes calldata interop) external pure override {
|
|
15
|
+
Erc7930.Interop memory io = Erc7930.parseStrict(interop);
|
|
16
|
+
// A zero-length address is a Chain Identifier, which has no felt to bound.
|
|
17
|
+
if (io.addr.length == 0) return;
|
|
18
|
+
StarknetDerive.validateAddress(StarknetDerive.toFelt(io.addr));
|
|
19
|
+
}
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossecute/protocol",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Crossecute protocol interfaces, libraries and ABIs for integrators",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/crossecute/protocol.git",
|
|
9
|
+
"directory": "contracts/evm/npm"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
"./abi": {
|
|
14
|
+
"types": "./abi/index.d.ts",
|
|
15
|
+
"default": "./abi/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./abi/*.json": "./abi/*.json",
|
|
18
|
+
"./contracts/*": "./contracts/*"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"abi",
|
|
22
|
+
"contracts",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "cd .. && forge build && node npm/pack.mjs",
|
|
27
|
+
"prepack": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@openzeppelin/contracts": "5.4.0",
|
|
31
|
+
"@openzeppelin/contracts-upgradeable": "5.4.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependenciesMeta": {
|
|
34
|
+
"@openzeppelin/contracts-upgradeable": {
|
|
35
|
+
"optional": true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
7
38
|
}
|