Merge branch 'main' into main

This commit is contained in:
Steve Degosserie 2026-01-26 10:01:05 +02:00 committed by GitHub
commit 3f531c8889
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
145 changed files with 1955 additions and 1341 deletions

View file

@ -14,7 +14,7 @@
"!**/.papi/descriptors/**/*",
"!**/contract-bindings/**/*",
"!**/html/**/*",
"!**/datahaven/contracts/out/**/*",
"!**/moonwall/contracts/out/**/*",
"!**/contracts/out/**/*",
"!**/contracts/deployments/state-diff.checksum"
],

View file

@ -1,7 +1,7 @@
{
"name": "DataHaven",
"website": "https://datahaven.xyz/",
"description": "DataHaven is a decentralized, EigenLayer-secured AVS for distributed storage. By leveraging restaking, it ensures tamper-proof, censorship-resistant, and verifiable data persistence. Designed with AI and Web3 ecosystems in mind, DataHaven integrates seamlessly with smart contracts, offering developers reliable storage infrastructure for models, logs, and digital assets at scale..",
"logo": "https://raw.githubusercontent.com/datahaven-xyz/datahaven-files/refs/heads/main/files/datahaven-logo.png",
"description": "DataHaven is a decentralized, EigenLayer-secured AVS for distributed storage. By leveraging restaking, it ensures tamper-proof, censorship-resistant, and verifiable data persistence. Designed with AI and Web3 ecosystems in mind, DataHaven integrates seamlessly with smart contracts, offering developers reliable storage infrastructure for models, logs, and digital assets at scale.",
"logo": "https://raw.githubusercontent.com/datahaven-xyz/datahaven/refs/heads/main/contracts/deployments/datahaven-logo.png",
"twitter": "https://x.com/datahaven_xyz"
}

View file

@ -1 +1 @@
c23b1c40740f73273dddba8b23b9b1a84003e5a1
711490494719593c219c35ca496cd28b86d9f54a

File diff suppressed because one or more lines are too long

View file

@ -17,7 +17,6 @@
# Defines paths for Solidity imports.
remappings = [
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/ds-test/src/",
"eigenlayer-contracts/=lib/eigenlayer-contracts/",
"snowbridge/=lib/snowbridge/contracts/",
"@openzeppelin/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/",
@ -28,13 +27,9 @@
"lib/snowbridge/contracts/:prb/math/=lib/snowbridge/contracts/lib/prb-math/",
"openzeppelin/=lib/snowbridge/contracts/lib/openzeppelin-contracts/contracts/",
"prb/math/=lib/snowbridge/contracts/lib/prb-math/",
"src/contracts/=lib/eigenlayer-contracts/src/contracts/",
"src/test/=lib/eigenlayer-contracts/src/test/",
]
# Specifies the exact version of Solidity to use, overriding auto-detection.
solc_version = '0.8.28'
# If enabled, treats Solidity compiler warnings as errors, preventing artifact generation if warnings are present.
deny_warnings = false
# If set to true, changes compilation pipeline to go through the new IR optimizer.
via_ir = false
# Whether or not to enable the Solidity optimizer.
@ -118,4 +113,11 @@
anvil = "http://localhost:8545"
# [etherscan]
# mainnet = { key = "${ETHERSCAN_API_KEY}" }
# mainnet = { key = "${ETHERSCAN_API_KEY}" }
[lint]
# Global lint suppressions for naming conventions
exclude_lints = [
"mixed-case-function", # Keep AVS/EL/ERC naming conventions
"mixed-case-variable", # Keep __GAP, ethPOSDeposit, _metadataURI naming
]

View file

@ -13,7 +13,6 @@ import {Gateway} from "snowbridge/src/Gateway.sol";
import {IGatewayV2} from "snowbridge/src/v2/IGateway.sol";
import {GatewayProxy} from "snowbridge/src/GatewayProxy.sol";
import {AgentExecutor} from "snowbridge/src/AgentExecutor.sol";
import {Agent} from "snowbridge/src/Agent.sol";
import {Initializer} from "snowbridge/src/Initializer.sol";
import {OperatingMode} from "snowbridge/src/types/Common.sol";
import {ud60x18} from "snowbridge/lib/prb-math/src/UD60x18.sol";
@ -21,9 +20,6 @@ import {BeefyClient} from "snowbridge/src/BeefyClient.sol";
// OpenZeppelin imports
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {
TransparentUpgradeableProxy
} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
// EigenLayer imports
import {AllocationManager} from "eigenlayer-contracts/src/contracts/core/AllocationManager.sol";

View file

