Merge branch 'main' into feat/add-validator-submitter-ci-job

This commit is contained in:
Ahmad Kaouk 2026-03-09 14:37:40 +01:00 committed by GitHub
commit 6971df2ee1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 115 additions and 102 deletions

View file

@ -35,7 +35,7 @@
"randaoCommitExpiration": 24,
"minNumRequiredSignatures": 2,
"startBlock": 1,
"rewardsMessageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000",
"messageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000",
"initialValidatorSetId": 0,
"initialValidatorHashes": [
"0xaeb47a269393297f4b0a3c9c9cfd00c7a4195255274cf39d83dabc2fcc9ff3d7",

View file

@ -99,9 +99,9 @@
/// Initial BEEFY block number. Set to latest finalized block by update-beefy-checkpoint.
/// The BeefyClient will only accept BEEFY commitments with block numbers > startBlock.
"startBlock": 1,
/// The origin linked to the Rewards Agent, the Agent contract who's allowed to submit
/// new reward merkle roots to the RewardsRegistry contract.
"rewardsMessageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000",
/// The origin linked to the Agent, the Agent contract who's allowed to submit
/// new reward merkle roots or slashes.
"messageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000",
/// The BEEFY validator set ID for the initial validators.
/// This is fetched from Beefy.ValidatorSetId on the DataHaven chain.
"initialValidatorSetId": 0,

View file

@ -43,7 +43,7 @@
"randaoCommitExpiration": 24,
"minNumRequiredSignatures": 16,
"startBlock": 1,
"rewardsMessageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000",
"messageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000",
"initialValidatorSetId": 0,
"initialValidatorHashes": [],
"nextValidatorSetId": 1,

View file

@ -44,7 +44,7 @@
"randaoCommitExpiration": 24,
"minNumRequiredSignatures": 3,
"startBlock": 1303065,
"rewardsMessageOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd",
"messageOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd",
"initialValidatorSetId": 2186,
"initialValidatorHashes": [
"0x07ce4f2cd558f4d4b529a3362b6ff7d616ca0893b53252dc62829b8218ea5c10",

View file

@ -44,7 +44,7 @@
"randaoCommitExpiration": 24,
"minNumRequiredSignatures": 5,
"startBlock": 1381173,
"rewardsMessageOrigin": "0xd0d6dbd1ffb401ef613f00e93cd5061ecec03ae35d2f820cd6754a5b5f020215",
"messageOrigin": "0xd0d6dbd1ffb401ef613f00e93cd5061ecec03ae35d2f820cd6754a5b5f020215",
"initialValidatorSetId": 2303,
"initialValidatorHashes": [
"0x0ec3102f334aba804c18b843e45ec874005587122a1b49273b1b04d6fd98b1a2",

View file

@ -0,0 +1 @@
{"Agent": "0xac06641381166cf085281c45292147f833C622d7","AgentOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000"}

View file

@ -1 +1 @@
{"RewardsAgent": "0xac06641381166cf085281c45292147f833C622d7","RewardsAgentOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000"}
{"RewardsAgent": "0xac06641381166cf085281c45292147f833C622d7","AgentOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000"}

View file

@ -1 +1 @@
{"RewardsAgent": "0x2E039a88838241d1Ac738cf2e3C5763ba12571e7","RewardsAgentOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd"}
{"RewardsAgent": "0x2E039a88838241d1Ac738cf2e3C5763ba12571e7","AgentOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd"}

View file

@ -12,7 +12,7 @@ contract Config {
bytes32[] initialValidatorHashes;
uint128 nextValidatorSetId;
bytes32[] nextValidatorHashes;
bytes32 rewardsMessageOrigin;
bytes32 messageOrigin;
}
// AVS parameters

View file

@ -123,7 +123,7 @@ abstract contract DeployBase is Script, DeployParams, Accounts {
BeefyClient beefyClient,
AgentExecutor agentExecutor,
IGatewayV2 gateway,
address payable rewardsAgentAddress
address payable agentAddress
) = _deploySnowbridge(snowbridgeConfig);
Logging.logFooter();
_logProgress();
@ -132,14 +132,14 @@ abstract contract DeployBase is Script, DeployParams, Accounts {
(
DataHavenServiceManager serviceManager,
DataHavenServiceManager serviceManagerImplementation
) = _deployDataHavenContracts(avsConfig, proxyAdmin, gateway);
) = _deployDataHavenContracts(avsConfig, proxyAdmin, gateway, agentAddress);
Logging.logFooter();
_logProgress();
// Final configuration (same for both modes)
Logging.logHeader("FINAL CONFIGURATION");
Logging.logContractDeployed("Rewards Agent Address", rewardsAgentAddress);
Logging.logContractDeployed("Agent Address", agentAddress);
Logging.logFooter();
_logProgress();
@ -150,11 +150,11 @@ abstract contract DeployBase is Script, DeployParams, Accounts {
gateway,
serviceManager,
serviceManagerImplementation,
rewardsAgentAddress,
agentAddress,
proxyAdmin
);
_outputRewardsAgentInfo(rewardsAgentAddress, snowbridgeConfig.rewardsMessageOrigin);
_outputAgentInfo(agentAddress, snowbridgeConfig.messageOrigin);
}
/**
@ -201,11 +201,11 @@ abstract contract DeployBase is Script, DeployParams, Accounts {
// Create Agent
Logging.logSection("Creating Snowbridge Agent");
vm.broadcast(_deployerPrivateKey);
gateway.v2_createAgent(config.rewardsMessageOrigin);
address payable rewardsAgentAddress = payable(gateway.agentOf(config.rewardsMessageOrigin));
Logging.logContractDeployed("Rewards Agent", rewardsAgentAddress);
gateway.v2_createAgent(config.messageOrigin);
address payable agentAddress = payable(gateway.agentOf(config.messageOrigin));
Logging.logContractDeployed("Rewards Agent", agentAddress);
return (beefyClient, agentExecutor, gateway, rewardsAgentAddress);
return (beefyClient, agentExecutor, gateway, agentAddress);
}
/**
@ -240,7 +240,8 @@ abstract contract DeployBase is Script, DeployParams, Accounts {
function _deployDataHavenContracts(
AVSConfig memory avsConfig,
ProxyAdmin proxyAdmin,
IGatewayV2 gateway
IGatewayV2 gateway,
address agentAddress
) internal returns (DataHavenServiceManager, DataHavenServiceManager) {
Logging.logHeader("DATAHAVEN CUSTOM CONTRACTS DEPLOYMENT");
@ -269,7 +270,7 @@ abstract contract DeployBase is Script, DeployParams, Accounts {
// Create service manager initialisation parameters struct
ServiceManagerInitParams memory initParams = ServiceManagerInitParams({
avsOwner: avsConfig.avsOwner,
rewardsInitiator: avsConfig.rewardsInitiator,
rewardsInitiator: agentAddress,
validatorsStrategiesAndMultipliers: strategiesAndMultipliers,
gateway: address(gateway),
validatorSetSubmitter: avsConfig.validatorSetSubmitter,
@ -313,38 +314,38 @@ abstract contract DeployBase is Script, DeployParams, Accounts {
IGatewayV2 gateway,
DataHavenServiceManager serviceManager,
DataHavenServiceManager serviceManagerImplementation,
address rewardsAgent,
address agent,
ProxyAdmin proxyAdmin
) internal virtual;
/**
* @notice Output rewards agent info (shared across all deployment types)
* @notice Output agent info (shared across all deployment types)
*/
function _outputRewardsAgentInfo(
address rewardsAgent,
bytes32 rewardsAgentOrigin
function _outputAgentInfo(
address agent,
bytes32 agentOrigin
) internal {
Logging.logHeader("REWARDS AGENT INFO");
Logging.logContractDeployed("RewardsAgent", rewardsAgent);
Logging.logAgentOrigin("RewardsAgentOrigin", vm.toString(rewardsAgentOrigin));
Logging.logHeader("AGENT INFO");
Logging.logContractDeployed("Agent", agent);
Logging.logAgentOrigin("AgentOrigin", vm.toString(agentOrigin));
Logging.logFooter();
// Write to deployment file for future reference
string memory network = _getNetworkName();
string memory rewardsInfoPath =
string.concat(vm.projectRoot(), "/deployments/", network, "-rewards-info.json");
string memory agentInfoPath =
string.concat(vm.projectRoot(), "/deployments/", network, "-agent-info.json");
// Create directory if it doesn't exist
vm.createDir(string.concat(vm.projectRoot(), "/deployments"), true);
// Create JSON with rewards info
string memory json = "{";
json = string.concat(json, '"RewardsAgent": "', vm.toString(rewardsAgent), '",');
json = string.concat(json, '"RewardsAgentOrigin": "', vm.toString(rewardsAgentOrigin), '"');
json = string.concat(json, '"Agent": "', vm.toString(agent), '",');
json = string.concat(json, '"AgentOrigin": "', vm.toString(agentOrigin), '"');
json = string.concat(json, "}");
// Write to file
vm.writeFile(rewardsInfoPath, json);
Logging.logInfo(string.concat("Rewards info saved to: ", rewardsInfoPath));
vm.writeFile(agentInfoPath, json);
Logging.logInfo(string.concat("Agent info saved to: ", agentInfoPath));
}
}

View file

@ -24,8 +24,7 @@ contract DeployParams is Script, Config {
config.minNumRequiredSignatures =
vm.parseJsonUint(configJson, ".snowbridge.minNumRequiredSignatures");
config.startBlock = vm.parseJsonUint(configJson, ".snowbridge.startBlock").toUint64();
config.rewardsMessageOrigin =
vm.parseJsonBytes32(configJson, ".snowbridge.rewardsMessageOrigin");
config.messageOrigin = vm.parseJsonBytes32(configJson, ".snowbridge.messageOrigin");
// Load validators from file or generate placeholder ones in dev mode
bool isDevMode = keccak256(abi.encodePacked(vm.envOr("DEV_MODE", string("false"))))

View file

@ -1518,7 +1518,7 @@ impl datahaven_runtime_common::rewards_adapter::RewardsSubmissionConfig for Main
}
fn rewards_agent_origin() -> H256 {
runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get()
runtime_params::dynamic_params::runtime_config::AgentOrigin::get()
}
fn strategies_and_multipliers() -> Vec<(H160, u128)> {
@ -1692,9 +1692,9 @@ impl datahaven_runtime_common::slashes_adapter::SlashesSubmissionConfig for Main
runtime_params::dynamic_params::runtime_config::DatahavenServiceManagerAddress::get()
}
// TODO: remove `slashes_` prefix and just call it `agent_origin`
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` ?
runtime_params::dynamic_params::runtime_config::AgentOrigin::get()
}
fn strategies() -> Vec<Address> {

View file

@ -48,9 +48,9 @@ pub mod dynamic_params {
#[codec(index = 3)]
#[allow(non_upper_case_globals)]
/// The RewardsAgentOrigin is the hash of the string "external_validators_rewards"
/// The AgentOrigin is the hash of the string "external_validators_rewards"
/// TODO: Decide which agent origin we want to use. Currently for testing it's the zero hash
pub static RewardsAgentOrigin: H256 = H256::from_slice(&hex!(
pub static AgentOrigin: H256 = H256::from_slice(&hex!(
"c505dfb2df107d106d08bd0f1a0acd10052ca9aa078629a4ccfd0c90c6e69b65"
));

View file

@ -1514,7 +1514,7 @@ impl datahaven_runtime_common::rewards_adapter::RewardsSubmissionConfig for Stag
}
fn rewards_agent_origin() -> H256 {
runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get()
runtime_params::dynamic_params::runtime_config::AgentOrigin::get()
}
fn strategies_and_multipliers() -> Vec<(H160, u128)> {
@ -1689,7 +1689,7 @@ impl datahaven_runtime_common::slashes_adapter::SlashesSubmissionConfig for Stag
}
fn slashes_agent_origin() -> H256 {
runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get()
runtime_params::dynamic_params::runtime_config::AgentOrigin::get()
// TODO: Can we use the same as reward and just rename the config to `AgentOrigin` ?
}
@ -1951,8 +1951,8 @@ mod tests {
/// Test that the Rewards Agent ID (used for Snowbridge outbound messages from the rewards pallet)
/// is correctly computed from the chain's genesis hash and the ExternalValidatorRewardsAccount.
///
/// This test verifies the value that should be set as `RewardsAgentOrigin` in runtime parameters
/// and as `rewardsMessageOrigin` in the AVS contract configuration.
/// This test verifies the value that should be set as `AgentOrigin` in runtime parameters
/// and as `messageOrigin` in the AVS contract configuration.
///
/// The Agent ID is computed following Snowbridge's pattern for GlobalConsensus locations:
/// blake2_256(SCALE_ENCODE("GlobalConsensus", ByGenesis(genesis_hash), compact_len, "AccountKey20", account_key))
@ -1992,8 +1992,8 @@ mod tests {
// Hash with blake2_256
let computed_agent_id = H256(blake2_256(&encoded));
// Expected Agent ID - this value must match RewardsAgentOrigin in runtime_params.rs
// If this test fails, update RewardsAgentOrigin to match the computed value.
// Expected Agent ID - this value must match AgentOrigin in runtime_params.rs
// If this test fails, update AgentOrigin to match the computed value.
let expected_agent_id = H256(hex_literal::hex!(
"56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd"
));
@ -2003,8 +2003,8 @@ mod tests {
expected_agent_id,
"Computed Rewards Agent ID must match expected value.\n\
This value should be set as:\n\
- RewardsAgentOrigin in runtime_params.rs\n\
- rewardsMessageOrigin in AVS contract config\n\
- AgentOrigin in runtime_params.rs\n\
- messageOrigin in AVS contract config\n\
\n\
Rewards account: 0x{}\n\
Genesis hash: 0x{}\n\

View file

@ -51,13 +51,13 @@ pub mod dynamic_params {
#[codec(index = 3)]
#[allow(non_upper_case_globals)]
/// The RewardsAgentOrigin is the Agent ID for the rewards pallet's outbound Snowbridge messages.
/// The AgentOrigin is the Agent ID for the rewards/slashes pallet's outbound Snowbridge messages.
/// Computed as: blake2_256(SCALE_ENCODE("GlobalConsensus", ByGenesis(genesis_hash), interior))
/// where interior = SCALE_ENCODE("AccountKey20", ExternalValidatorRewardsAccount)
///
/// For stagenet with genesis hash 0x72d0856fd339e09cb21df7bac8ac3120bd871e327ec0e1658395df68acef9bee
/// and rewards account 0x6d6f646c64682f65767265770000000000000000 (from PalletId "dh/evrew"):
pub static RewardsAgentOrigin: H256 = H256::from_slice(&hex!(
pub static AgentOrigin: H256 = H256::from_slice(&hex!(
"56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd"
));

View file

@ -1518,7 +1518,7 @@ impl datahaven_runtime_common::rewards_adapter::RewardsSubmissionConfig for Test
}
fn rewards_agent_origin() -> H256 {
runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get()
runtime_params::dynamic_params::runtime_config::AgentOrigin::get()
}
fn strategies_and_multipliers() -> Vec<(H160, u128)> {
@ -1693,8 +1693,7 @@ impl datahaven_runtime_common::slashes_adapter::SlashesSubmissionConfig for Test
}
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` ?
runtime_params::dynamic_params::runtime_config::AgentOrigin::get()
}
fn strategies() -> Vec<Address> {
@ -1973,8 +1972,8 @@ mod tests {
/// Test that the Rewards Agent ID (used for Snowbridge outbound messages from the rewards pallet)
/// is correctly computed from the chain's genesis hash and the ExternalValidatorRewardsAccount.
///
/// This test verifies the value that should be set as `RewardsAgentOrigin` in runtime parameters
/// and as `rewardsMessageOrigin` in the AVS contract configuration.
/// This test verifies the value that should be set as `AgentOrigin` in runtime parameters
/// and as `messageOrigin` in the AVS contract configuration.
///
/// The Agent ID is computed following Snowbridge's pattern for GlobalConsensus locations:
/// blake2_256(SCALE_ENCODE("GlobalConsensus", ByGenesis(genesis_hash), compact_len, "AccountKey20", account_key))
@ -2014,8 +2013,8 @@ mod tests {
// Hash with blake2_256
let computed_agent_id = H256(blake2_256(&encoded));
// Expected Agent ID - this value must match RewardsAgentOrigin in runtime_params.rs
// If this test fails, update RewardsAgentOrigin to match the computed value.
// Expected Agent ID - this value must match AgentOrigin in runtime_params.rs
// If this test fails, update AgentOrigin to match the computed value.
let expected_agent_id = H256(hex_literal::hex!(
"d0d6dbd1ffb401ef613f00e93cd5061ecec03ae35d2f820cd6754a5b5f020215"
));
@ -2025,8 +2024,8 @@ mod tests {
expected_agent_id,
"Computed Rewards Agent ID must match expected value.\n\
This value should be set as:\n\
- RewardsAgentOrigin in runtime_params.rs\n\
- rewardsMessageOrigin in AVS contract config\n\
- AgentOrigin in runtime_params.rs\n\
- messageOrigin in AVS contract config\n\
\n\
Rewards account: 0x{}\n\
Genesis hash: 0x{}\n\

View file

@ -49,13 +49,13 @@ pub mod dynamic_params {
#[codec(index = 3)]
#[allow(non_upper_case_globals)]
/// The RewardsAgentOrigin is the Agent ID for the rewards pallet's outbound Snowbridge messages.
/// The AgentOrigin is the Agent ID for the rewards/slashes pallet's outbound Snowbridge messages.
/// Computed as: blake2_256(SCALE_ENCODE("GlobalConsensus", ByGenesis(genesis_hash), interior))
/// where interior = SCALE_ENCODE("AccountKey20", ExternalValidatorRewardsAccount)
///
/// For testnet with genesis hash 0xdbf403d348916fb0694485bc7f9c0d8c53fdf86664ebac019af209c090c3df99
/// and rewards account 0x6d6f646c64682f65767265770000000000000000 (from PalletId "dh/evrew"):
pub static RewardsAgentOrigin: H256 = H256::from_slice(&hex!(
pub static AgentOrigin: H256 = H256::from_slice(&hex!(
"d0d6dbd1ffb401ef613f00e93cd5061ecec03ae35d2f820cd6754a5b5f020215"
));

View file

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

Binary file not shown.

View file

@ -48,7 +48,7 @@ const palletIdToAccountId20 = (palletId: string): Hex => {
* blake2_256(SCALE_ENCODE(("GlobalConsensus", ByGenesis(genesis_hash), ("AccountKey20", account_key))))
*
* NOTE: This computation follows Snowbridge's pattern but may need verification against
* the actual on-chain Agent ID. The preferred approach is to set RewardsAgentOrigin on
* the actual on-chain Agent ID. The preferred approach is to set AgentOrigin on
* the chain and fetch it via this command.
*
* @param genesisHash - The chain's genesis hash (32 bytes, hex string with 0x prefix)
@ -116,36 +116,36 @@ const computeAgentId = async (genesisHash: Hex, accountKey20: Hex): Promise<Hex>
};
/**
* Fetches the RewardsAgentOrigin from the runtime parameters.
* Fetches the AgentOrigin from the runtime parameters.
*
* @param rpcUrl - WebSocket RPC endpoint of the DataHaven chain
* @returns The RewardsAgentOrigin as a hex string, or null if not set or zero
* @returns The AgentOrigin as a hex string, or null if not set or zero
*/
const fetchRewardsAgentOrigin = async (rpcUrl: string): Promise<Hex | null> => {
const fetchAgentOrigin = async (rpcUrl: string): Promise<Hex | null> => {
logger.info(`📡 Connecting to DataHaven chain at ${rpcUrl}...`);
const { client: papiClient, typedApi: dhApi } = createPapiConnectors(rpcUrl);
try {
logger.info("🔍 Fetching RewardsAgentOrigin from runtime parameters...");
logger.info("🔍 Fetching AgentOrigin from runtime parameters...");
// Query the Parameters pallet for RewardsAgentOrigin
// Query the Parameters pallet for AgentOrigin
const parameter = await dhApi.query.Parameters.Parameters.getValue(
{
type: "RuntimeConfig",
value: { type: "RewardsAgentOrigin", value: undefined }
value: { type: "AgentOrigin", value: undefined }
},
{ at: "best" }
);
if (!parameter) {
logger.info(" RewardsAgentOrigin parameter not found (using default)");
logger.info(" AgentOrigin parameter not found (using default)");
return null;
}
// Extract the value from the parameter result
// The parameter is wrapped in the RuntimeConfig enum variant
if (parameter.type === "RuntimeConfig" && parameter.value.type === "RewardsAgentOrigin") {
if (parameter.type === "RuntimeConfig" && parameter.value.type === "AgentOrigin") {
const origin = parameter.value.value;
if (origin) {
const originHex = origin.asHex();
@ -153,15 +153,15 @@ const fetchRewardsAgentOrigin = async (rpcUrl: string): Promise<Hex | null> => {
const zeroHash =
"0x0000000000000000000000000000000000000000000000000000000000000000" as Hex;
if (originHex === zeroHash) {
logger.info(" RewardsAgentOrigin is set to zero (placeholder)");
logger.info(" AgentOrigin is set to zero (placeholder)");
return null;
}
logger.success(`Found RewardsAgentOrigin: ${originHex}`);
logger.success(`Found AgentOrigin: ${originHex}`);
return originHex as Hex;
}
}
logger.info(" RewardsAgentOrigin value not available");
logger.info(" AgentOrigin value not available");
return null;
} finally {
papiClient.destroy();
@ -193,9 +193,9 @@ const fetchGenesisHash = async (rpcUrl: string): Promise<Hex> => {
* Updates the config file with the rewards message origin.
*
* @param networkId - The network identifier (e.g., "hoodi", "stagenet-hoodi")
* @param rewardsMessageOrigin - The rewards message origin (Agent ID)
* @param messageOrigin - The rewards message origin (Agent ID)
*/
const updateConfigFile = async (networkId: string, rewardsMessageOrigin: Hex): Promise<void> => {
const updateConfigFile = async (networkId: string, messageOrigin: Hex): Promise<void> => {
const configFilePath = `../contracts/config/${networkId}.json`;
const configFile = Bun.file(configFilePath);
@ -211,21 +211,21 @@ const updateConfigFile = async (networkId: string, rewardsMessageOrigin: Hex): P
configJson.snowbridge = {};
}
const oldOrigin = configJson.snowbridge.rewardsMessageOrigin;
configJson.snowbridge.rewardsMessageOrigin = rewardsMessageOrigin;
const oldOrigin = configJson.snowbridge.messageOrigin;
configJson.snowbridge.messageOrigin = messageOrigin;
await Bun.write(configFilePath, `${JSON.stringify(configJson, null, 2)}\n`);
logger.success(`Config file updated: ${configFilePath}`);
if (oldOrigin !== rewardsMessageOrigin) {
logger.info(` rewardsMessageOrigin: ${oldOrigin ?? "unset"} -> ${rewardsMessageOrigin}`);
if (oldOrigin !== messageOrigin) {
logger.info(` messageOrigin: ${oldOrigin ?? "unset"} -> ${messageOrigin}`);
}
};
/**
* Main handler for the update-rewards-origin command.
* Fetches or computes the RewardsAgentOrigin and updates the config file.
* Fetches or computes the AgentOrigin and updates the config file.
*/
export const updateRewardsOrigin = async (options: UpdateRewardsOriginOptions): Promise<void> => {
const networkId = buildNetworkId(options.chain, options.environment);
@ -246,17 +246,17 @@ export const updateRewardsOrigin = async (options: UpdateRewardsOriginOptions):
printDivider();
try {
// Step 1: Try to fetch RewardsAgentOrigin from the chain
let rewardsMessageOrigin = await fetchRewardsAgentOrigin(options.rpcUrl);
// Step 1: Try to fetch AgentOrigin from the chain
let messageOrigin = await fetchAgentOrigin(options.rpcUrl);
printDivider();
if (rewardsMessageOrigin) {
if (messageOrigin) {
// Use the value from the chain
logger.info("✅ Using RewardsAgentOrigin from chain runtime parameters");
logger.info("✅ Using AgentOrigin from chain runtime parameters");
} else {
// Compute the Agent ID from genesis hash and pallet account
logger.info("🔧 Computing RewardsAgentOrigin from genesis hash and pallet account...");
logger.info("🔧 Computing AgentOrigin from genesis hash and pallet account...");
// Get genesis hash (from option or fetch from chain)
const genesisHash = options.genesisHash
@ -272,22 +272,22 @@ export const updateRewardsOrigin = async (options: UpdateRewardsOriginOptions):
// Compute the Agent ID
logger.info("🔐 Computing Agent ID...");
logger.warn(
"⚠️ Note: Computed Agent ID may need verification. Prefer setting RewardsAgentOrigin on-chain."
"⚠️ Note: Computed Agent ID may need verification. Prefer setting AgentOrigin on-chain."
);
rewardsMessageOrigin = await computeAgentId(genesisHash, rewardsAccount);
logger.info(` Agent ID: ${rewardsMessageOrigin}`);
messageOrigin = await computeAgentId(genesisHash, rewardsAccount);
logger.info(` Agent ID: ${messageOrigin}`);
}
printDivider();
// Display the final value
logger.info("📝 Rewards Message Origin:");
logger.info(` ${rewardsMessageOrigin}`);
logger.info(` ${messageOrigin}`);
printDivider();
// Update the config file
await updateConfigFile(networkId, rewardsMessageOrigin);
await updateConfigFile(networkId, messageOrigin);
printDivider();
logger.success(`Rewards message origin updated successfully for ${networkId}`);

View file

@ -212,7 +212,7 @@ const contractsCommand = program
- upgrade: Upgrade contracts by deploying new implementations
- verify: Verify deployed contracts on block explorer
- update-beefy-checkpoint: Fetch BEEFY authorities from a live chain and update config
- update-rewards-origin: Fetch or compute the RewardsAgentOrigin and update config
- update-rewards-origin: Fetch or compute the AgentOrigin and update config
- update-metadata: Update the metadata URI of an existing AVS contract
Common options:
@ -385,17 +385,14 @@ contractsCommand
contractsCommand
.command("update-rewards-origin")
.description(
"Fetch or compute the RewardsAgentOrigin and update the config file with the rewards message origin"
"Fetch or compute the AgentOrigin and update the config file with the rewards message origin"
)
.option("--chain <value>", "Target chain (hoodi, ethereum, anvil)")
.option(
"--environment <value>",
"Deployment environment (stagenet, testnet, mainnet). Config and deployment files will be prefixed with this value."
)
.option(
"--rpc-url <value>",
"WebSocket RPC URL of the DataHaven chain to fetch RewardsAgentOrigin from"
)
.option("--rpc-url <value>", "WebSocket RPC URL of the DataHaven chain to fetch AgentOrigin from")
.option(
"--genesis-hash <value>",
"Chain genesis hash (32 bytes hex). If not provided, will be fetched from the chain."

View file

@ -8,7 +8,7 @@
"value": null
},
{
"name": "RewardsAgentOrigin",
"name": "AgentOrigin",
"value": null
},
{

View file

@ -3,8 +3,9 @@ import { $ } from "bun";
import { Binary, FixedSizeBinary } from "polkadot-api";
import { CROSS_CHAIN_TIMEOUTS, getPapiSigner, logger } from "utils";
import type { Address } from "viem";
import { gatewayAbi } from "../../contract-bindings";
import { getContractInstance, parseDeploymentsFile } from "../../utils/contracts";
import { waitForDataHavenEvent } from "../../utils/events";
import { waitForDataHavenEvent, waitForEthereumEvent } from "../../utils/events";
import { waitFor } from "../../utils/waits";
import { BaseTestSuite } from "../framework";
@ -122,6 +123,8 @@ describe("Should slash an operator", () => {
}, 40000);
it("use sudo to slash operator", async () => {
const { publicClient } = suite.getTestConnectors();
// get era number
const activeEra = await dhApi.query.ExternalValidators.ActiveEra.getValue();
@ -168,6 +171,19 @@ describe("Should slash an operator", () => {
throw new Error("SlashesMessageSent event not found");
}
logger.info("Slashes message sent");
const fromBlock = await publicClient.getBlockNumber();
const deployments = await parseDeploymentsFile();
const _ethEvent = await waitForEthereumEvent({
client: publicClient,
address: deployments.Gateway,
abi: gatewayAbi,
eventName: "SlashingComplete",
fromBlock: fromBlock > 0n ? fromBlock - 1n : fromBlock,
timeout: CROSS_CHAIN_TIMEOUTS.DH_TO_ETH_MS
});
logger.info("Got Ethereum event!");
}, 560000);
it("should detect and slash an unresponsive validator (liveness)", async () => {

View file

@ -184,7 +184,7 @@ export const parseJsonToBeaconCheckpoint = (jsonInput: any): BeaconCheckpoint =>
const DATAHAVEN_PARAM_NAMES = [
"EthereumGatewayAddress",
"RewardsUpdateSelector",
"RewardsAgentOrigin",
"AgentOrigin",
"DatahavenServiceManagerAddress"
] as const;