@ -10,19 +10,6 @@ import {IGatewayV2} from "snowbridge/src/v2/IGateway.sol";
// Logging import
import {Logging} from "../utils/Logging.sol";
import {Accounts} from "../utils/Accounts.sol";
import {ValidatorsUtils} from "../utils/ValidatorsUtils.sol";
// Snowbridge imports
import {Gateway} from "snowbridge/src/Gateway.sol";
import {IGatewayV2} from "snowbridge/src/v2/IGateway.sol";
import {GatewayProxy} from "snowbridge/src/GatewayProxy.sol";
import {AgentExecutor} from "snowbridge/src/AgentExecutor.sol";
import {Agent} from "snowbridge/src/Agent.sol";
import {Initializer} from "snowbridge/src/Initializer.sol";
import {OperatingMode} from "snowbridge/src/types/Common.sol";
import {ud60x18} from "snowbridge/lib/prb-math/src/UD60x18.sol";
import {BeefyClient} from "snowbridge/src/BeefyClient.sol";
// Additional imports specific to local deployment
import {
@ -49,12 +36,8 @@ import {
PermissionController
} from "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol";
import {
IAllocationManagerTypes
} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IETHPOSDeposit} from "eigenlayer-contracts/src/contracts/interfaces/IETHPOSDeposit.sol";
import {
IRewardsCoordinator,
IRewardsCoordinatorTypes
} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
@ -189,7 +172,7 @@ contract DeployLocal is DeployBase {
_deployImplementations(eigenLayerConfig, pauserRegistry);
Logging.logStep("Implementation contracts deployed successfully");
// Upgrade proxies to point to implementations and initialise
// Upgrade proxies to point to implementations and initialize
Logging.logSection("Initializing Contracts");
_upgradeAndInitializeProxies(eigenLayerConfig, proxyAdmin);
Logging.logStep("Proxies upgraded and initialized successfully");
@ -220,7 +203,7 @@ contract DeployLocal is DeployBase {
vm.broadcast(_deployerPrivateKey);
bytes memory initData = abi.encodeWithSelector(
DataHavenServiceManager.initialise.selector,
DataHavenServiceManager.initialize.selector,
params.avsOwner,
params.rewardsInitiator,
params.validatorsStrategies,

View file

@ -5,8 +5,11 @@ import {EmptyContract} from "eigenlayer-contracts/src/test/mocks/EmptyContract.s
import {Config} from "./Config.sol";
import {Script} from "forge-std/Script.sol";
import {TestUtils} from "../../test/utils/TestUtils.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
contract DeployParams is Script, Config {
using SafeCast for uint256;
function getSnowbridgeConfig() public view returns (SnowbridgeConfig memory) {
SnowbridgeConfig memory config;
@ -20,7 +23,7 @@ contract DeployParams is Script, Config {
vm.parseJsonUint(configJson, ".snowbridge.randaoCommitExpiration");
config.minNumRequiredSignatures =
vm.parseJsonUint(configJson, ".snowbridge.minNumRequiredSignatures");
config.startBlock = uint64(vm.parseJsonUint(configJson, ".snowbridge.startBlock"));
config.startBlock = vm.parseJsonUint(configJson, ".snowbridge.startBlock").toUint64();
config.rewardsMessageOrigin =
vm.parseJsonBytes32(configJson, ".snowbridge.rewardsMessageOrigin");
@ -56,7 +59,7 @@ contract DeployParams is Script, Config {
}
config.rewardsInitiator = vm.parseJsonAddress(configJson, ".avs.rewardsInitiator");
config.vetoCommitteeMember = vm.parseJsonAddress(configJson, ".avs.vetoCommitteeMember");
config.vetoWindowBlocks = uint32(vm.parseJsonUint(configJson, ".avs.vetoWindowBlocks"));
config.vetoWindowBlocks = vm.parseJsonUint(configJson, ".avs.vetoWindowBlocks").toUint32();
config.validatorsStrategies =
vm.parseJsonAddressArray(configJson, ".avs.validatorsStrategies");
@ -76,15 +79,17 @@ contract DeployParams is Script, Config {
config.unpauserAddress = vm.parseJsonAddress(configJson, ".eigenLayer.unpauser");
config.rewardsUpdater = vm.parseJsonAddress(configJson, ".eigenLayer.rewardsUpdater");
config.calculationIntervalSeconds =
uint32(vm.parseJsonUint(configJson, ".eigenLayer.calculationIntervalSeconds"));
vm.parseJsonUint(configJson, ".eigenLayer.calculationIntervalSeconds").toUint32();
config.maxRewardsDuration =
uint32(vm.parseJsonUint(configJson, ".eigenLayer.maxRewardsDuration"));
vm.parseJsonUint(configJson, ".eigenLayer.maxRewardsDuration").toUint32();
config.maxRetroactiveLength =
uint32(vm.parseJsonUint(configJson, ".eigenLayer.maxRetroactiveLength"));
config.maxFutureLength = uint32(vm.parseJsonUint(configJson, ".eigenLayer.maxFutureLength"));
vm.parseJsonUint(configJson, ".eigenLayer.maxRetroactiveLength").toUint32();
config.maxFutureLength =
vm.parseJsonUint(configJson, ".eigenLayer.maxFutureLength").toUint32();
config.genesisRewardsTimestamp =
uint32(vm.parseJsonUint(configJson, ".eigenLayer.genesisRewardsTimestamp"));
config.activationDelay = uint32(vm.parseJsonUint(configJson, ".eigenLayer.activationDelay"));
vm.parseJsonUint(configJson, ".eigenLayer.genesisRewardsTimestamp").toUint32();
config.activationDelay =
vm.parseJsonUint(configJson, ".eigenLayer.activationDelay").toUint32();
config.globalCommissionBips =
uint16(vm.parseJsonUint(configJson, ".eigenLayer.globalCommissionBips"));
config.executorMultisig = vm.parseJsonAddress(configJson, ".eigenLayer.executorMultisig");
@ -95,7 +100,7 @@ contract DeployParams is Script, Config {
try vm.parseJsonUint(configJson, ".eigenLayer.minWithdrawalDelayBlocks") returns (
uint256 val
) {
config.minWithdrawalDelayBlocks = uint32(val);
config.minWithdrawalDelayBlocks = val.toUint32();
} catch {
config.minWithdrawalDelayBlocks = 7 days / 12 seconds; // Default: 1 week in blocks at 12s per block
}
@ -103,7 +108,7 @@ contract DeployParams is Script, Config {
try vm.parseJsonUint(configJson, ".eigenLayer.delegationWithdrawalDelayBlocks") returns (
uint256 val
) {
config.delegationWithdrawalDelayBlocks = uint32(val);
config.delegationWithdrawalDelayBlocks = val.toUint32();
} catch {
config.delegationWithdrawalDelayBlocks = 7 days / 12 seconds; // Default: 1 week
}
@ -149,7 +154,7 @@ contract DeployParams is Script, Config {
}
try vm.parseJsonUint(configJson, ".eigenLayer.deallocationDelay") returns (uint256 val) {
config.deallocationDelay = uint32(val);
config.deallocationDelay = val.toUint32();
} catch {
config.deallocationDelay = 7 days; // Default: 1 week
}
@ -157,7 +162,7 @@ contract DeployParams is Script, Config {
try vm.parseJsonUint(configJson, ".eigenLayer.allocationConfigurationDelay") returns (
uint256 val
) {
config.allocationConfigurationDelay = uint32(val);
config.allocationConfigurationDelay = val.toUint32();
} catch {
config.allocationConfigurationDelay = 1 days; // Default: 1 day
}
@ -165,7 +170,7 @@ contract DeployParams is Script, Config {
try vm.parseJsonUint(configJson, ".eigenLayer.beaconChainGenesisTimestamp") returns (
uint256 val
) {
config.beaconChainGenesisTimestamp = uint64(val);
config.beaconChainGenesisTimestamp = val.toUint64();
} catch {
config.beaconChainGenesisTimestamp = 1616508000; // Mainnet default
}

View file

@ -18,7 +18,6 @@ import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory
import {DelegationManager} from "eigenlayer-contracts/src/contracts/core/DelegationManager.sol";
import {RewardsCoordinator} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol";
import {StrategyManager} from "eigenlayer-contracts/src/contracts/core/StrategyManager.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {
PermissionController
} from "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol";
@ -61,7 +60,7 @@ contract DeployTestnet is DeployBase {
return networkName;
}
function _getDeploymentMode() internal view override returns (string memory) {
function _getDeploymentMode() internal pure override returns (string memory) {
return "HOODI_TESTNET";
}
@ -117,7 +116,7 @@ contract DeployTestnet is DeployBase {
vm.broadcast(_deployerPrivateKey);
bytes memory initData = abi.encodeWithSelector(
DataHavenServiceManager.initialise.selector,
DataHavenServiceManager.initialize.selector,
params.avsOwner,
params.rewardsInitiator,
params.validatorsStrategies,

View file

@ -2,7 +2,6 @@
pragma solidity ^0.8.27;
import {SignUpOperatorBase} from "./SignUpOperatorBase.s.sol";
import {DataHavenServiceManager} from "../../src/DataHavenServiceManager.sol";
/**
* @title SignUpValidator

View file

@ -12,9 +12,7 @@ import {
import {AllocationManager} from "eigenlayer-contracts/src/contracts/core/AllocationManager.sol";
import {DelegationManager} from "eigenlayer-contracts/src/contracts/core/DelegationManager.sol";
import {StrategyManager} from "eigenlayer-contracts/src/contracts/core/StrategyManager.sol";
import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol";
import {EigenPodManager} from "eigenlayer-contracts/src/contracts/pods/EigenPodManager.sol";
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import {EigenPod} from "eigenlayer-contracts/src/contracts/pods/EigenPod.sol";
import {
StrategyBaseTVLLimits

View file

@ -36,7 +36,8 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
// ============ Constants ============
/// @notice The metadata for the DataHaven AVS.
string public constant DATAHAVEN_AVS_METADATA = "https://datahaven.network/";
string public constant DATAHAVEN_AVS_METADATA =
"https://raw.githubusercontent.com/datahaven-xyz/datahaven/refs/heads/main/contracts/deployments/metadata.json";
/// @notice The EigenLayer operator set ID for the Validators securing the DataHaven network.
uint32 public constant VALIDATORS_SET_ID = 0;
@ -44,10 +45,10 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
// ============ Immutables ============
/// @notice The EigenLayer AllocationManager contract
IAllocationManager internal immutable _allocationManager;
IAllocationManager internal immutable _ALLOCATION_MANAGER;
/// @notice The EigenLayer RewardsCoordinator contract
IRewardsCoordinator internal immutable _rewardsCoordinator;
IRewardsCoordinator internal immutable _REWARDS_COORDINATOR;
// ============ State Variables ============
@ -71,65 +72,83 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
/// @notice Restricts function to the rewards initiator
modifier onlyRewardsInitiator() {
require(msg.sender == rewardsInitiator, OnlyRewardsInitiator());
_checkRewardsInitiator();
_;
}
/// @notice Restricts function to registered validators
modifier onlyValidator() {
OperatorSet memory operatorSet = OperatorSet({avs: address(this), id: VALIDATORS_SET_ID});
require(
_allocationManager.isMemberOfOperatorSet(msg.sender, operatorSet),
CallerIsNotValidator()
);
_checkValidator();
_;
}
/// @notice Restricts function to the EigenLayer AllocationManager
modifier onlyAllocationManager() {
require(msg.sender == address(_allocationManager), OnlyAllocationManager());
_checkAllocationManager();
_;
}
function _checkRewardsInitiator() internal view {
require(msg.sender == rewardsInitiator, OnlyRewardsInitiator());
}
function _checkValidator() internal view {
OperatorSet memory operatorSet = OperatorSet({avs: address(this), id: VALIDATORS_SET_ID});
require(
_ALLOCATION_MANAGER.isMemberOfOperatorSet(msg.sender, operatorSet),
CallerIsNotValidator()
);
}
function _checkAllocationManager() internal view {
require(msg.sender == address(_ALLOCATION_MANAGER), OnlyAllocationManager());
}
// ============ Constructor ============
/// @notice Sets the immutable EigenLayer contract references
/// @param __rewardsCoordinator The EigenLayer RewardsCoordinator contract
/// @param __allocationManager The EigenLayer AllocationManager contract
/// @param rewardsCoordinator_ The EigenLayer RewardsCoordinator contract
/// @param allocationManager_ The EigenLayer AllocationManager contract
constructor(
IRewardsCoordinator __rewardsCoordinator,
IAllocationManager __allocationManager
IRewardsCoordinator rewardsCoordinator_,
IAllocationManager allocationManager_
) {
_rewardsCoordinator = __rewardsCoordinator;
_allocationManager = __allocationManager;
_REWARDS_COORDINATOR = rewardsCoordinator_;
_ALLOCATION_MANAGER = allocationManager_;
_disableInitializers();
}
// ============ Initializer ============
/// @inheritdoc IDataHavenServiceManager
function initialise(
function initialize(
address initialOwner,
address _rewardsInitiator,
IStrategy[] memory validatorsStrategies,
address _snowbridgeGatewayAddress
) public virtual initializer {
require(initialOwner != address(0), ZeroAddress());
require(_rewardsInitiator != address(0), ZeroAddress());
require(_snowbridgeGatewayAddress != address(0), ZeroAddress());
__Ownable_init();
_transferOwnership(initialOwner);
_setRewardsInitiator(_rewardsInitiator);
rewardsInitiator = _rewardsInitiator;
emit RewardsInitiatorSet(address(0), _rewardsInitiator);
// Register the DataHaven service in the AllocationManager.
_allocationManager.updateAVSMetadataURI(address(this), DATAHAVEN_AVS_METADATA);
_ALLOCATION_MANAGER.updateAVSMetadataURI(address(this), DATAHAVEN_AVS_METADATA);
// Create the operator set for the DataHaven service.
_createDataHavenOperatorSets(validatorsStrategies);
IAllocationManagerTypes.CreateSetParams[] memory operatorSets =
new IAllocationManagerTypes.CreateSetParams[](1);
operatorSets[0] = IAllocationManagerTypes.CreateSetParams({
operatorSetId: VALIDATORS_SET_ID, strategies: validatorsStrategies
});
_ALLOCATION_MANAGER.createOperatorSets(address(this), operatorSets);
// Set the Snowbridge Gateway address.
_snowbridgeGateway = IGatewayV2(_snowbridgeGatewayAddress);
}
// ============ Snowbridge Functions ============
/// @inheritdoc IDataHavenServiceManager
function sendNewValidatorSet(
uint128 executionFee,
@ -144,31 +163,42 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
/// @inheritdoc IDataHavenServiceManager
function buildNewValidatorSetMessage() public view returns (bytes memory) {
OperatorSet memory operatorSet = OperatorSet({avs: address(this), id: VALIDATORS_SET_ID});
address[] memory currentValidatorSet = _allocationManager.getMembers(operatorSet);
address[] memory currentValidatorSet = _ALLOCATION_MANAGER.getMembers(operatorSet);
// Allocate max size, then resize after filtering
address[] memory newValidatorSet = new address[](currentValidatorSet.length);
uint256 validCount = 0;
for (uint256 i = 0; i < currentValidatorSet.length; i++) {
newValidatorSet[i] = validatorEthAddressToSolochainAddress[currentValidatorSet[i]];
address solochainAddr = validatorEthAddressToSolochainAddress[currentValidatorSet[i]];
if (solochainAddr != address(0)) {
newValidatorSet[validCount] = solochainAddr;
++validCount;
}
}
// Resize array to actual count
assembly {
mstore(newValidatorSet, validCount)
}
DataHavenSnowbridgeMessages.NewValidatorSetPayload memory newValidatorSetPayload =
DataHavenSnowbridgeMessages.NewValidatorSetPayload({validators: newValidatorSet});
DataHavenSnowbridgeMessages.NewValidatorSet memory newValidatorSetMessage =
DataHavenSnowbridgeMessages.NewValidatorSet({payload: newValidatorSetPayload});
return DataHavenSnowbridgeMessages.scaleEncodeNewValidatorSetMessage(newValidatorSetMessage);
return DataHavenSnowbridgeMessages.scaleEncodeNewValidatorSetMessagePayload(
DataHavenSnowbridgeMessages.NewValidatorSetPayload({validators: newValidatorSet})
);
}
/// @inheritdoc IDataHavenServiceManager
function updateSolochainAddressForValidator(
address solochainAddress
) external onlyValidator {
require(solochainAddress != address(0), ZeroAddress());
validatorEthAddressToSolochainAddress[msg.sender] = solochainAddress;
emit SolochainAddressUpdated(msg.sender, solochainAddress);
}
/// @inheritdoc IDataHavenServiceManager
function setSnowbridgeGateway(
address _newSnowbridgeGateway
) external onlyOwner {
require(_newSnowbridgeGateway != address(0), ZeroAddress());
_snowbridgeGateway = IGatewayV2(_newSnowbridgeGateway);
emit SnowbridgeGatewaySet(_newSnowbridgeGateway);
}
@ -187,24 +217,11 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
uint32[] calldata operatorSetIds,
bytes calldata data
) external override onlyAllocationManager {
if (avsAddress != address(this)) {
revert IncorrectAVSAddress();
}
if (operatorSetIds.length != 1) {
revert CantRegisterToMultipleOperatorSets();
}
if (operatorSetIds[0] != VALIDATORS_SET_ID) {
revert InvalidOperatorSetId();
}
if (!validatorsAllowlist[operator]) {
revert OperatorNotInAllowlist();
}
require(data.length == 20, "Invalid solochain address length");
validatorEthAddressToSolochainAddress[operator] = address(bytes20(data));
require(avsAddress == address(this), IncorrectAVSAddress());
require(operatorSetIds.length == 1, CantRegisterToMultipleOperatorSets());
require(operatorSetIds[0] == VALIDATORS_SET_ID, InvalidOperatorSetId());
require(validatorsAllowlist[operator], OperatorNotInAllowlist());
validatorEthAddressToSolochainAddress[operator] = _toAddress(data);
emit OperatorRegistered(operator, operatorSetIds[0]);
}
@ -215,17 +232,9 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
address avsAddress,
uint32[] calldata operatorSetIds
) external override onlyAllocationManager {
if (avsAddress != address(this)) {
revert IncorrectAVSAddress();
}
if (operatorSetIds.length != 1) {
revert CantDeregisterFromMultipleOperatorSets();
}
if (operatorSetIds[0] != VALIDATORS_SET_ID) {
revert InvalidOperatorSetId();
}
require(avsAddress == address(this), IncorrectAVSAddress());
require(operatorSetIds.length == 1, CantDeregisterFromMultipleOperatorSets());
require(operatorSetIds[0] == VALIDATORS_SET_ID, InvalidOperatorSetId());
delete validatorEthAddressToSolochainAddress[operator];
@ -245,6 +254,7 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
function addValidatorToAllowlist(
address validator
) external onlyOwner {
require(validator != address(0), ZeroAddress());
validatorsAllowlist[validator] = true;
emit ValidatorAddedToAllowlist(validator);
}
@ -260,14 +270,14 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
/// @inheritdoc IDataHavenServiceManager
function validatorsSupportedStrategies() external view returns (IStrategy[] memory) {
OperatorSet memory operatorSet = OperatorSet({avs: address(this), id: VALIDATORS_SET_ID});
return _allocationManager.getStrategiesInOperatorSet(operatorSet);
return _ALLOCATION_MANAGER.getStrategiesInOperatorSet(operatorSet);
}
/// @inheritdoc IDataHavenServiceManager
function removeStrategiesFromValidatorsSupportedStrategies(
IStrategy[] calldata _strategies
) external onlyOwner {
_allocationManager.removeStrategiesFromOperatorSet(
_ALLOCATION_MANAGER.removeStrategiesFromOperatorSet(
address(this), VALIDATORS_SET_ID, _strategies
);
}
@ -276,7 +286,9 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
function addStrategiesToValidatorsSupportedStrategies(
IStrategy[] calldata _strategies
) external onlyOwner {
_allocationManager.addStrategiesToOperatorSet(address(this), VALIDATORS_SET_ID, _strategies);
_ALLOCATION_MANAGER.addStrategiesToOperatorSet(
address(this), VALIDATORS_SET_ID, _strategies
);
}
// ============ Rewards Functions ============
@ -290,14 +302,14 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
totalAmount += submission.operatorRewards[i].amount;
}
submission.token.safeIncreaseAllowance(address(_rewardsCoordinator), totalAmount);
submission.token.safeIncreaseAllowance(address(_REWARDS_COORDINATOR), totalAmount);
IRewardsCoordinatorTypes.OperatorDirectedRewardsSubmission[] memory submissions =
new IRewardsCoordinatorTypes.OperatorDirectedRewardsSubmission[](1);
submissions[0] = submission;
OperatorSet memory operatorSet = OperatorSet({avs: address(this), id: VALIDATORS_SET_ID});
_rewardsCoordinator.createOperatorDirectedOperatorSetRewardsSubmission(
_REWARDS_COORDINATOR.createOperatorDirectedOperatorSetRewardsSubmission(
operatorSet, submissions
);
@ -308,8 +320,9 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
function setRewardsInitiator(
address newRewardsInitiator
) external override onlyOwner {
require(newRewardsInitiator != address(0), ZeroAddress());
address oldInitiator = rewardsInitiator;
_setRewardsInitiator(newRewardsInitiator);
rewardsInitiator = newRewardsInitiator;
emit RewardsInitiatorSet(oldInitiator, newRewardsInitiator);
}
@ -319,7 +332,7 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
function updateAVSMetadataURI(
string memory _metadataURI
) external onlyOwner {
_allocationManager.updateAVSMetadataURI(address(this), _metadataURI);
_ALLOCATION_MANAGER.updateAVSMetadataURI(address(this), _metadataURI);
}
/// @inheritdoc IDataHavenServiceManager
@ -331,33 +344,48 @@ contract DataHavenServiceManager is OwnableUpgradeable, IAVSRegistrar, IDataHave
IAllocationManagerTypes.DeregisterParams({
operator: operator, avs: address(this), operatorSetIds: operatorSetIds
});
_allocationManager.deregisterFromOperatorSets(params);
_ALLOCATION_MANAGER.deregisterFromOperatorSets(params);
}
// ============ Slashing Submitter Functions ============
/**
* @notice Slash the operators of the validators set
* @param slashings array of request to slash operator containing the operator to slash, array of proportions to slash and the reason of the slashing.
*/
function slashValidatorsOperator(
SlashingRequest[] calldata slashings
) external onlyRewardsInitiator {
for (uint256 i = 0; i < slashings.length; i++) {
IAllocationManagerTypes.SlashingParams memory slashingParams =
IAllocationManagerTypes.SlashingParams({
operator: slashings[i].operator,
operatorSetId: VALIDATORS_SET_ID,
strategies: slashings[i].strategies,
wadsToSlash: slashings[i].wadsToSlash,
description: slashings[i].description
});
_ALLOCATION_MANAGER.slashOperator(address(this), slashingParams);
}
emit SlashingComplete();
}
// ============ Internal Functions ============
/**
* @notice Creates the initial operator set for DataHaven in the AllocationManager.
* @dev This function should be called during initialisation to set up the required operator set.
* @notice Safely converts a 20-byte array to an address
* @param data The bytes to convert (must be exactly 20 bytes)
* @return result The address representation of the bytes
*/
function _createDataHavenOperatorSets(
IStrategy[] memory validatorsStrategies
) internal {
IAllocationManagerTypes.CreateSetParams[] memory operatorSets =
new IAllocationManagerTypes.CreateSetParams[](1);
operatorSets[0] = IAllocationManagerTypes.CreateSetParams({
operatorSetId: VALIDATORS_SET_ID, strategies: validatorsStrategies
});
_allocationManager.createOperatorSets(address(this), operatorSets);
}
/**
* @notice Internal function to set the rewards initiator
* @param _rewardsInitiator The new rewards initiator address
*/
function _setRewardsInitiator(
address _rewardsInitiator
) internal {
rewardsInitiator = _rewardsInitiator;
function _toAddress(
bytes memory data
) private pure returns (address result) {
require(data.length == 20, "Invalid address length");
assembly {
result := shr(96, mload(add(data, 32)))
}
require(result != address(0), ZeroAddress());
}
}

View file

@ -28,6 +28,10 @@ interface IDataHavenServiceManagerErrors {
error OnlyRewardsInitiator();
/// @notice Thrown when a function is called by an address that is not the AllocationManager
error OnlyAllocationManager();
/// @notice Thrown when a zero address is provided where a non-zero address is required
error ZeroAddress();
/// @notice Thrown when the solochain address data length is not 20 bytes
error InvalidSolochainAddressLength();
}
/**
@ -66,6 +70,14 @@ interface IDataHavenServiceManagerEvents {
/// @param oldInitiator The previous rewards initiator address
/// @param newInitiator The new rewards initiator address
event RewardsInitiatorSet(address indexed oldInitiator, address indexed newInitiator);
/// @notice Emitted when a validator updates their solochain address
/// @param validator Address of the validator
/// @param solochainAddress The new solochain address
event SolochainAddressUpdated(address indexed validator, address indexed solochainAddress);
/// @notice Emitted when a batch of slashing request is being successfully slashed
event SlashingComplete();
}
/**
@ -77,6 +89,14 @@ interface IDataHavenServiceManager is
IDataHavenServiceManagerErrors,
IDataHavenServiceManagerEvents
{
/// @notice Slashing request sent from the datahaven slashing pallet via snowbridge to slash operators in the validators set in EL.
struct SlashingRequest {
address operator;
IStrategy[] strategies;
uint256[] wadsToSlash;
string description;
}
/// @notice Checks if a validator address is in the allowlist
/// @param validator Address to check
/// @return True if the validator is in the allowlist, false otherwise
@ -103,7 +123,7 @@ interface IDataHavenServiceManager is
* @param rewardsInitiator Address authorized to initiate rewards
* @param validatorsStrategies Array of strategies supported by validators
*/
function initialise(
function initialize(
address initialOwner,
address rewardsInitiator,
IStrategy[] memory validatorsStrategies,

View file

@ -37,17 +37,6 @@ library DataHavenSnowbridgeMessages {
address[] validators;
}
/**
* @notice Encodes a new validator set message into a bytes array.
* @param message The new validator set message to encode.
* @return The encoded message.
*/
function scaleEncodeNewValidatorSetMessage(
NewValidatorSet memory message
) public pure returns (bytes memory) {
return scaleEncodeNewValidatorSetMessagePayload(message.payload);
}
/**
* @notice Encodes a new validator set message payload into a bytes array.
* @param payload The new validator set message payload to encode.

View file

@ -17,11 +17,8 @@ contract MessageEncodingTest is Test {
DataHavenSnowbridgeMessages.NewValidatorSetPayload memory payload =
DataHavenSnowbridgeMessages.NewValidatorSetPayload({validators: mockValidators});
DataHavenSnowbridgeMessages.NewValidatorSet memory newValidatorSetMessage =
DataHavenSnowbridgeMessages.NewValidatorSet({payload: payload});
bytes memory encodedMessage =
DataHavenSnowbridgeMessages.scaleEncodeNewValidatorSetMessage(newValidatorSetMessage);
DataHavenSnowbridgeMessages.scaleEncodeNewValidatorSetMessagePayload(payload);
console.logBytes(encodedMessage);
}

View file

@ -3,27 +3,19 @@ pragma solidity ^0.8.13;
/* solhint-disable func-name-mixedcase */
import {Test, console} from "forge-std/Test.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {
TransparentUpgradeableProxy
} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {
IRewardsCoordinator,
IRewardsCoordinatorTypes
} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
import {AVSDeployer} from "./utils/AVSDeployer.sol";
import {ERC20FixedSupply} from "./utils/ERC20FixedSupply.sol";
import {DataHavenServiceManager} from "../src/DataHavenServiceManager.sol";
import {
IDataHavenServiceManager,
IDataHavenServiceManagerEvents,
IDataHavenServiceManagerErrors
} from "../src/interfaces/IDataHavenServiceManager.sol";
import {IDataHavenServiceManagerEvents} from "../src/interfaces/IDataHavenServiceManager.sol";
contract RewardsSubmitterTest is AVSDeployer {
using SafeERC20 for IERC20;
// Test addresses
address public snowbridgeAgent = address(uint160(uint256(keccak256("snowbridgeAgent"))));
address public operator1 = address(uint160(uint256(keccak256("operator1"))));
@ -46,7 +38,7 @@ contract RewardsSubmitterTest is AVSDeployer {
serviceManager.setRewardsInitiator(snowbridgeAgent);
// Fund the service manager with reward tokens
rewardToken.transfer(address(serviceManager), 100000e18);
IERC20(address(rewardToken)).safeTransfer(address(serviceManager), 100000e18);
}
// Helper function to build a submission
@ -228,7 +220,7 @@ contract RewardsSubmitterTest is AVSDeployer {
// Deploy a different token
ERC20FixedSupply otherToken =
new ERC20FixedSupply("Other", "OTHER", 1000000e18, address(this));
otherToken.transfer(address(serviceManager), 100000e18);
IERC20(address(otherToken)).safeTransfer(address(serviceManager), 100000e18);
// Build submission with different token
IRewardsCoordinatorTypes.StrategyAndMultiplier[] memory strategiesAndMultipliers =

View file

@ -0,0 +1,142 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;
import {AVSDeployer} from "./utils/AVSDeployer.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {
IAllocationManagerErrors,
IAllocationManager,
IAllocationManagerTypes,
IAllocationManagerEvents
} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {DataHavenServiceManager} from "../src/DataHavenServiceManager.sol";
import {
IDataHavenServiceManagerEvents,
IDataHavenServiceManager
} from "../src/interfaces/IDataHavenServiceManager.sol";
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
import "forge-std/Test.sol";
contract SlashingTest is AVSDeployer {
address operator = address(0xabcd);
address public snowbridgeAgent = address(uint160(uint256(keccak256("snowbridgeAgent"))));
function setUp() public virtual {
_deployMockEigenLayerAndAVS();
}
function test_fulfilSlashingRequest() public {
// Allow our operator to register
vm.prank(avsOwner);
serviceManager.addValidatorToAllowlist(operator);
// Configure the rewards initiator (because only the reward agent can submit slashing request)
vm.prank(avsOwner);
serviceManager.setRewardsInitiator(snowbridgeAgent);
vm.prank(operator);
delegationManager.registerAsOperator(address(0), 0, "");
uint32[] memory operatorSetIds = new uint32[](1);
operatorSetIds[0] = serviceManager.VALIDATORS_SET_ID();
IAllocationManagerTypes.RegisterParams memory registerParams =
IAllocationManagerTypes.RegisterParams({
avs: address(serviceManager),
operatorSetIds: operatorSetIds,
data: abi.encodePacked(address(operator))
});
vm.prank(operator);
allocationManager.registerForOperatorSets(operator, registerParams);
DataHavenServiceManager.SlashingRequest[] memory slashings =
new DataHavenServiceManager.SlashingRequest[](1);
uint256[] memory wadsToSlash = new uint256[](3); // 3 wadsToSlash because we have register 3 strategies for the Validator set
wadsToSlash[0] = 1e16;
wadsToSlash[1] = 1e16;
wadsToSlash[2] = 1e16;
OperatorSet memory operatorSet =
OperatorSet({avs: address(serviceManager), id: serviceManager.VALIDATORS_SET_ID()});
IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet);
slashings[0] = IDataHavenServiceManager.SlashingRequest(
operator, strategies, wadsToSlash, "Testing slashing"
);
console.log(block.number);
vm.roll(block.number + uint32(7 days) + 1);
console.log(block.number);
// Because the current magnitude for the allocation is 0
uint256[] memory wadsToSlashed = new uint256[](3);
// We emit the event we expect to see.
vm.prank(snowbridgeAgent);
vm.expectEmit();
emit IAllocationManagerEvents.OperatorSlashed(
operator, operatorSet, strategies, wadsToSlashed, "Testing slashing"
);
vm.expectEmit();
emit IDataHavenServiceManagerEvents.SlashingComplete();
serviceManager.slashValidatorsOperator(slashings);
}
function test_fulfilSlashingRequestForOnlyOneStrategy() public {
// Allow our operator to register
vm.prank(avsOwner);
serviceManager.addValidatorToAllowlist(operator);
// Configure the rewards initiator (because only the reward agent can submit slashing request)
vm.prank(avsOwner);
serviceManager.setRewardsInitiator(snowbridgeAgent);
vm.prank(operator);
delegationManager.registerAsOperator(address(0), 0, "");
uint32[] memory operatorSetIds = new uint32[](1);
operatorSetIds[0] = serviceManager.VALIDATORS_SET_ID();
IAllocationManagerTypes.RegisterParams memory registerParams =
IAllocationManagerTypes.RegisterParams({
avs: address(serviceManager),
operatorSetIds: operatorSetIds,
data: abi.encodePacked(address(operator))
});
vm.prank(operator);
allocationManager.registerForOperatorSets(operator, registerParams);
OperatorSet memory operatorSet =
OperatorSet({avs: address(serviceManager), id: serviceManager.VALIDATORS_SET_ID()});
IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet);
DataHavenServiceManager.SlashingRequest[] memory slashings =
new DataHavenServiceManager.SlashingRequest[](1);
uint256[] memory wadsToSlash = new uint256[](1); // We only want to slash 1 strategy
wadsToSlash[0] = 1e16;
IStrategy[] memory strategiesToSlash = new IStrategy[](1);
strategiesToSlash[0] = strategies[0];
slashings[0] = IDataHavenServiceManager.SlashingRequest(
operator, strategiesToSlash, wadsToSlash, "Testing slashing"
);
console.log(block.number);
vm.roll(block.number + uint32(7 days) + 1);
console.log(block.number);
// Because the current magnitude for the allocation is 0
uint256[] memory wadsToSlashed = new uint256[](1);
// We emit the event we expect to see.
vm.prank(snowbridgeAgent);
vm.expectEmit();
emit IAllocationManagerEvents.OperatorSlashed(
operator, operatorSet, strategiesToSlash, wadsToSlashed, "Testing slashing"
);
vm.expectEmit();
emit IDataHavenServiceManagerEvents.SlashingComplete();
serviceManager.slashValidatorsOperator(slashings);
}
}

View file

@ -8,7 +8,6 @@ import {Payload, Message, MessageKind, Asset} from "snowbridge/src/v2/Types.sol"
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
import {SnowbridgeAndAVSDeployer} from "./utils/SnowbridgeAndAVSDeployer.sol";
import "forge-std/Test.sol";
contract SnowbridgeIntegrationTest is SnowbridgeAndAVSDeployer {
function setUp() public {

View file

@ -3,7 +3,6 @@ pragma solidity ^0.8.27;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol";
import {
IRewardsCoordinator
} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";

View file

@ -0,0 +1,61 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;
import {IGatewayV2} from "snowbridge/src/v2/IGateway.sol";
import {OperatingMode, InboundMessage} from "snowbridge/src/v2/Types.sol";
import {BeefyVerification} from "snowbridge/src/BeefyVerification.sol";
/// @notice Minimal mock of the Snowbridge Gateway for testing purposes
contract SnowbridgeGatewayMock is IGatewayV2 {
function operatingMode() external pure returns (OperatingMode) {
return OperatingMode.Normal;
}
function agentOf(
bytes32
) external pure returns (address) {
return address(0);
}
function v2_submit(
InboundMessage calldata,
bytes32[] calldata,
BeefyVerification.Proof calldata,
bytes32
) external {}
function v2_sendMessage(
bytes calldata,
bytes[] calldata,
bytes calldata,
uint128,
uint128
) external payable {}
function v2_registerToken(
address,
uint8,
uint128,
uint128
) external payable {}
function v2_createAgent(
bytes32
) external {}
function v2_outboundNonce() external pure returns (uint64) {
return 0;
}
function v2_isDispatched(
uint64
) external pure returns (bool) {
return false;
}
function isTokenRegistered(
address
) external pure returns (bool) {
return false;
}
}

View file

@ -1,22 +1,18 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {
TransparentUpgradeableProxy,
ITransparentUpgradeableProxy
} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {PauserRegistry} from "eigenlayer-contracts/src/contracts/permissions/PauserRegistry.sol";
import {
IAllocationManagerTypes
} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol";
import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol";
import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol";
import {RewardsCoordinator} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol";
import {
PermissionController
} from "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol";
import {AllocationManager} from "eigenlayer-contracts/src/contracts/core/AllocationManager.sol";
import {
IRewardsCoordinator,
@ -33,11 +29,14 @@ import {DataHavenServiceManager} from "../../src/DataHavenServiceManager.sol";
// Mocks
import {RewardsCoordinatorMock} from "../mocks/RewardsCoordinatorMock.sol";
import {PermissionControllerMock} from "../mocks/PermissionControllerMock.sol";
import {SnowbridgeGatewayMock} from "../mocks/SnowbridgeGatewayMock.sol";
import {DelegationManager} from "eigenlayer-contracts/src/contracts/core/DelegationManager.sol";
import "forge-std/Test.sol";
import {Test, console, Vm} from "forge-std/Test.sol";
contract AVSDeployer is Test {
using SafeCast for uint256;
Vm public cheats = Vm(VM_ADDRESS);
ProxyAdmin public proxyAdmin;
@ -49,6 +48,7 @@ contract AVSDeployer is Test {
DataHavenServiceManager public serviceManager;
DataHavenServiceManager public serviceManagerImplementation;
// Truncation is intentional - deriving a deterministic mock address from hash
address public vetoCommitteeMember =
address(uint160(uint256(keccak256("vetoCommitteeMember"))));
uint32 public vetoWindowBlocks = 100; // 100 blocks veto window for tests
@ -66,6 +66,7 @@ contract AVSDeployer is Test {
RewardsCoordinator public rewardsCoordinatorImplementation;
RewardsCoordinatorMock public rewardsCoordinatorMock;
PermissionControllerMock public permissionControllerMock;
SnowbridgeGatewayMock public snowbridgeGatewayMock;
// Addresses
address public proxyAdminOwner = address(uint160(uint256(keccak256("proxyAdminOwner"))));
@ -113,6 +114,7 @@ contract AVSDeployer is Test {
eigenPodManagerMock = new EigenPodManagerMock(pauserRegistry);
permissionControllerMock = new PermissionControllerMock();
rewardsCoordinatorMock = new RewardsCoordinatorMock();
snowbridgeGatewayMock = new SnowbridgeGatewayMock();
cheats.stopPrank();
console.log("Mock EigenLayer contracts deployed");
@ -255,11 +257,11 @@ contract AVSDeployer is Test {
address(serviceManagerImplementation),
address(proxyAdmin),
abi.encodeWithSelector(
DataHavenServiceManager.initialise.selector,
DataHavenServiceManager.initialize.selector,
avsOwner,
rewardsInitiator,
validatorsStrategies,
address(0) // This deployment does not use Snowbridge
address(snowbridgeGatewayMock)
)
)
)
@ -380,7 +382,7 @@ contract AVSDeployer is Test {
address start,
uint256 inc
) internal pure returns (address) {
return address(uint160(uint256(uint160(start) + inc)));
return address((uint256(uint160(start)) + inc).toUint160());
}
function _incrementBytes32(

View file

@ -16,10 +16,9 @@ import {TestUtils} from "./TestUtils.sol";
import {
IAllocationManagerTypes
} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {ValidatorsUtils} from "../../script/utils/ValidatorsUtils.sol";
import "forge-std/Test.sol";
import {console} from "forge-std/Test.sol";
contract SnowbridgeAndAVSDeployer is AVSDeployer {
// Snowbridge contracts
@ -58,7 +57,9 @@ contract SnowbridgeAndAVSDeployer is AVSDeployer {
uint256 public constant MIN_NUM_REQUIRED_SIGNATURES = 2;
uint64 public constant START_BLOCK = 1;
bytes32 public constant REWARDS_MESSAGE_ORIGIN = bytes32(0);
bytes32 public constant WRONG_MESSAGE_ORIGIN = bytes32("wrong origin");
// "wrong origin" as bytes32 (hex-encoded, right-padded with zeros)
bytes32 public constant WRONG_MESSAGE_ORIGIN =
0x77726f6e67206f726967696e0000000000000000000000000000000000000000;
function _deployMockAllContracts() internal {
_deployMockSnowbridge();

View file

@ -1,11 +1,15 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
/**
* @title TestUtils
* @notice Utility functions for testing DataHaven contracts
*/
library TestUtils {
using SafeCast for uint256;
/**
* @notice Generates mock validator addresses for testing
* @param count Number of validators to generate
@ -18,7 +22,7 @@ library TestUtils {
) internal pure returns (address[] memory) {
address[] memory validators = new address[](count);
for (uint256 i = 0; i < count; i++) {
validators[i] = address(uint160(uint256(bytes32(startIndex + i + 1))));
validators[i] = address((startIndex + i + 1).toUint160());
}
return validators;
}

320
operator/Cargo.lock generated
View file

@ -114,9 +114,9 @@ dependencies = [
[[package]]
name = "alloy-dyn-abi"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb8e762aefd39a397ff485bc86df673465c4ad3ec8819cc60833a8a3ba5cdc87"
checksum = "cf69d3061e2e908a4370bda5d8d6529d5080232776975489eec0b49ce971027e"
dependencies = [
"alloy-json-abi",
"alloy-primitives",
@ -131,9 +131,9 @@ dependencies = [
[[package]]
name = "alloy-json-abi"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe6beff64ad0aa6ad1019a3db26fef565aefeb011736150ab73ed3366c3cfd1b"
checksum = "4584e3641181ff073e9d5bec5b3b8f78f9749d9fb108a1cfbc4399a4a139c72a"
dependencies = [
"alloy-primitives",
"alloy-sol-type-parser",
@ -143,9 +143,9 @@ dependencies = [
[[package]]
name = "alloy-primitives"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c77490fe91a0ce933a1f219029521f20fc28c2c0ca95d53fa4da9c00b8d9d4e"
checksum = "777d58b30eb9a4db0e5f59bc30e8c2caef877fee7dc8734cf242a51a60f22e05"
dependencies = [
"alloy-rlp",
"bytes",
@ -180,9 +180,9 @@ dependencies = [
[[package]]
name = "alloy-sol-macro"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e10ae8e9a91d328ae954c22542415303919aabe976fe7a92eb06db1b68fd59f2"
checksum = "e68b32b6fa0d09bb74b4cefe35ccc8269d711c26629bc7cd98a47eeb12fe353f"
dependencies = [
"alloy-sol-macro-expander",
"alloy-sol-macro-input",
@ -194,9 +194,9 @@ dependencies = [
[[package]]
name = "alloy-sol-macro-expander"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83ad5da86c127751bc607c174d6c9fe9b85ef0889a9ca0c641735d77d4f98f26"
checksum = "2afe6879ac373e58fd53581636f2cce843998ae0b058ebe1e4f649195e2bd23c"
dependencies = [
"alloy-sol-macro-input",
"const-hex",
@ -212,9 +212,9 @@ dependencies = [
[[package]]
name = "alloy-sol-macro-input"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3d30f0d3f9ba3b7686f3ff1de9ee312647aac705604417a2f40c604f409a9e"
checksum = "c3ba01aee235a8c699d07e5be97ba215607564e71be72f433665329bec307d28"
dependencies = [
"const-hex",
"dunce",
@ -228,9 +228,9 @@ dependencies = [
[[package]]
name = "alloy-sol-type-parser"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c"
checksum = "4c13fc168b97411e04465f03e632f31ef94cad1c7c8951bf799237fd7870d535"
dependencies = [
"serde",
"winnow",
@ -238,9 +238,9 @@ dependencies = [
[[package]]
name = "alloy-sol-types"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d43d5e60466a440230c07761aa67671d4719d46f43be8ea6e7ed334d8db4a9ab"
checksum = "6e960c4b52508ef2ae1e37cae5058e905e9ae099b107900067a503f8c454036f"
dependencies = [
"alloy-json-abi",
"alloy-primitives",
@ -1176,7 +1176,7 @@ dependencies = [
"bitflags 2.9.4",
"cexpr",
"clang-sys",
"itertools 0.13.0",
"itertools 0.11.0",
"proc-macro2",
"quote",
"regex",
@ -1521,7 +1521,7 @@ dependencies = [
"pallet-message-queue",
"parity-scale-codec",
"scale-info",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"sp-core",
"sp-runtime",
"sp-std",
@ -2607,8 +2607,9 @@ dependencies = [
[[package]]
name = "datahaven-mainnet-runtime"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"alloy-core",
"bridge-hub-common 0.13.1",
"datahaven-runtime-common",
"dhp-bridge",
@ -2715,8 +2716,8 @@ dependencies = [
"shp-treasury-funding",
"shp-tx-implicits-runtime-api",
"smallvec",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-core 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"snowbridge-core 0.20.0",
"snowbridge-inbound-queue-primitives",
"snowbridge-merkle-tree",
"snowbridge-outbound-queue-primitives",
@ -2759,7 +2760,7 @@ dependencies = [
[[package]]
name = "datahaven-node"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"async-channel 1.9.0",
"clap",
@ -2870,7 +2871,7 @@ dependencies = [
[[package]]
name = "datahaven-runtime-common"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"alloy-core",
"fp-account",
@ -2882,6 +2883,7 @@ dependencies = [
"pallet-evm",
"pallet-evm-chain-id",
"pallet-evm-precompile-proxy",
"pallet-external-validator-slashes",
"pallet-external-validators-rewards",
"pallet-migrations",
"pallet-safe-mode",
@ -2903,8 +2905,9 @@ dependencies = [
[[package]]
name = "datahaven-stagenet-runtime"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"alloy-core",
"bridge-hub-common 0.13.1",
"datahaven-runtime-common",
"dhp-bridge",
@ -3011,8 +3014,8 @@ dependencies = [
"shp-treasury-funding",
"shp-tx-implicits-runtime-api",
"smallvec",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-core 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"snowbridge-core 0.20.0",
"snowbridge-inbound-queue-primitives",
"snowbridge-merkle-tree",
"snowbridge-outbound-queue-primitives",
@ -3055,8 +3058,9 @@ dependencies = [
[[package]]
name = "datahaven-testnet-runtime"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"alloy-core",
"bridge-hub-common 0.13.1",
"datahaven-runtime-common",
"dhp-bridge",
@ -3163,8 +3167,8 @@ dependencies = [
"shp-treasury-funding",
"shp-tx-implicits-runtime-api",
"smallvec",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-core 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"snowbridge-core 0.20.0",
"snowbridge-inbound-queue-primitives",
"snowbridge-merkle-tree",
"snowbridge-outbound-queue-primitives",
@ -3356,7 +3360,7 @@ dependencies = [
[[package]]
name = "dhp-bridge"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-support",
"frame-system",
@ -3364,7 +3368,7 @@ dependencies = [
"pallet-datahaven-native-transfer",
"pallet-external-validators",
"parity-scale-codec",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"snowbridge-inbound-queue-primitives",
"sp-core",
"sp-std",
@ -3854,7 +3858,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@ -8249,7 +8253,7 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
dependencies = [
"proc-macro-crate 3.4.0",
"proc-macro-crate 1.1.3",
"proc-macro2",
"quote",
"syn 2.0.106",
@ -8614,8 +8618,8 @@ dependencies = [
[[package]]
name = "pallet-bucket-nfts"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -8671,8 +8675,8 @@ dependencies = [
[[package]]
name = "pallet-cr-randomness"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-support",
"frame-system",
@ -8691,7 +8695,7 @@ dependencies = [
[[package]]
name = "pallet-datahaven-native-transfer"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -8699,7 +8703,7 @@ dependencies = [
"pallet-balances",
"parity-scale-codec",
"scale-info",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"snowbridge-outbound-queue-primitives",
"sp-core",
"sp-io",
@ -8803,7 +8807,7 @@ dependencies = [
[[package]]
name = "pallet-evm-precompile-balances-erc20"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"fp-evm",
"frame-support",
@ -8826,7 +8830,7 @@ dependencies = [
[[package]]
name = "pallet-evm-precompile-batch"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"evm",
"fp-evm",
@ -8865,7 +8869,7 @@ dependencies = [
[[package]]
name = "pallet-evm-precompile-call-permit"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"evm",
"fp-evm",
@ -8931,7 +8935,7 @@ dependencies = [
[[package]]
name = "pallet-evm-precompile-datahaven-native-transfer"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"evm",
"fp-evm",
@ -8945,7 +8949,7 @@ dependencies = [
"parity-scale-codec",
"precompile-utils",
"scale-info",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"snowbridge-outbound-queue-primitives",
"sp-core",
"sp-io",
@ -8955,8 +8959,8 @@ dependencies = [
[[package]]
name = "pallet-evm-precompile-file-system"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"fp-account",
"fp-evm",
@ -9024,7 +9028,7 @@ dependencies = [
[[package]]
name = "pallet-evm-precompile-proxy"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"evm",
"fp-evm",
@ -9068,7 +9072,7 @@ dependencies = [
[[package]]
name = "pallet-evm-precompile-registry"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"fp-evm",
"frame-support",
@ -9119,7 +9123,7 @@ dependencies = [
"parity-scale-codec",
"scale-info",
"serde",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"snowbridge-outbound-queue-primitives",
"sp-core",
"sp-io",
@ -9129,7 +9133,7 @@ dependencies = [
[[package]]
name = "pallet-external-validators"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -9153,7 +9157,7 @@ dependencies = [
[[package]]
name = "pallet-external-validators-rewards"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -9166,7 +9170,7 @@ dependencies = [
"pallet-timestamp",
"parity-scale-codec",
"scale-info",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"snowbridge-outbound-queue-primitives",
"sp-core",
"sp-io",
@ -9195,8 +9199,8 @@ dependencies = [
[[package]]
name = "pallet-file-system"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -9222,8 +9226,8 @@ dependencies = [
[[package]]
name = "pallet-file-system-runtime-api"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"parity-scale-codec",
"scale-info",
@ -9390,7 +9394,7 @@ dependencies = [
[[package]]
name = "pallet-outbound-commitment-store"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-support",
"frame-system",
@ -9418,8 +9422,8 @@ dependencies = [
[[package]]
name = "pallet-payment-streams"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -9438,8 +9442,8 @@ dependencies = [
[[package]]
name = "pallet-payment-streams-runtime-api"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"parity-scale-codec",
"scale-info",
@ -9466,8 +9470,8 @@ dependencies = [
[[package]]
name = "pallet-proofs-dealer"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -9488,8 +9492,8 @@ dependencies = [
[[package]]
name = "pallet-proofs-dealer-runtime-api"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"parity-scale-codec",
"scale-info",
@ -9510,8 +9514,8 @@ dependencies = [
[[package]]
name = "pallet-randomness"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -9651,8 +9655,8 @@ dependencies = [
[[package]]
name = "pallet-storage-providers"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -9673,8 +9677,8 @@ dependencies = [
[[package]]
name = "pallet-storage-providers-runtime-api"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"parity-scale-codec",
"scale-info",
@ -11077,7 +11081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4"
dependencies = [
"bytes",
"heck 0.5.0",
"heck 0.4.1",
"itertools 0.12.1",
"log",
"multimap",
@ -11097,7 +11101,7 @@ version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
dependencies = [
"heck 0.5.0",
"heck 0.4.1",
"itertools 0.14.0",
"log",
"multimap",
@ -11891,7 +11895,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.11.0",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@ -13836,8 +13840,8 @@ dependencies = [
[[package]]
name = "shc-actors-derive"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"once_cell",
"proc-macro2",
@ -13849,8 +13853,8 @@ dependencies = [
[[package]]
name = "shc-actors-framework"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"anyhow",
"bincode",
@ -13868,8 +13872,8 @@ dependencies = [
[[package]]
name = "shc-blockchain-service"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"anyhow",
"array-bytes",
@ -13924,8 +13928,8 @@ dependencies = [
[[package]]
name = "shc-blockchain-service-db"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"chrono",
"diesel",
@ -13948,8 +13952,8 @@ dependencies = [
[[package]]
name = "shc-client"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"anyhow",
"array-bytes",
@ -14022,8 +14026,8 @@ dependencies = [
[[package]]
name = "shc-common"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"anyhow",
"bigdecimal",
@ -14086,8 +14090,8 @@ dependencies = [
[[package]]
name = "shc-file-manager"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"bincode",
"hash-db",
@ -14110,8 +14114,8 @@ dependencies = [
[[package]]
name = "shc-file-transfer-service"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"anyhow",
"array-bytes",
@ -14139,8 +14143,8 @@ dependencies = [
[[package]]
name = "shc-fisherman-service"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"async-trait",
"diesel",
@ -14170,8 +14174,8 @@ dependencies = [
[[package]]
name = "shc-forest-manager"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"anyhow",
"async-trait",
@ -14196,8 +14200,8 @@ dependencies = [
[[package]]
name = "shc-indexer-db"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"bigdecimal",
"chrono",
@ -14224,8 +14228,8 @@ dependencies = [
[[package]]
name = "shc-indexer-service"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"anyhow",
"array-bytes",
@ -14275,8 +14279,8 @@ dependencies = [
[[package]]
name = "shc-rpc"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"array-bytes",
"async-trait",
@ -14321,8 +14325,8 @@ dependencies = [
[[package]]
name = "shc-telemetry"
version = "0.1.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"log",
"substrate-prometheus-endpoint",
@ -14338,8 +14342,8 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "shp-constants"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"sp-core",
"sp-runtime",
@ -14347,8 +14351,8 @@ dependencies = [
[[package]]
name = "shp-data-price-updater"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-support",
"parity-scale-codec",
@ -14362,8 +14366,8 @@ dependencies = [
[[package]]
name = "shp-file-key-verifier"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-support",
"parity-scale-codec",
@ -14380,8 +14384,8 @@ dependencies = [
[[package]]
name = "shp-file-metadata"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"hex",
"num-bigint",
@ -14396,8 +14400,8 @@ dependencies = [
[[package]]
name = "shp-forest-verifier"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-support",
"parity-scale-codec",
@ -14413,16 +14417,16 @@ dependencies = [
[[package]]
name = "shp-opaque"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"sp-runtime",
]
[[package]]
name = "shp-session-keys"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"async-trait",
"parity-scale-codec",
@ -14436,8 +14440,8 @@ dependencies = [
[[package]]
name = "shp-traits"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"frame-support",
"parity-scale-codec",
@ -14450,8 +14454,8 @@ dependencies = [
[[package]]
name = "shp-treasury-funding"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"log",
"shp-traits",
@ -14461,8 +14465,8 @@ dependencies = [
[[package]]
name = "shp-tx-implicits-runtime-api"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"parity-scale-codec",
"scale-info",
@ -14474,8 +14478,8 @@ dependencies = [
[[package]]
name = "shp-types"
version = "0.3.0"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.1#e135f65ad54d5c500259d0f6d3b6c34ea66dc2a4"
version = "0.3.3"
source = "git+https://github.com/Moonsong-Labs/storage-hub.git?tag=v0.3.3#57d2a195d58d39e0d6e38a927ec312dd0f640522"
dependencies = [
"sp-core",
"sp-runtime",
@ -14755,7 +14759,7 @@ dependencies = [
[[package]]
name = "snowbridge-beacon-primitives"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"byte-slice-cast",
"frame-support",
@ -14800,7 +14804,7 @@ dependencies = [
[[package]]
name = "snowbridge-core"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"bp-relayers",
"ethabi-decode",
@ -14877,8 +14881,8 @@ dependencies = [
"log",
"parity-scale-codec",
"scale-info",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-core 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"snowbridge-core 0.20.0",
"snowbridge-verification-primitives",
"sp-core",
"sp-io",
@ -14891,7 +14895,7 @@ dependencies = [
[[package]]
name = "snowbridge-merkle-tree"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"array-bytes",
"hex",
@ -14932,7 +14936,7 @@ dependencies = [
[[package]]
name = "snowbridge-outbound-queue-primitives"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"alloy-core",
"ethabi-decode",
@ -14944,7 +14948,7 @@ dependencies = [
"parity-scale-codec",
"polkadot-parachain-primitives",
"scale-info",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"snowbridge-verification-primitives",
"sp-arithmetic",
"sp-core",
@ -14958,12 +14962,12 @@ dependencies = [
[[package]]
name = "snowbridge-outbound-queue-v2-runtime-api"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-support",
"parity-scale-codec",
"scale-info",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"snowbridge-merkle-tree",
"snowbridge-outbound-queue-primitives",
"sp-api",
@ -14973,7 +14977,7 @@ dependencies = [
[[package]]
name = "snowbridge-pallet-ethereum-client"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -14986,8 +14990,8 @@ dependencies = [
"scale-info",
"serde",
"serde_json",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-core 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"snowbridge-core 0.20.0",
"snowbridge-ethereum 0.3.0",
"snowbridge-inbound-queue-primitives",
"snowbridge-pallet-ethereum-client-fixtures",
@ -15003,8 +15007,8 @@ name = "snowbridge-pallet-ethereum-client-fixtures"
version = "0.9.0"
dependencies = [
"hex-literal 0.3.4",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-core 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"snowbridge-core 0.20.0",
"snowbridge-inbound-queue-primitives",
"sp-core",
"sp-std",
@ -15012,7 +15016,7 @@ dependencies = [
[[package]]
name = "snowbridge-pallet-inbound-queue-v2"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"alloy-core",
"bp-relayers",
@ -15026,8 +15030,8 @@ dependencies = [
"parity-scale-codec",
"scale-info",
"serde",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-core 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"snowbridge-core 0.20.0",
"snowbridge-inbound-queue-primitives",
"snowbridge-pallet-ethereum-client",
"snowbridge-pallet-inbound-queue-v2-fixtures",
@ -15048,8 +15052,8 @@ name = "snowbridge-pallet-inbound-queue-v2-fixtures"
version = "0.10.0"
dependencies = [
"hex-literal 0.3.4",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-core 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"snowbridge-core 0.20.0",
"snowbridge-inbound-queue-primitives",
"sp-core",
"sp-std",
@ -15079,7 +15083,7 @@ dependencies = [
[[package]]
name = "snowbridge-pallet-outbound-queue-v2"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"alloy-core",
"bp-relayers",
@ -15093,8 +15097,8 @@ dependencies = [
"parity-scale-codec",
"scale-info",
"serde",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-core 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"snowbridge-core 0.20.0",
"snowbridge-inbound-queue-primitives",
"snowbridge-merkle-tree",
"snowbridge-outbound-queue-primitives",
@ -15125,7 +15129,7 @@ dependencies = [
"parity-scale-codec",
"polkadot-primitives",
"scale-info",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"snowbridge-outbound-queue-primitives",
"snowbridge-pallet-outbound-queue",
"sp-core",
@ -15138,7 +15142,7 @@ dependencies = [
[[package]]
name = "snowbridge-pallet-system-v2"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -15150,7 +15154,7 @@ dependencies = [
"parity-scale-codec",
"polkadot-primitives",
"scale-info",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"snowbridge-outbound-queue-primitives",
"snowbridge-pallet-outbound-queue-v2",
"snowbridge-pallet-system",
@ -15166,10 +15170,10 @@ dependencies = [
[[package]]
name = "snowbridge-system-v2-runtime-api"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"parity-scale-codec",
"snowbridge-core 0.13.0",
"snowbridge-core 0.20.0",
"sp-api",
"sp-std",
"staging-xcm",
@ -15177,7 +15181,7 @@ dependencies = [
[[package]]
name = "snowbridge-test-utils"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-benchmarking",
"frame-support",
@ -15197,12 +15201,12 @@ dependencies = [
[[package]]
name = "snowbridge-verification-primitives"
version = "0.13.0"
version = "0.20.0"
dependencies = [
"frame-support",
"parity-scale-codec",
"scale-info",
"snowbridge-beacon-primitives 0.13.0",
"snowbridge-beacon-primitives 0.20.0",
"sp-core",
"sp-std",
]
@ -16672,9 +16676,9 @@ dependencies = [
[[package]]
name = "syn-solidity"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4560533fbd6914b94a8fb5cc803ed6801c3455668db3b810702c57612bac9412"
checksum = "ab4e6eed052a117409a1a744c8bda9c3ea6934597cf7419f791cb7d590871c4c"
dependencies = [
"paste",
"proc-macro2",
@ -16783,7 +16787,7 @@ dependencies = [
"getrandom 0.3.3",
"once_cell",
"rustix 1.1.2",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@ -18389,7 +18393,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.48.0",
]
[[package]]

View file

@ -5,7 +5,7 @@ edition = "2021"
homepage = "https://datahaven.xyz/"
license = "GPL-3"
repository = "https://github.com/datahavenxyz/datahaven"
version = "0.13.0"
version = "0.20.0"
[workspace]
members = [
@ -265,42 +265,42 @@ fc-storage = { git = "https://github.com/polkadot-evm/frontier", branch = "stabl
# StorageHub
## Runtime
pallet-bucket-nfts = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-cr-randomness = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-file-system = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-file-system-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-payment-streams = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-payment-streams-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-proofs-dealer = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-proofs-dealer-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-randomness = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-storage-providers = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-storage-providers-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-constants = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-data-price-updater = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-file-key-verifier = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-file-metadata = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-forest-verifier = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-traits = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-treasury-funding = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-bucket-nfts = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-cr-randomness = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-file-system = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-file-system-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-payment-streams = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-payment-streams-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-proofs-dealer = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-proofs-dealer-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-randomness = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-storage-providers = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
pallet-storage-providers-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-constants = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-data-price-updater = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-file-key-verifier = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-file-metadata = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-forest-verifier = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-traits = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-treasury-funding = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
## Client
shc-actors-derive = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-actors-framework = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-blockchain-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-client = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-common = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-file-manager = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-file-transfer-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-fisherman-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-forest-manager = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-indexer-db = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-indexer-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-rpc = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-opaque = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-tx-implicits-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shp-types = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
shc-actors-derive = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-actors-framework = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-blockchain-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-client = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-common = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-file-manager = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-file-transfer-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-fisherman-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-forest-manager = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-indexer-db = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-indexer-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shc-rpc = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-opaque = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-tx-implicits-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
shp-types = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
## Precompiles
pallet-evm-precompile-file-system = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.1", default-features = false }
pallet-evm-precompile-file-system = { git = "https://github.com/Moonsong-Labs/storage-hub.git", tag = "v0.3.3", default-features = false }
# Static linking

View file

@ -74,7 +74,7 @@ mod benchmarks {
let era = T::EraIndexProvider::active_era().index;
let dummy = || T::AccountId::decode(&mut TrailingZeroInput::zeroes()).unwrap();
#[extrinsic_call]
_(RawOrigin::Root, era, dummy(), Perbill::from_percent(50), 1);
_(RawOrigin::Root, era, dummy(), Perbill::from_percent(50));
assert_eq!(
Slashes::<T>::get(
@ -102,7 +102,7 @@ mod benchmarks {
#[block]
{
processed = Pallet::<T>::process_slashes_queue(s);
processed = Pallet::<T>::process_slashes_queue(s).unwrap();
}
assert_eq!(UnreportedSlashesQueue::<T>::get().len(), 1);

View file

@ -66,19 +66,15 @@ pub mod weights;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct SlashData<AccountId> {
pub validator: AccountId,
pub amount_to_slash: u128,
pub wad_to_slash: u128,
}
/// TODO: populate this with what we need
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct SlashDataUtils<AccountId>(pub Vec<SlashData<AccountId>>);
// FIXME (nice to have): Merge with SendMessage trait from pallet external-validator-reward (similar trait)
pub trait SendMessage<AccountId> {
type Message;
type Ticket;
fn build(utils: &SlashDataUtils<AccountId>) -> Option<Self::Message>;
fn build(utils: &Vec<SlashData<AccountId>>, era: u32) -> Option<Self::Message>;
fn validate(message: Self::Message) -> Result<Self::Ticket, SendError>;
@ -101,6 +97,10 @@ pub mod pallet {
},
/// The slashes message was sent correctly.
SlashesMessageSent { message_id: H256 },
/// We injected a slash
SlashInjected { slash_id: T::SlashId, era: u32 },
/// Number of slashes processed
SlashAddedToQueue { number: u32, era: u32 },
}
#[pallet::config]
@ -305,7 +305,6 @@ pub mod pallet {
era: EraIndex,
validator: T::AccountId,
percentage: Perbill,
external_idx: u64,
) -> DispatchResult {
ensure_root(origin)?;
let active_era = T::EraIndexProvider::active_era().index;
@ -325,7 +324,6 @@ pub mod pallet {
era,
validator,
slash_defer_duration,
external_idx,
)
.ok_or(Error::<T>::ErrorComputingSlash)?;
@ -342,6 +340,12 @@ pub mod pallet {
});
NextSlashId::<T>::put(next_slash_id.saturating_add(One::one()));
Self::deposit_event(Event::<T>::SlashInjected {
slash_id: next_slash_id,
era: era_to_consider,
});
Ok(())
}
@ -360,7 +364,12 @@ pub mod pallet {
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
let processed = Self::process_slashes_queue(T::QueuedSlashesProcessedPerBlock::get());
T::WeightInfo::process_slashes_queue(processed)
if let Some(p) = processed {
T::WeightInfo::process_slashes_queue(p)
} else {
T::WeightInfo::process_slashes_queue(0)
}
}
}
}
@ -412,10 +421,10 @@ where
// Fast path for active-era report - most likely.
// `slash_session` cannot be in a future active era. It must be in `active_era` or before.
let (slash_era, external_idx) = if slash_session >= active_era_start_session_index {
// Account for get_external_index read.
let slash_era = if slash_session >= active_era_start_session_index {
add_db_reads_writes(1, 0);
(active_era, T::ExternalIndexProvider::get_external_index())
active_era
} else {
let eras = BondedEras::<T>::get();
add_db_reads_writes(1, 0);
@ -426,7 +435,7 @@ where
.rev()
.find(|&(_, sesh, _)| sesh <= &slash_session)
{
Some((slash_era, _, external_idx)) => (*slash_era, *external_idx),
Some((slash_era, _, _external_idx)) => *slash_era,
// Before bonding period. defensive - should be filtered out.
None => return consumed_weight,
}
@ -468,7 +477,6 @@ where
slash_era,
stash.clone(),
slash_defer_duration,
external_idx,
);
if let Some(mut slash) = slash {
@ -562,13 +570,22 @@ impl<T: Config> Pallet<T> {
fn add_era_slashes_to_queue(active_era: EraIndex) {
let mut slashes: VecDeque<_> = Slashes::<T>::get(active_era).into();
let len = slashes.len();
UnreportedSlashesQueue::<T>::mutate(|queue| queue.append(&mut slashes));
if len > 0 {
Self::deposit_event(Event::<T>::SlashAddedToQueue {
number: len as u32,
era: active_era,
});
}
}
/// Returns number of slashes that were sent to ethereum.
fn process_slashes_queue(amount: u32) -> u32 {
fn process_slashes_queue(amount: u32) -> Option<u32> {
let mut slashes_to_send: Vec<SlashData<T::AccountId>> = vec![];
let _era_index = T::EraIndexProvider::active_era().index;
let era_index = T::EraIndexProvider::active_era().index;
UnreportedSlashesQueue::<T>::mutate(|queue| {
for _ in 0..amount {
@ -579,22 +596,22 @@ impl<T: Config> Pallet<T> {
slashes_to_send.push(SlashData {
validator: slash.validator,
amount_to_slash: 0, // TODO: need to compute how much we slash
wad_to_slash: u128::from_str_radix("10000000000000000", 10).unwrap(), // TODO: need to compute how much we slash (for now it is 1e16)
});
}
});
if slashes_to_send.is_empty() {
return 0;
return None;
}
let slashes_count = slashes_to_send.len() as u32;
let outbound = match T::SendMessage::build(&SlashDataUtils(slashes_to_send)) {
let outbound = match T::SendMessage::build(&slashes_to_send, era_index) {
Some(send_msg) => send_msg,
None => {
log::error!(target: "ext_validators_rewards", "Failed to build outbound message");
return 0;
log::error!(target: "ext_validators_slashes", "Failed to build outbound message");
return None;
}
};
@ -602,28 +619,26 @@ impl<T: Config> Pallet<T> {
let ticket = T::SendMessage::validate(outbound)
.map_err(|e| {
log::error!(
target: "ext_validators_rewards",
target: "ext_validators_slashes",
"Failed to validate outbound message: {:?}",
e
);
return 0;
})
.unwrap();
.ok()?;
let message_id = T::SendMessage::deliver(ticket)
.map_err(|e| {
log::error!(
target: "ext_validators_rewards",
target: "ext_validators_slashes",
"Failed to deliver outbound message: {:?}",
e
);
return 0;
})
.unwrap();
.ok()?;
Self::deposit_event(Event::<T>::SlashesMessageSent { message_id });
slashes_count
Some(slashes_count)
}
}
@ -631,8 +646,6 @@ impl<T: Config> Pallet<T> {
/// rather deferred for several eras.
#[derive(Encode, Decode, RuntimeDebug, TypeInfo, Clone, PartialEq)]
pub struct Slash<AccountId, SlashId> {
/// external index identifying a given set of validators
pub external_idx: u64,
/// The stash ID of the offending validator.
pub validator: AccountId,
/// Reporters of the offence; bounty payout recipients.
@ -648,7 +661,6 @@ impl<AccountId, SlashId: One> Slash<AccountId, SlashId> {
/// Initializes the default object using the given `validator`.
pub fn default_from(validator: AccountId) -> Self {
Self {
external_idx: 0,
validator,
reporters: vec![],
slash_id: One::one(),
@ -670,7 +682,6 @@ pub(crate) fn compute_slash<T: Config>(
slash_era: EraIndex,
stash: T::AccountId,
slash_defer_duration: EraIndex,
external_idx: u64,
) -> Option<Slash<T::AccountId, T::SlashId>> {
let prior_slash_p = ValidatorSlashInEra::<T>::get(slash_era, &stash).unwrap_or(Zero::zero());
@ -691,7 +702,6 @@ pub(crate) fn compute_slash<T: Config>(
let confirmed = slash_defer_duration.is_zero();
Some(Slash {
external_idx,
validator: stash.clone(),
percentage: slash_fraction,
slash_id,

View file

@ -218,7 +218,7 @@ pub struct MockOkOutboundQueue;
impl crate::SendMessage<AccountId> for MockOkOutboundQueue {
type Ticket = ();
type Message = ();
fn build(_: &crate::SlashDataUtils<AccountId>) -> Option<Self::Ticket> {
fn build(_: &Vec<crate::SlashData<AccountId>>, _: u32) -> Option<Self::Ticket> {
Some(())
}
fn validate(_: Self::Ticket) -> Result<Self::Ticket, SendError> {

View file

@ -35,12 +35,10 @@ fn root_can_inject_manual_offence() {
0,
1u64,
Perbill::from_percent(75),
1
));
assert_eq!(
Slashes::<Test>::get(get_slashing_era(0)),
vec![Slash {
external_idx: 1,
validator: 1,
percentage: Perbill::from_percent(75),
confirmed: false,
@ -61,8 +59,7 @@ fn cannot_inject_future_era_offence() {
RuntimeOrigin::root(),
1,
1u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
),
Error::<Test>::ProvidedFutureEra
);
@ -79,8 +76,7 @@ fn cannot_inject_era_offence_too_far_in_the_past() {
RuntimeOrigin::root(),
1,
4u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
),
Error::<Test>::ProvidedNonSlashableEra
);
@ -95,8 +91,7 @@ fn root_can_cancel_deferred_slash() {
RuntimeOrigin::root(),
0,
1u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
));
assert_ok!(ExternalValidatorSlashes::cancel_deferred_slash(
RuntimeOrigin::root(),
@ -116,8 +111,7 @@ fn root_cannot_cancel_deferred_slash_if_outside_deferring_period() {
RuntimeOrigin::root(),
0,
1u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
));
start_era(4, 0, 4);
@ -137,8 +131,7 @@ fn root_cannot_cancel_out_of_bounds() {
RuntimeOrigin::root(),
0,
1u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
));
assert_noop!(
ExternalValidatorSlashes::cancel_deferred_slash(
@ -159,8 +152,7 @@ fn root_cannot_cancel_duplicates() {
RuntimeOrigin::root(),
0,
1u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
));
assert_noop!(
ExternalValidatorSlashes::cancel_deferred_slash(RuntimeOrigin::root(), 3, vec![0, 0]),
@ -177,15 +169,13 @@ fn root_cannot_cancel_if_not_sorted() {
RuntimeOrigin::root(),
0,
1u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
));
assert_ok!(ExternalValidatorSlashes::force_inject_slash(
RuntimeOrigin::root(),
0,
2u64,
Perbill::from_percent(75),
2
Perbill::from_percent(75)
));
assert_noop!(
ExternalValidatorSlashes::cancel_deferred_slash(RuntimeOrigin::root(), 3, vec![1, 0]),
@ -206,14 +196,12 @@ fn test_after_bonding_period_we_can_remove_slashes() {
RuntimeOrigin::root(),
0,
1u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
));
assert_eq!(
Slashes::<Test>::get(get_slashing_era(0)),
vec![Slash {
external_idx: 1,
validator: 1,
percentage: Perbill::from_percent(75),
confirmed: false,
@ -250,7 +238,6 @@ fn test_on_offence_injects_offences() {
assert_eq!(
Slashes::<Test>::get(get_slashing_era(0)),
vec![Slash {
external_idx: 0,
validator: 3,
percentage: Perbill::from_percent(75),
confirmed: false,
@ -316,13 +303,11 @@ fn defer_period_of_zero_confirms_immediately_slashes() {
RuntimeOrigin::root(),
0,
1u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
));
assert_eq!(
Slashes::<Test>::get(get_slashing_era(0)),
vec![Slash {
external_idx: 1,
validator: 1,
percentage: Perbill::from_percent(75),
confirmed: true,
@ -342,8 +327,7 @@ fn we_cannot_cancel_anything_with_defer_period_zero() {
RuntimeOrigin::root(),
0,
1u64,
Perbill::from_percent(75),
1
Perbill::from_percent(75)
));
assert_noop!(
ExternalValidatorSlashes::cancel_deferred_slash(RuntimeOrigin::root(), 0, vec![0]),
@ -371,7 +355,6 @@ fn test_on_offence_defer_period_0() {
assert_eq!(
Slashes::<Test>::get(get_slashing_era(1)),
vec![Slash {
external_idx: 0,
validator: 3,
percentage: Perbill::from_percent(75),
confirmed: true,
@ -404,7 +387,6 @@ fn test_slashes_command_matches_event() {
assert_eq!(
Slashes::<Test>::get(get_slashing_era(1)),
vec![Slash {
external_idx: 0,
validator: 3,
percentage: Perbill::from_percent(75),
confirmed: true,
@ -463,7 +445,6 @@ fn test_account_id_encoding() {
let alice_account: [u8; 32] = [4u8; 32];
let slash = Slash::<AccountId20, u32> {
external_idx: 0,
validator: AccountId20::from(alice_account),
reporters: vec![],
slash_id: 1,

View file

@ -499,7 +499,9 @@ pub mod pallet {
base_weight.deconstruct() * 100 / Perbill::ACCURACY
);
// Calculate and award points for each validator
let mut rewards = Vec::new();
// Calculate points for each validator
for validator in validators.iter() {
// Skip whitelisted validators - they don't participate in performance rewards
if whitelisted_validators.contains(validator) {
@ -596,10 +598,14 @@ pub mod pallet {
points
);
Self::reward_by_ids([(validator.clone(), points)].into_iter());
rewards.push((validator.clone(), points));
}
}
if !rewards.is_empty() {
Self::reward_by_ids(rewards.into_iter());
}
// Clear session tracking storage
let _ = BlocksAuthoredInSession::<T>::clear(u32::MAX, None);
}

View file

@ -446,6 +446,9 @@ where
let account_amount: U256 = {
let owner: Runtime::AccountId =
Runtime::AddressMapping::into_account_id(handle.context().caller);
// frame_system::Account:
// Blake2128(16) + AccountId(20) + AccountInfo ((4 * 4) + AccountData(16 * 4))
handle.record_db_read::<Runtime>(116)?;
pallet_balances::Pallet::<Runtime, Instance>::usable_balance(&owner).into()
};

View file

@ -16,6 +16,7 @@ pallet-authorship = { workspace = true }
pallet-balances = { workspace = true }
pallet-external-validators-rewards = { workspace = true }
pallet-timestamp = { workspace = true }
pallet-external-validator-slashes = { workspace = true }
pallet-evm = { workspace = true }
pallet-evm-chain-id = { workspace = true }
pallet-evm-precompile-proxy = { workspace = true }

View file

@ -28,6 +28,7 @@ pub use migrations::*;
pub mod rewards_adapter;
pub mod safe_mode;
pub use safe_mode::*;
pub mod slashes_adapter;
use fp_account::EthereumSignature;
pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;

View file

@ -0,0 +1,125 @@
use alloy_core::{
primitives::{Address, U256},
sol,
sol_types::SolCall,
};
use pallet_external_validator_slashes::SlashData;
use snowbridge_outbound_queue_primitives::v2::SendMessage;
use snowbridge_outbound_queue_primitives::v2::{Command, Message as OutboundMessage};
use snowbridge_outbound_queue_primitives::SendError;
use sp_core::{H160, H256};
use sp_std::vec;
use sp_std::vec::Vec;
use crate::AccountId;
sol! {
// Slashing request to be send to the DatahavenServiceManager
struct SlashingRequest {
address operator;
address[] strategies;
uint256[] wadsToSlash;
string description;
}
// function to call in the DatahavenServiceManager to process all the slashing requests (batching)
function slashValidatorsOperator(SlashingRequest[] calldata slashings) external;
}
/// Gas limit for the submitRewards call on Ethereum.
pub const SLASH_VALIDATORS_GAS_LIMIT: u64 = 1_000_000;
/// Configuration for slashes submission.
///
/// Runtimes implement this trait to provide environment-specific values
/// such as contract address and the slash agent origin.
pub trait SlashesSubmissionConfig {
type OutboundQueue: snowbridge_outbound_queue_primitives::v2::SendMessage<
Ticket = OutboundMessage,
>;
/// Get the DataHaven ServiceManager contract address on Ethereum.
fn service_manager_address() -> H160;
/// Get the agent origin for outbound messages.
fn slashes_agent_origin() -> H256;
/// Get the strategies to slash.
fn strategies() -> Vec<Address>;
}
/// Generic slashes submission adapter.
///
/// This adapter implements [`SendMessage`] and uses the configuration provided
/// by [`SlashesSubmissionConfig`] to build, validate, and deliver slashes
/// messages to EigenLayer via Snowbridge.
pub struct SlashesSubmissionAdapter<C>(core::marker::PhantomData<C>);
impl<C: SlashesSubmissionConfig> pallet_external_validator_slashes::SendMessage<AccountId>
for SlashesSubmissionAdapter<C>
{
type Message = OutboundMessage;
type Ticket = OutboundMessage;
fn build(slashes_utils: &Vec<SlashData<AccountId>>, era: u32) -> Option<Self::Message> {
let strategies = C::strategies();
let calldata = encode_slashing_request(slashes_utils, strategies);
let command = Command::CallContract {
target: C::service_manager_address(),
calldata,
gas: SLASH_VALIDATORS_GAS_LIMIT,
value: 0,
};
let message = OutboundMessage {
origin: C::slashes_agent_origin(),
id: H256::from_low_u64_be(era as u64).into(),
fee: 0,
commands: match vec![command].try_into() {
Ok(cmds) => cmds,
Err(_) => {
log::error!(
target: "slashes_send_adapter",
"Failed to convert commands: too many commands"
);
return None;
}
},
};
Some(message)
}
fn validate(message: Self::Message) -> Result<Self::Ticket, SendError> {
C::OutboundQueue::validate(&message)
}
fn deliver(message: Self::Ticket) -> Result<H256, SendError> {
C::OutboundQueue::deliver(message)
}
}
fn encode_slashing_request(
slashes_utils: &Vec<SlashData<AccountId>>,
strategies: Vec<Address>,
) -> Vec<u8> {
let mut slashings: Vec<SlashingRequest> = vec![];
let strategies_len = strategies.len();
// Extend with operator address to slash
for slash_operator in slashes_utils {
// slashing all the strategies
let wads_to_slash = vec![U256::from(slash_operator.wad_to_slash); strategies_len];
let slashing_request = SlashingRequest {
operator: Address::from(slash_operator.validator.0),
strategies: strategies.clone(),
wadsToSlash: wads_to_slash, // We only have one strategy deployed
description: "Slashing validator".into(),
};
slashings.push(slashing_request);
}
// Use the `slashValidatorsOperator` function defined in the sol! macro to build the Ethereum call and encoded it correctly
let calldata = slashValidatorsOperatorCall { slashings }.abi_encode();
return calldata;
}

View file

@ -13,6 +13,7 @@ version = { workspace = true }
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
alloy-core = { workspace = true, features = ["sol-types"] }
bridge-hub-common = { workspace = true, optional = true }
codec = { workspace = true, features = ["derive"] }
datahaven-runtime-common = { workspace = true }

View file

@ -30,6 +30,7 @@ use super::{
Signature, System, Timestamp, Treasury, TxPause, BLOCK_HASH_COUNT, EXTRINSIC_BASE_WEIGHT,
MAXIMUM_BLOCK_WEIGHT, NORMAL_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, VERSION,
};
use alloy_core::primitives::Address;
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{traits::AccountIdConversion, RuntimeDebug};
@ -103,7 +104,7 @@ use frame_support::{
weights::{constants::RocksDbWeight, IdentityFee, RuntimeDbWeight, Weight},
PalletId,
};
use frame_system::{limits::BlockLength, unique, EnsureRoot, EnsureRootWithSuccess};
use frame_system::{limits::BlockLength, EnsureRoot, EnsureRootWithSuccess};
use governance::councils::*;
use pallet_ethereum::PostLogContent;
use pallet_evm::{
@ -123,7 +124,7 @@ use snowbridge_core::{gwei, meth, AgentIdOf, PricingParameters, Rewards, TokenId
use snowbridge_inbound_queue_primitives::RewardLedger;
use snowbridge_outbound_queue_primitives::{
v1::{Fee, Message, SendMessage},
v2::{Command, ConstantGasMeter, Message as OutboundMessage, SendMessage as SendMessageV2},
v2::{Command, ConstantGasMeter},
SendError, SendMessageFeeProvider,
};
use snowbridge_pallet_outbound_queue_v2::OnNewCommitment;
@ -1678,51 +1679,39 @@ impl pallet_tx_pause::Config for Runtime {
type WeightInfo = mainnet_weights::pallet_tx_pause::WeightInfo<Runtime>;
}
// Stub SendMessage implementation for slash pallet
pub struct SlashesSendAdapter;
impl pallet_external_validator_slashes::SendMessage<AccountId> for SlashesSendAdapter {
type Message = OutboundMessage;
type Ticket = OutboundMessage;
fn build(
_slashes_utils: &pallet_external_validator_slashes::SlashDataUtils<AccountId>,
) -> Option<Self::Message> {
let calldata = Vec::new();
/// Mainnet slashes configuration for EigenLayer submission.
pub struct MainnetSlashesConfig;
let command = Command::CallContract {
target:
runtime_params::dynamic_params::runtime_config::DatahavenServiceManagerAddress::get(
),
calldata,
gas: 1_000_000, // TODO: Determine appropriate gas value after testing
value: 0,
};
let message = OutboundMessage {
origin: runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get(), // TODO: get the slash agent address
// TODO: Determine appropriate id value
id: unique(1).into(),
fee: 0,
commands: match vec![command].try_into() {
Ok(cmds) => cmds,
Err(_) => {
log::error!(
target: "slashes_send_adapter",
"Failed to convert commands: too many commands"
);
return None;
}
},
};
Some(message)
impl datahaven_runtime_common::slashes_adapter::SlashesSubmissionConfig for MainnetSlashesConfig {
type OutboundQueue = EthereumOutboundQueueV2;
fn service_manager_address() -> H160 {
runtime_params::dynamic_params::runtime_config::DatahavenServiceManagerAddress::get()
}
fn validate(message: Self::Message) -> Result<Self::Ticket, SendError> {
EthereumOutboundQueueV2::validate(&message)
fn slashes_agent_origin() -> H256 {
runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get()
// TODO: Can we use the same as reward and just rename the config to `AgentOrigin` ?
}
fn deliver(message: Self::Ticket) -> Result<H256, SendError> {
EthereumOutboundQueueV2::deliver(message)
fn strategies() -> Vec<Address> {
// We only slash strategy that we reward
let mut strategies: Vec<Address> =
runtime_params::dynamic_params::runtime_config::RewardsStrategiesAndMultipliers::get()
.iter()
.map(|(strategy, _mult)| Address::from(strategy.as_fixed_bytes()))
.collect();
// The array of strategies need to be in ascending order (see https://github.com/Layr-Labs/eigenlayer-contracts/blob/7ecc83c7b180850531bc5b8b953a7340adeecd43/src/contracts/core/AllocationManager.sol#L343-L347)
strategies.sort();
return strategies;
}
}
// Stub SendMessage implementation for slash pallet
pub type SlashesSendAdapter =
datahaven_runtime_common::slashes_adapter::SlashesSubmissionAdapter<MainnetSlashesConfig>;
impl pallet_external_validator_slashes::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type ValidatorId = AccountId;

View file

@ -324,9 +324,8 @@ pub mod dynamic_params {
#[codec(index = 35)]
#[allow(non_upper_case_globals)]
/// The Selector is the first 4 bytes of the keccak256 hash of the function signature("slashValidatorsOperator(address[])")
pub static SlashOperatorSelector: BoundedVec<u8, ConstU32<4>> =
BoundedVec::truncate_from(vec![0xca, 0x48, 0x11, 0x9f]);
/// Temporary placeholder.
pub static Placeholder: H160 = H160::repeat_byte(0x0);
#[codec(index = 36)]
#[allow(non_upper_case_globals)]

View file

@ -502,7 +502,7 @@ impl pallet_file_system::Config for Runtime {
type CollectionInspector = BucketNfts;
type BspStopStoringFilePenalty = runtime_config::BspStopStoringFilePenalty;
type TreasuryAccount = TreasuryAccount;
type MaxBatchConfirmStorageRequests = ConstU32<10>;
type MaxBatchConfirmStorageRequests = ConstU32<100>;
type MaxFilePathSize = ConstU32<512u32>;
type MaxPeerIdSize = ConstU32<100>;
type MaxNumberOfPeerIds = ConstU32<5>;

View file

@ -142,7 +142,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 200 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 910,
spec_version: 1000,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
@ -1254,6 +1254,12 @@ impl_runtime_apis! {
fn list_incomplete_storage_request_keys(start_after: Option<H256>, limit: u32) -> Vec<H256> {
FileSystem::list_incomplete_storage_request_keys(start_after, limit)
}
fn query_pending_bsp_confirm_storage_requests(
bsp_id: BackupStorageProviderId<Runtime>,
file_keys: Vec<H256>,
) -> Vec<H256> {
FileSystem::query_pending_bsp_confirm_storage_requests(bsp_id, file_keys)
}
}
impl pallet_payment_streams_runtime_api::PaymentStreamsApi<Block, ProviderIdFor<Runtime>, Balance, AccountId> for Runtime {

View file

@ -13,6 +13,7 @@ version = { workspace = true }
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
alloy-core = { workspace = true, features = ["sol-types"] }
bridge-hub-common = { workspace = true, optional = true }
codec = { workspace = true, features = ["derive"] }
datahaven-runtime-common = { workspace = true }
@ -183,6 +184,7 @@ snowbridge-pallet-system-v2 = { workspace = true }
[features]
default = ["std"]
std = [
"alloy-core/std",
"codec/std",
"datahaven-runtime-common/std",
"fp-account/std",

View file

@ -30,6 +30,7 @@ use super::{
Signature, System, Timestamp, Treasury, TxPause, BLOCK_HASH_COUNT, EXTRINSIC_BASE_WEIGHT,
MAXIMUM_BLOCK_WEIGHT, NORMAL_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, VERSION,
};
use alloy_core::primitives::Address;
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{traits::AccountIdConversion, RuntimeDebug};
@ -103,7 +104,7 @@ use frame_support::{
weights::{constants::RocksDbWeight, IdentityFee, RuntimeDbWeight, Weight},
PalletId,
};
use frame_system::{limits::BlockLength, unique, EnsureRoot, EnsureRootWithSuccess};
use frame_system::{limits::BlockLength, EnsureRoot, EnsureRootWithSuccess};
use governance::councils::*;
use pallet_ethereum::PostLogContent;
use pallet_evm::{
@ -123,7 +124,7 @@ use snowbridge_core::{gwei, meth, AgentIdOf, PricingParameters, Rewards, TokenId
use snowbridge_inbound_queue_primitives::RewardLedger;
use snowbridge_outbound_queue_primitives::{
v1::{Fee, Message, SendMessage},
v2::{Command, ConstantGasMeter, Message as OutboundMessage, SendMessage as SendMessageV2},
v2::{Command, ConstantGasMeter},
SendError, SendMessageFeeProvider,
};
use snowbridge_pallet_outbound_queue_v2::OnNewCommitment;
@ -1674,51 +1675,39 @@ impl pallet_tx_pause::Config for Runtime {
type WeightInfo = stagenet_weights::pallet_tx_pause::WeightInfo<Runtime>;
}
// Stub SendMessage implementation for slash pallet
pub struct SlashesSendAdapter;
impl pallet_external_validator_slashes::SendMessage<AccountId> for SlashesSendAdapter {
type Message = OutboundMessage;
type Ticket = OutboundMessage;
fn build(
_slashes_utils: &pallet_external_validator_slashes::SlashDataUtils<AccountId>,
) -> Option<Self::Message> {
let calldata = Vec::new();
/// Stagenet slashes configuration for EigenLayer submission.
pub struct StagenetSlashesConfig;
let command = Command::CallContract {
target:
runtime_params::dynamic_params::runtime_config::DatahavenServiceManagerAddress::get(
),
calldata,
gas: 1_000_000, // TODO: Determine appropriate gas value after testing
value: 0,
};
let message = OutboundMessage {
origin: runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get(), // TODO: get the slash agent address
// TODO: Determine appropriate id value
id: unique(1).into(),
fee: 0,
commands: match vec![command].try_into() {
Ok(cmds) => cmds,
Err(_) => {
log::error!(
target: "slashes_send_adapter",
"Failed to convert commands: too many commands"
);
return None;
}
},
};
Some(message)
impl datahaven_runtime_common::slashes_adapter::SlashesSubmissionConfig for StagenetSlashesConfig {
type OutboundQueue = EthereumOutboundQueueV2;
fn service_manager_address() -> H160 {
runtime_params::dynamic_params::runtime_config::DatahavenServiceManagerAddress::get()
}
fn validate(message: Self::Message) -> Result<Self::Ticket, SendError> {
EthereumOutboundQueueV2::validate(&message)
fn slashes_agent_origin() -> H256 {
runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get()
// TODO: Can we use the same as reward and just rename the config to `AgentOrigin` ?
}
fn deliver(message: Self::Ticket) -> Result<H256, SendError> {
EthereumOutboundQueueV2::deliver(message)
fn strategies() -> Vec<Address> {
// We only slash strategy that we reward
let mut strategies: Vec<Address> =
runtime_params::dynamic_params::runtime_config::RewardsStrategiesAndMultipliers::get()
.iter()
.map(|(strategy, _mult)| Address::from(strategy.as_fixed_bytes()))
.collect();
// The array of strategies need to be in ascending order (see https://github.com/Layr-Labs/eigenlayer-contracts/blob/7ecc83c7b180850531bc5b8b953a7340adeecd43/src/contracts/core/AllocationManager.sol#L343-L347)
strategies.sort();
return strategies;
}
}
// Stub SendMessage implementation for slash pallet
pub type SlashesSendAdapter =
datahaven_runtime_common::slashes_adapter::SlashesSubmissionAdapter<StagenetSlashesConfig>;
impl pallet_external_validator_slashes::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type ValidatorId = AccountId;

View file

@ -327,9 +327,8 @@ pub mod dynamic_params {
#[codec(index = 35)]
#[allow(non_upper_case_globals)]
/// The Selector is the first 4 bytes of the keccak256 hash of the function signature("slashValidatorsOperator(address[])")
pub static SlashOperatorSelector: BoundedVec<u8, ConstU32<4>> =
BoundedVec::truncate_from(vec![0xca, 0x48, 0x11, 0x9f]);
/// Temporary placeholder.
pub static Placeholder: H160 = H160::repeat_byte(0x0);
#[codec(index = 36)]
#[allow(non_upper_case_globals)]

View file

@ -502,7 +502,7 @@ impl pallet_file_system::Config for Runtime {
type CollectionInspector = BucketNfts;
type BspStopStoringFilePenalty = runtime_config::BspStopStoringFilePenalty;
type TreasuryAccount = TreasuryAccount;
type MaxBatchConfirmStorageRequests = ConstU32<10>;
type MaxBatchConfirmStorageRequests = ConstU32<100>;
type MaxFilePathSize = ConstU32<512u32>;
type MaxPeerIdSize = ConstU32<100>;
type MaxNumberOfPeerIds = ConstU32<5>;

View file

@ -145,7 +145,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 200 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 910,
spec_version: 1000,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
@ -1257,6 +1257,12 @@ impl_runtime_apis! {
fn list_incomplete_storage_request_keys(start_after: Option<H256>, limit: u32) -> Vec<H256> {
FileSystem::list_incomplete_storage_request_keys(start_after, limit)
}
fn query_pending_bsp_confirm_storage_requests(
bsp_id: BackupStorageProviderId<Runtime>,
file_keys: Vec<H256>,
) -> Vec<H256> {
FileSystem::query_pending_bsp_confirm_storage_requests(bsp_id, file_keys)
}
}
impl pallet_payment_streams_runtime_api::PaymentStreamsApi<Block, ProviderIdFor<Runtime>, Balance, AccountId> for Runtime {

View file

@ -13,6 +13,7 @@ version = { workspace = true }
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
alloy-core = { workspace = true, features = ["sol-types"] }
bridge-hub-common = { workspace = true, optional = true }
codec = { workspace = true, features = ["derive"] }
datahaven-runtime-common = { workspace = true }
@ -183,6 +184,7 @@ snowbridge-pallet-system-v2 = { workspace = true }
[features]
default = ["std"]
std = [
"alloy-core/std",
"codec/std",
"datahaven-runtime-common/std",
"fp-account/std",

View file

@ -30,6 +30,7 @@ use super::{
Signature, System, Timestamp, Treasury, TxPause, BLOCK_HASH_COUNT, EXTRINSIC_BASE_WEIGHT,
MAXIMUM_BLOCK_WEIGHT, NORMAL_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, VERSION,
};
use alloy_core::primitives::Address;
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{traits::AccountIdConversion, RuntimeDebug};
@ -103,7 +104,7 @@ use frame_support::{
weights::{constants::RocksDbWeight, IdentityFee, RuntimeDbWeight, Weight},
PalletId,
};
use frame_system::{limits::BlockLength, unique, EnsureRoot, EnsureRootWithSuccess};
use frame_system::{limits::BlockLength, EnsureRoot, EnsureRootWithSuccess};
use governance::councils::*;
use pallet_ethereum::PostLogContent;
use pallet_evm::{
@ -123,7 +124,7 @@ use snowbridge_core::{gwei, meth, AgentIdOf, PricingParameters, Rewards, TokenId
use snowbridge_inbound_queue_primitives::RewardLedger;
use snowbridge_outbound_queue_primitives::{
v1::{Fee, Message, SendMessage},
v2::{Command, ConstantGasMeter, Message as OutboundMessage, SendMessage as SendMessageV2},
v2::{Command, ConstantGasMeter},
SendError, SendMessageFeeProvider,
};
use snowbridge_pallet_outbound_queue_v2::OnNewCommitment;
@ -1678,51 +1679,38 @@ impl pallet_tx_pause::Config for Runtime {
type WeightInfo = testnet_weights::pallet_tx_pause::WeightInfo<Runtime>;
}
// Stub SendMessage implementation for slash pallet
pub struct SlashesSendAdapter;
impl pallet_external_validator_slashes::SendMessage<AccountId> for SlashesSendAdapter {
type Message = OutboundMessage;
type Ticket = OutboundMessage;
fn build(
_slashes_utils: &pallet_external_validator_slashes::SlashDataUtils<AccountId>,
) -> Option<Self::Message> {
let calldata = Vec::new();
/// Testnet slashes configuration for EigenLayer submission.
pub struct TestnetSlashesConfig;
let command = Command::CallContract {
target:
runtime_params::dynamic_params::runtime_config::DatahavenServiceManagerAddress::get(
),
calldata,
gas: 1_000_000, // TODO: Determine appropriate gas value after testing
value: 0,
};
let message = OutboundMessage {
origin: runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get(), // TODO: get the slash agent address
// TODO: Determine appropriate id value
id: unique(1).into(),
fee: 0,
commands: match vec![command].try_into() {
Ok(cmds) => cmds,
Err(_) => {
log::error!(
target: "slashes_send_adapter",
"Failed to convert commands: too many commands"
);
return None;
}
},
};
Some(message)
impl datahaven_runtime_common::slashes_adapter::SlashesSubmissionConfig for TestnetSlashesConfig {
type OutboundQueue = EthereumOutboundQueueV2;
fn service_manager_address() -> H160 {
runtime_params::dynamic_params::runtime_config::DatahavenServiceManagerAddress::get()
}
fn validate(message: Self::Message) -> Result<Self::Ticket, SendError> {
EthereumOutboundQueueV2::validate(&message)
fn slashes_agent_origin() -> H256 {
runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get()
// TODO: Can we use the same as reward and just rename the config to `AgentOrigin` ?
}
fn deliver(message: Self::Ticket) -> Result<H256, SendError> {
EthereumOutboundQueueV2::deliver(message)
fn strategies() -> Vec<Address> {
// We only slash strategy that we reward
let mut strategies: Vec<Address> =
runtime_params::dynamic_params::runtime_config::RewardsStrategiesAndMultipliers::get()
.iter()
.map(|(strategy, _mult)| Address::from(strategy.as_fixed_bytes()))
.collect();
// The array of strategies need to be in ascending order (see https://github.com/Layr-Labs/eigenlayer-contracts/blob/7ecc83c7b180850531bc5b8b953a7340adeecd43/src/contracts/core/AllocationManager.sol#L343-L347)
strategies.sort();
return strategies;
}
}
// Stub SendMessage implementation for slash pallet
pub type SlashesSendAdapter =
datahaven_runtime_common::slashes_adapter::SlashesSubmissionAdapter<TestnetSlashesConfig>;
impl pallet_external_validator_slashes::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type ValidatorId = AccountId;

View file

@ -325,9 +325,8 @@ pub mod dynamic_params {
#[codec(index = 35)]
#[allow(non_upper_case_globals)]
/// The Selector is the first 4 bytes of the keccak256 hash of the function signature("slashValidatorsOperator(address[])")
pub static SlashOperatorSelector: BoundedVec<u8, ConstU32<4>> =
BoundedVec::truncate_from(vec![0xca, 0x48, 0x11, 0x9f]);
/// Temporary placeholder.
pub static Placeholder: H160 = H160::repeat_byte(0x0);
#[codec(index = 36)]
#[allow(non_upper_case_globals)]

View file

@ -502,7 +502,7 @@ impl pallet_file_system::Config for Runtime {
type CollectionInspector = BucketNfts;
type BspStopStoringFilePenalty = runtime_config::BspStopStoringFilePenalty;
type TreasuryAccount = TreasuryAccount;
type MaxBatchConfirmStorageRequests = ConstU32<10>;
type MaxBatchConfirmStorageRequests = ConstU32<100>;
type MaxFilePathSize = ConstU32<512u32>;
type MaxPeerIdSize = ConstU32<100>;
type MaxNumberOfPeerIds = ConstU32<5>;

View file

@ -142,7 +142,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 200 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 910,
spec_version: 1000,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
@ -1254,6 +1254,12 @@ impl_runtime_apis! {
fn list_incomplete_storage_request_keys(start_after: Option<H256>, limit: u32) -> Vec<H256> {
FileSystem::list_incomplete_storage_request_keys(start_after, limit)
}
fn query_pending_bsp_confirm_storage_requests(
bsp_id: BackupStorageProviderId<Runtime>,
file_keys: Vec<H256>,
) -> Vec<H256> {
FileSystem::query_pending_bsp_confirm_storage_requests(bsp_id, file_keys)
}
}
impl pallet_payment_streams_runtime_api::PaymentStreamsApi<Block, ProviderIdFor<Runtime>, Balance, AccountId> for Runtime {

View file

@ -1,5 +1,5 @@
{
"version": "0.1.0-autogenerated.11986612280028596972",
"version": "0.1.0-autogenerated.18110841939960448741",
"name": "@polkadot-api/descriptors",
"files": [
"dist"

Binary file not shown.

View file

@ -293,19 +293,21 @@ This script will:
```
test/
├── suites/ # E2E test suites
│ ├── contracts.test.ts # Contract deployment & configuration
│ ├── cross-chain.test.ts # Cross-chain message passing
│ ├── datahaven-substrate.test.ts # Block production & finality
│ ├── ethereum-basic.test.ts # Ethereum network validation
│ ├── native-token-transfer.test.ts # Cross-chain token transfers
│ ├── rewards-message.test.ts # Validator rewards distribution
│ └── validator-set-update.test.ts # Dynamic validator set updates
├── framework/ # Test utilities & helpers
│ ├── connectors.ts # Network connectors
│ ├── manager.ts # Test environment manager
│ ├── suite.ts # Test suite utilities
│ └── index.ts # Framework exports
├── e2e/
│ ├── suites/ # E2E test suites (Kurtosis-based)
│ │ ├── native-token-transfer.test.ts
│ │ ├── rewards-message.test.ts
│ │ └── validator-set-update.test.ts
│ └── framework/ # Test utilities & helpers
│ ├── connectors.ts # Network connectors
│ ├── manager.ts # Test environment manager
│ ├── suite.ts # Test suite utilities
│ ├── validators.ts # Validator test helpers
│ └── index.ts # Framework exports
├── moonwall/ # Moonwall single-node tests
│ ├── contracts/ # Test contracts for Moonwall
│ ├── helpers/ # Moonwall test helpers
│ └── suites/ # Moonwall test suites
├── launcher/ # Network deployment tools
│ ├── kurtosis/ # Ethereum network launcher
│ ├── snowbridge/ # Relayer management

View file

@ -2028,12 +2028,12 @@ export const dataHavenServiceManagerAbi = [
type: 'constructor',
inputs: [
{
name: '__rewardsCoordinator',
name: 'rewardsCoordinator_',
internalType: 'contract IRewardsCoordinator',
type: 'address',
},
{
name: '__allocationManager',
name: 'allocationManager_',
internalType: 'contract IAllocationManager',
type: 'address',
},
@ -2118,7 +2118,7 @@ export const dataHavenServiceManagerAbi = [
type: 'address',
},
],
name: 'initialise',
name: 'initialize',
outputs: [],
stateMutability: 'nonpayable',
},
@ -2207,6 +2207,29 @@ export const dataHavenServiceManagerAbi = [
outputs: [],
stateMutability: 'nonpayable',
},
{
type: 'function',
inputs: [
{
name: 'slashings',
internalType: 'struct IDataHavenServiceManager.SlashingRequest[]',
type: 'tuple[]',
components: [
{ name: 'operator', internalType: 'address', type: 'address' },
{
name: 'strategies',
internalType: 'contract IStrategy[]',
type: 'address[]',
},
{ name: 'wadsToSlash', internalType: 'uint256[]', type: 'uint256[]' },
{ name: 'description', internalType: 'string', type: 'string' },
],
},
],
name: 'slashValidatorsOperator',
outputs: [],
stateMutability: 'nonpayable',
},
{
type: 'function',
inputs: [],
@ -2413,6 +2436,7 @@ export const dataHavenServiceManagerAbi = [
],
name: 'RewardsSubmitted',
},
{ type: 'event', anonymous: false, inputs: [], name: 'SlashingComplete' },
{
type: 'event',
anonymous: false,
@ -2426,6 +2450,25 @@ export const dataHavenServiceManagerAbi = [
],
name: 'SnowbridgeGatewaySet',
},
{
type: 'event',
anonymous: false,
inputs: [
{
name: 'validator',
internalType: 'address',
type: 'address',
indexed: true,
},
{
name: 'solochainAddress',
internalType: 'address',
type: 'address',
indexed: true,
},
],
name: 'SolochainAddressUpdated',
},
{
type: 'event',
anonymous: false,
@ -2457,9 +2500,11 @@ export const dataHavenServiceManagerAbi = [
{ type: 'error', inputs: [], name: 'CantRegisterToMultipleOperatorSets' },
{ type: 'error', inputs: [], name: 'IncorrectAVSAddress' },
{ type: 'error', inputs: [], name: 'InvalidOperatorSetId' },
{ type: 'error', inputs: [], name: 'InvalidSolochainAddressLength' },
{ type: 'error', inputs: [], name: 'OnlyAllocationManager' },
{ type: 'error', inputs: [], name: 'OnlyRewardsInitiator' },
{ type: 'error', inputs: [], name: 'OperatorNotInAllowlist' },
{ type: 'error', inputs: [], name: 'ZeroAddress' },
] as const
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -10722,12 +10767,12 @@ export const writeDataHavenServiceManagerDeregisterOperatorFromOperatorSets =
})
/**
* Wraps __{@link writeContract}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `functionName` set to `"initialise"`
* Wraps __{@link writeContract}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `functionName` set to `"initialize"`
*/
export const writeDataHavenServiceManagerInitialise =
export const writeDataHavenServiceManagerInitialize =
/*#__PURE__*/ createWriteContract({
abi: dataHavenServiceManagerAbi,
functionName: 'initialise',
functionName: 'initialize',
})
/**
@ -10793,6 +10838,15 @@ export const writeDataHavenServiceManagerSetSnowbridgeGateway =
functionName: 'setSnowbridgeGateway',
})
/**
* Wraps __{@link writeContract}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `functionName` set to `"slashValidatorsOperator"`
*/
export const writeDataHavenServiceManagerSlashValidatorsOperator =
/*#__PURE__*/ createWriteContract({
abi: dataHavenServiceManagerAbi,
functionName: 'slashValidatorsOperator',
})
/**
* Wraps __{@link writeContract}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `functionName` set to `"submitRewards"`
*/
@ -10872,12 +10926,12 @@ export const simulateDataHavenServiceManagerDeregisterOperatorFromOperatorSets =
})
/**
* Wraps __{@link simulateContract}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `functionName` set to `"initialise"`
* Wraps __{@link simulateContract}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `functionName` set to `"initialize"`
*/
export const simulateDataHavenServiceManagerInitialise =
export const simulateDataHavenServiceManagerInitialize =
/*#__PURE__*/ createSimulateContract({
abi: dataHavenServiceManagerAbi,
functionName: 'initialise',
functionName: 'initialize',
})
/**
@ -10943,6 +10997,15 @@ export const simulateDataHavenServiceManagerSetSnowbridgeGateway =
functionName: 'setSnowbridgeGateway',
})
/**
* Wraps __{@link simulateContract}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `functionName` set to `"slashValidatorsOperator"`
*/
export const simulateDataHavenServiceManagerSlashValidatorsOperator =
/*#__PURE__*/ createSimulateContract({
abi: dataHavenServiceManagerAbi,
functionName: 'slashValidatorsOperator',
})
/**
* Wraps __{@link simulateContract}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `functionName` set to `"submitRewards"`
*/
@ -11039,6 +11102,15 @@ export const watchDataHavenServiceManagerRewardsSubmittedEvent =
eventName: 'RewardsSubmitted',
})
/**
* Wraps __{@link watchContractEvent}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `eventName` set to `"SlashingComplete"`
*/
export const watchDataHavenServiceManagerSlashingCompleteEvent =
/*#__PURE__*/ createWatchContractEvent({
abi: dataHavenServiceManagerAbi,
eventName: 'SlashingComplete',
})
/**
* Wraps __{@link watchContractEvent}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `eventName` set to `"SnowbridgeGatewaySet"`
*/
@ -11048,6 +11120,15 @@ export const watchDataHavenServiceManagerSnowbridgeGatewaySetEvent =
eventName: 'SnowbridgeGatewaySet',
})
/**
* Wraps __{@link watchContractEvent}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `eventName` set to `"SolochainAddressUpdated"`
*/
export const watchDataHavenServiceManagerSolochainAddressUpdatedEvent =
/*#__PURE__*/ createWatchContractEvent({
abi: dataHavenServiceManagerAbi,
eventName: 'SolochainAddressUpdated',
})
/**
* Wraps __{@link watchContractEvent}__ with `abi` set to __{@link dataHavenServiceManagerAbi}__ and `eventName` set to `"ValidatorAddedToAllowlist"`
*/

View file

@ -10,8 +10,10 @@ The E2E testing framework creates isolated test environments for comprehensive i
```
test/
├── suites/ # Test files (*.test.ts)
├── framework/ # Base classes and test utilities
├── e2e/
│ ├── suites/ # E2E test files (*.test.ts)
│ └── framework/ # Base classes and test utilities
├── moonwall/ # Moonwall single-node tests
├── launcher/ # Network orchestration code
├── utils/ # Common helpers and utilities
├── configs/ # Component configuration files
@ -65,7 +67,7 @@ The `launchNetwork` function orchestrates the following steps:
### Basic Test Structure
```typescript
import { BaseTestSuite } from "../framework/base-test-suite";
import { BaseTestSuite } from "../e2e/framework";
class MyTestSuite extends BaseTestSuite {
constructor() {

View file

@ -16,7 +16,7 @@ import {
import { privateKeyToAccount } from "viem/accounts";
import { anvil } from "viem/chains";
import { socketClientCache } from "viem/utils";
import type { LaunchNetworkResult } from "../launcher";
import type { LaunchNetworkResult } from "../../launcher";
export interface TestConnectors {
// Ethereum connectors

View file

@ -1,3 +1,4 @@
export * from "./connectors";
export * from "./manager";
export * from "./suite";
export * from "./validators";

View file

@ -2,8 +2,8 @@ import { afterAll, beforeAll } from "bun:test";
import readline from "node:readline";
import { isCI } from "launcher/network";
import { logger } from "utils";
import { launchNetwork } from "../launcher";
import type { LaunchNetworkResult } from "../launcher/types";
import { launchNetwork } from "../../launcher";
import type { LaunchNetworkResult } from "../../launcher/types";
import { ConnectorFactory, type TestConnectors } from "./connectors";
import { TestSuiteManager } from "./manager";

View file

@ -0,0 +1,164 @@
/**
* E2E test helper functions for validator management
* These functions depend on TestConnectors and are only used in e2e tests
*/
import { $ } from "bun";
import {
allocationManagerAbi,
dataHavenServiceManagerAbi,
delegationManagerAbi
} from "contract-bindings";
import { type Deployments, logger, waitForContainerToStart } from "utils";
import { DEFAULT_SUBSTRATE_WS_PORT } from "utils/constants";
import { getPublicPort } from "utils/docker";
import { privateKeyToAccount } from "viem/accounts";
import validatorSet from "../../configs/validator-set.json";
import type { LaunchedNetwork } from "../../launcher/types/launchedNetwork";
import { getOwnerAccount } from "../../launcher/validators";
import type { TestConnectors } from "./connectors";
/**
* Get validator info by name from validator set JSON
* @param name - Validator name (e.g., "alice", "bob")
* @returns Validator info
*/
export const getValidator = (name: string) => {
const node = validatorSet.validators.find((v) => v.solochainAuthorityName === name.toLowerCase());
if (!node) throw new Error(`Validator ${name} not found`);
return node;
};
/** Checks if a DataHaven validator container is running */
export const isValidatorRunning = async (name: string, networkId: string) =>
(await $`docker ps -q -f name=^datahaven-${name}-${networkId}`.text()).trim().length > 0;
/** Launches a single DataHaven validator node on demand */
export const launchDatahavenValidator = async (
name: string,
options: { launchedNetwork: LaunchedNetwork; datahavenImageTag?: string }
): Promise<void> => {
const { launchedNetwork, datahavenImageTag = "datahavenxyz/datahaven:local" } = options;
const nodeId = name.toLowerCase();
const containerName = `datahaven-${nodeId}-${launchedNetwork.networkId}`;
if (await isValidatorRunning(nodeId, launchedNetwork.networkId)) {
logger.warn(`⚠️ Node ${nodeId} is already running`);
return;
}
logger.debug(`Launching DataHaven validator node: ${nodeId}...`);
const COMMON_LAUNCH_ARGS = [
"--unsafe-force-node-key-generation",
"--tmp",
"--validator",
"--discover-local",
"--no-prometheus",
"--unsafe-rpc-external",
"--rpc-cors=all",
"--force-authoring",
"--no-telemetry",
"--enable-offchain-indexing=true"
];
const args = [
"run",
"-d",
"--name",
containerName,
"--network",
launchedNetwork.networkName,
"-p",
String(DEFAULT_SUBSTRATE_WS_PORT),
datahavenImageTag,
`--${nodeId}`,
...COMMON_LAUNCH_ARGS
];
await $`docker ${args}`.quiet();
await waitForContainerToStart(containerName);
const publicPort = await getPublicPort(containerName, DEFAULT_SUBSTRATE_WS_PORT);
launchedNetwork.addContainer(
containerName,
{ ws: publicPort },
{ ws: DEFAULT_SUBSTRATE_WS_PORT }
);
logger.debug(`DataHaven validator ${nodeId} launched on port ${publicPort}`);
};
/** Adds a validator to the EigenLayer allowlist */
export const addValidatorToAllowlist = async (
validatorName: string,
options: { connectors: TestConnectors; deployments: Deployments }
): Promise<void> => {
logger.debug(`Adding validator ${validatorName} to allowlist...`);
const { connectors, deployments } = options;
const validator = getValidator(validatorName);
const hash = await connectors.walletClient.writeContract({
address: deployments.ServiceManager as `0x${string}`,
abi: dataHavenServiceManagerAbi,
functionName: "addValidatorToAllowlist",
args: [validator.publicKey as `0x${string}`],
account: getOwnerAccount(),
chain: null
});
await connectors.publicClient.waitForTransactionReceipt({ hash });
logger.debug(`Validator ${validatorName} added to allowlist`);
};
/** Register an operator in EigenLayer and for operator sets */
export async function registerOperator(
validatorName: string,
options: { connectors: TestConnectors; deployments: Deployments }
): Promise<void> {
const { connectors, deployments } = options;
const validator = getValidator(validatorName);
const account = privateKeyToAccount(validator.privateKey as `0x${string}`);
// Register as EigenLayer operator
const operatorHash = await connectors.walletClient.writeContract({
address: deployments.DelegationManager as `0x${string}`,
abi: delegationManagerAbi,
functionName: "registerAsOperator",
args: ["0x0000000000000000000000000000000000000000", 0, ""],
account,
chain: null
});
const operatorReceipt = await connectors.publicClient.waitForTransactionReceipt({
hash: operatorHash
});
if (operatorReceipt.status !== "success") {
throw new Error(`EigenLayer operator registration failed: ${operatorReceipt.status}`);
}
// Register for operator sets
const hash = await connectors.walletClient.writeContract({
address: deployments.AllocationManager as `0x${string}`,
abi: allocationManagerAbi,
functionName: "registerForOperatorSets",
args: [
validator.publicKey as `0x${string}`,
{
avs: deployments.ServiceManager as `0x${string}`,
operatorSetIds: [0],
data: validator.solochainAddress as `0x${string}`
}
],
account,
chain: null
});
const receipt = await connectors.publicClient.waitForTransactionReceipt({ hash });
if (receipt.status !== "success") {
throw new Error(`Operator set registration failed: ${receipt.status}`);
}
logger.debug(`Registered ${validatorName} as operator (gas: ${receipt.gasUsed})`);
}

View file

@ -26,7 +26,7 @@ import {
ZERO_ADDRESS
} from "utils";
import { decodeEventLog, encodeAbiParameters, erc20Abi, parseEther, parseEventLogs } from "viem";
import { gatewayAbi } from "../contract-bindings";
import { gatewayAbi } from "../../contract-bindings";
import { BaseTestSuite } from "../framework";
import type { TestConnectors } from "../framework/connectors";

View file

@ -2,9 +2,9 @@ import { beforeAll, describe, expect, it } from "bun:test";
import { FixedSizeBinary } from "polkadot-api";
import { CROSS_CHAIN_TIMEOUTS, getEvmEcdsaSigner, logger, SUBSTRATE_FUNDED_ACCOUNTS } from "utils";
import type { Address } from "viem";
import { getContractInstance, parseDeploymentsFile } from "../../utils/contracts";
import { waitForDataHavenEvent } from "../../utils/events";
import { BaseTestSuite } from "../framework";
import { getContractInstance, parseDeploymentsFile } from "../utils/contracts";
import { waitForDataHavenEvent } from "../utils/events";
/**
* Temporary helper to set V2 rewards parameters via sudo.

View file

@ -0,0 +1,162 @@
import { beforeAll, describe, expect, it } from "bun:test";
import { FixedSizeBinary } from "polkadot-api";
import { CROSS_CHAIN_TIMEOUTS, getPapiSigner, logger } from "utils";
import type { Address } from "viem";
import { getContractInstance, parseDeploymentsFile } from "../../utils/contracts";
import { waitForDataHavenEvent } from "../../utils/events";
import { BaseTestSuite } from "../framework";
class SlashTestSuite extends BaseTestSuite {
constructor() {
super({
suiteName: "slash"
});
// Set up hooks in constructor
this.setupHooks();
}
}
// Create the test suite instance
const suite = new SlashTestSuite();
describe("Should slash an operator", () => {
let publicClient: any;
let dhApi: any;
beforeAll(async () => {
const connectors = suite.getTestConnectors();
publicClient = connectors.publicClient;
dhApi = connectors.dhApi;
const deployments = await parseDeploymentsFile();
const strategyAddress =
deployments.DeployedStrategies?.[0]?.address ?? "0x0000000000000000000000000000000000000000";
logger.info(
"Setting slashing required parameters:\n" +
` StrategyAddress=${strategyAddress}\n` +
` ServiceManagerAddress=${deployments.ServiceManager}\n`
);
// Build sudo calls to set parameters
const calls = [
// Set DatahavenServiceManagerAddress address (required to call the slash operator function)
dhApi.tx.Parameters.set_parameter({
key_value: {
type: "RuntimeConfig",
value: {
type: "DatahavenServiceManagerAddress",
value: [new FixedSizeBinary(Buffer.from(deployments.ServiceManager.slice(2), "hex"))]
}
}
}).decodedCall,
// Set strategies and multipliers: [(strategy_address, multiplier)] (we use the same rewards strategy for the slashing logic)
dhApi.tx.Parameters.set_parameter({
key_value: {
type: "RuntimeConfig",
value: {
type: "RewardsStrategiesAndMultipliers",
value: [[[new FixedSizeBinary(Buffer.from(strategyAddress.slice(2), "hex")), 1n]]]
}
}
}).decodedCall
];
const tx = dhApi.tx.Sudo.sudo({
call: dhApi.tx.Utility.batch_all({ calls }).decodedCall
});
const alithSigner = getPapiSigner("ALITH");
const result = await tx.signAndSubmit(alithSigner);
if (!result.ok) {
throw new Error("Failed to set slasher required parameters");
}
logger.info("slashing required parameters set successfully");
});
it("verify we have the agent origin set", async () => {
const gateway = await getContractInstance("Gateway");
const serviceManager = await getContractInstance("ServiceManager");
expect(serviceManager.address).toBeDefined();
expect(gateway.address).toBeDefined();
const rewardsInitiator = (await publicClient.readContract({
address: serviceManager.address,
abi: serviceManager.abi,
functionName: "rewardsInitiator",
args: []
})) as Address;
// ServiceManager must have a rewardsInitiator configured for EigenLayer rewards submission
expect(rewardsInitiator).toBeDefined();
logger.info(`ServiceManager rewardsInitiator: ${rewardsInitiator}`);
});
it("Activate slashing", async () => {
const mode = await dhApi.query.ExternalValidatorsSlashes.SlashingMode.getValue();
expect(mode.type).toBe("LogOnly");
mode.type = "Enabled";
const sudoSlashCall = dhApi.tx.ExternalValidatorsSlashes.set_slashing_mode({
mode
});
const sudoTx = dhApi.tx.Sudo.sudo({
call: sudoSlashCall.decodedCall
});
const alithSigner = getPapiSigner("ALITH");
const result = await sudoTx.signAndSubmit(alithSigner);
expect(result.ok).toBeTruthy();
const mode2 = await dhApi.query.ExternalValidatorsSlashes.SlashingMode.getValue();
expect(mode2.type).toBe("Enabled");
}, 40000);
it("use sudo to slash operator", async () => {
// get era number
const activeEra = await dhApi.query.ExternalValidators.ActiveEra.getValue();
if (activeEra === undefined) {
throw new Error("couldn't get current era");
}
// need operator address to slash
const validator = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
const sudoSlashCall = dhApi.tx.ExternalValidatorsSlashes.force_inject_slash({
validator,
era: activeEra?.index || 0, // Will fail if active era is 0. !! Important !! Sometimes for the inject to work (because of some latency) we need to inject in the `activeEra.index + 1`
percentage: 20
});
const sudoTx = dhApi.tx.Sudo.sudo({
call: sudoSlashCall.decodedCall
});
const alithSigner = getPapiSigner("ALITH");
const resultSubmitTx = await sudoTx.signAndSubmit(alithSigner);
expect(resultSubmitTx.ok).toBeTruthy();
logger.info("Transaction submitted !");
// look for event inject event
const resultEventSlashInjected =
await dhApi.event.ExternalValidatorsSlashes.SlashInjected.pull();
if (resultEventSlashInjected.length === 0) {
throw new Error("SlashInjected event not found");
}
logger.info("Slash injected");
const resultEventSlashesMessageSent = await waitForDataHavenEvent<{ message_id: any }>({
api: dhApi,
pallet: "ExternalValidatorsSlashes",
event: "SlashesMessageSent",
timeout: CROSS_CHAIN_TIMEOUTS.DH_TO_ETH_MS
});
if (!resultEventSlashesMessageSent) {
throw new Error("SlashesMessageSent event not found");
}
logger.info("Slashes message sent");
}, 560000);
});

View file

@ -11,21 +11,24 @@
import { beforeAll, describe, expect, it } from "bun:test";
import { getOwnerAccount } from "launcher/validators";
import {
addValidatorToAllowlist,
CROSS_CHAIN_TIMEOUTS,
type Deployments,
getValidator,
isValidatorRunning,
launchDatahavenValidator,
logger,
parseDeploymentsFile,
registerOperator,
ZERO_ADDRESS
} from "utils";
import { waitForDataHavenEvent } from "utils/events";
import { decodeEventLog, parseEther } from "viem";
import { dataHavenServiceManagerAbi, gatewayAbi } from "../contract-bindings";
import { BaseTestSuite, type TestConnectors } from "../framework";
import { dataHavenServiceManagerAbi, gatewayAbi } from "../../contract-bindings";
import {
addValidatorToAllowlist,
BaseTestSuite,
getValidator,
isValidatorRunning,
launchDatahavenValidator,
registerOperator,
type TestConnectors
} from "../framework";
class ValidatorSetUpdateTestSuite extends BaseTestSuite {
constructor() {

View file

@ -1,42 +0,0 @@
import { secp256k1 } from "@noble/curves/secp256k1";
import { keccak_256 } from "@noble/hashes/sha3";
import type { Hex } from "viem";
/**
* Converts a compressed ECDSA public key to an Ethereum address.
* Used for converting BEEFY authorities public keys to Ethereum addresses.
*
* @param compressedPubKey - The compressed public key (33 bytes)
* @returns The Ethereum address derived from the public key
*/
export const compressedPubKeyToEthereumAddress = (compressedPubKey: Hex): Hex => {
// Remove 0x prefix if present
const pubKeyBytes = compressedPubKey.startsWith("0x")
? compressedPubKey.slice(2)
: compressedPubKey;
// Convert hex string to Uint8Array
const matches = pubKeyBytes.match(/.{1,2}/g);
if (!matches) {
throw new Error("Invalid hex string format");
}
const compressedBytes = new Uint8Array(matches.map((byte) => Number.parseInt(byte, 16)));
// Get the uncompressed point
const point = secp256k1.ProjectivePoint.fromHex(compressedBytes);
const uncompressedBytes = point.toRawBytes(false); // false = uncompressed
// Remove the first byte (0x04) which indicates uncompressed format
const publicKeyBytes = uncompressedBytes.slice(1);
// Keccak256 hash of the public key
const hash = keccak_256(publicKeyBytes);
// Take the last 20 bytes as the Ethereum address
const address = hash.slice(-20);
// Convert to hex string with 0x prefix
return `0x${Array.from(address)
.map((b) => b.toString(16).padStart(2, "0"))
.join("")}` as Hex;
};

View file

@ -1,3 +1,2 @@
export * from "./checks";
export * from "./constants";
export * from "./crypto";

View file

@ -6,11 +6,11 @@
"environments": [
{
"name": "dev_datahaven",
"testFileDir": ["datahaven/suites/dev"],
"testFileDir": ["moonwall/suites/dev"],
"include": ["**/*test*.ts"],
"timeout": 180000,
"multiThreads": false,
"contracts": "datahaven/contracts/",
"contracts": "moonwall/contracts/",
"runScripts": ["compile-contracts.sh compile"],
"envVars": ["DEBUG_COLORS=1"],
"reporters": ["basic", "html", "json"],

Some files were not shown because too many files have changed in this diff Show more