From 925a4146a924fe22ed0f2f7e42c2be6ec2c1fccb Mon Sep 17 00:00:00 2001 From: WillQ Date: Wed, 7 May 2025 13:24:16 +0800 Subject: [PATCH 1/3] update urc --- lib/urc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/urc b/lib/urc index e0c5c8a..5f18225 160000 --- a/lib/urc +++ b/lib/urc @@ -1 +1 @@ -Subproject commit e0c5c8a8212a04e8844df0268c7de17b9e6b8896 +Subproject commit 5f18225c4d027b49084605129b7666a37ea13412 From a023a80b307fde79e7702e8ef0f1e551fa6379e5 Mon Sep 17 00:00:00 2001 From: WillQ Date: Wed, 7 May 2025 13:24:33 +0800 Subject: [PATCH 2/3] fix test --- src/libs/SlashingLib.sol | 2 +- src/slasher/LinglongSlasher.sol | 11 +++++------ test/EigenLayerMiddleware.t.sol | 2 +- test/SymbioticMiddleware.t.sol | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/libs/SlashingLib.sol b/src/libs/SlashingLib.sol index 7e45dac..739bed5 100644 --- a/src/libs/SlashingLib.sol +++ b/src/libs/SlashingLib.sol @@ -305,7 +305,7 @@ library SlashingLib { revert OperatorUnregistered(); } - if (registeredAt + registry.getConfig().fraudProofWindow > block.number) { + if (registeredAt + registry.getConfig().fraudProofWindow > block.timestamp) { revert OperatorFraudProofPeriodNotOver(); } } diff --git a/src/slasher/LinglongSlasher.sol b/src/slasher/LinglongSlasher.sol index 26c2131..f39a829 100644 --- a/src/slasher/LinglongSlasher.sol +++ b/src/slasher/LinglongSlasher.sol @@ -212,10 +212,11 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt /// @inheritdoc ISlasher function slash( - ISlasher.Delegation calldata, /* delegation */ - ISlasher.Commitment calldata, /* commitment */ - bytes calldata, /* evidence */ - address /* challenger */ + Delegation calldata delegation, + Commitment calldata commitment, + address committer, + bytes calldata evidence, + address challenger ) external pure @@ -284,7 +285,6 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt } } - /// @inheritdoc ISlasher /// @notice Slash an operator for a given commitment /// @dev The URC Registry will call this function to slash a registered operator if supplied with a valid commitment and evidence /// @param commitment The commitment message @@ -296,7 +296,6 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt address /* challenger */ ) external - override onlyInitialized onlyURC returns (uint256 slashAmountGwei) diff --git a/test/EigenLayerMiddleware.t.sol b/test/EigenLayerMiddleware.t.sol index 8dc7966..672f292 100644 --- a/test/EigenLayerMiddleware.t.sol +++ b/test/EigenLayerMiddleware.t.sol @@ -986,7 +986,7 @@ contract EigenlayerMiddlewareTest is Test, G2Operations { vm.startPrank(primaryOp); // Wait for the fraud proof window to pass - vm.roll(block.number + 100 days); + vm.warp(block.timestamp + 3 hours); // Call optInToSlasher function with the registration root middleware.optInToSlasher( diff --git a/test/SymbioticMiddleware.t.sol b/test/SymbioticMiddleware.t.sol index 5474c63..38fa258 100644 --- a/test/SymbioticMiddleware.t.sol +++ b/test/SymbioticMiddleware.t.sol @@ -238,7 +238,7 @@ contract SymbioticMiddlewareTest is POCBaseTest { data[1] = abi.encode("validator-2-metadata"); // Wait for fraud proof window - vm.roll(block.number + 100 days); + vm.warp(block.timestamp + 3 hours); // Call middleware's optInToSlasher vm.startPrank(operator); From ca232ad988c6e865599bf2dbff0f46e286bb5afd Mon Sep 17 00:00:00 2001 From: WillQ Date: Thu, 8 May 2025 11:58:06 +0800 Subject: [PATCH 3/3] fix slasher implementation --- script/Deployments.s.sol | 1 + src/slasher/LinglongSlasher.sol | 116 +++++++++++++++--------------- test/EigenLayerMiddleware.t.sol | 1 + test/utils/EigenlayerDeployer.sol | 2 +- test/utils/MockChallenger.sol | 2 +- 5 files changed, 62 insertions(+), 60 deletions(-) diff --git a/script/Deployments.s.sol b/script/Deployments.s.sol index e8ab315..c8c1b71 100644 --- a/script/Deployments.s.sol +++ b/script/Deployments.s.sol @@ -375,6 +375,7 @@ contract Deploy is Script, Test { Registry registry = new Registry(registryConfig); emit log_address(address(registry)); urc = address(registry); + vm.serializeAddress(taiyiAddresses, "urc", address(registry)); } function setupHoleskyAddresses() internal { diff --git a/src/slasher/LinglongSlasher.sol b/src/slasher/LinglongSlasher.sol index f39a829..1f64121 100644 --- a/src/slasher/LinglongSlasher.sol +++ b/src/slasher/LinglongSlasher.sol @@ -57,6 +57,16 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt error SlashingInProgress(); error NotURC(); + /// @dev Struct to hold slashing parameters + struct SlashingParams { + bytes32 commitmentHash; + bytes32 violationType; + address challengerContract; + address operator; + address middleware; + ITaiyiRegistryCoordinator.RestakingProtocol protocol; + } + /// @notice Constructor - disabled for upgradeable pattern constructor() { _disableInitializers(); @@ -210,6 +220,33 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt return challengerImpls[challenger].violationType; } + /// @dev Helper function to validate and prepare slashing parameters + function _prepareSlashingParams( + Delegation calldata delegation, + Commitment calldata commitment, + bytes calldata evidence + ) + internal + view + returns (SlashingParams memory params) + { + params.commitmentHash = keccak256(abi.encode(commitment, evidence)); + if (slashedCommitments[params.commitmentHash]) revert AlreadySlashed(); + if (commitment.slasher != address(this)) revert InvalidSlasher(); + + params.violationType = URCCommitmentTypeToViolationType[commitment.commitmentType]; + params.challengerContract = violationTypeChallengers[params.violationType]; + params.operator = _extractOperatorFromCommitment(commitment); + params.middleware = _findMiddleware(params.operator); + + if (params.middleware == address(0)) { + revert OperatorNotInSet(params.operator, 0); + } + + params.protocol = ITaiyiRegistryCoordinator(TAIYI_REGISTRY_COORDINATOR) + .getMiddlewareProtocol(params.middleware); + } + /// @inheritdoc ISlasher function slash( Delegation calldata delegation, @@ -219,12 +256,30 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt address challenger ) external - pure override returns (uint256 /* slashAmountGwei */ ) { - // This method is required by ISlasher but not used - revert MethodNotSupported(); + SlashingParams memory params = + _prepareSlashingParams(delegation, commitment, evidence); + + // Execute slashing based on protocol + bool executed = _executeSlashingByProtocol( + params.operator, + params.middleware, + params.challengerContract, + commitment.payload, + params.protocol + ); + + // If direct execution is requested, execute the slashing + if (executed) { + slashedCommitments[params.commitmentHash] = true; + emit SlashingResult(params.operator, true); + } + + // Always return 0 for slashAmountGwei + // This is because collateral management is handled by EigenLayer/Symbiotic + return 0; } /// @dev Helper function to find middleware for an operator @@ -285,61 +340,6 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt } } - /// @notice Slash an operator for a given commitment - /// @dev The URC Registry will call this function to slash a registered operator if supplied with a valid commitment and evidence - /// @param commitment The commitment message - /// @param evidence Arbitrary evidence for the slashing - /// @return slashAmountGwei The amount of Gwei slashed (always 0 for Taiyi, as EigenLayer handles actual slashing) - function slashFromOptIn( - ISlasher.Commitment calldata commitment, - bytes calldata evidence, - address /* challenger */ - ) - external - onlyInitialized - onlyURC - returns (uint256 slashAmountGwei) - { - // Prevent double slashing by tracking the commitment hash - bytes32 commitmentHash = keccak256(abi.encode(commitment, evidence)); - if (slashedCommitments[commitmentHash]) revert AlreadySlashed(); - if (commitment.slasher != address(this)) revert InvalidSlasher(); - - // Get violation type and challenger contract - bytes32 violationType = - URCCommitmentTypeToViolationType[commitment.commitmentType]; - address challengerContract = violationTypeChallengers[violationType]; - - // Extract operator from commitment - address operator = _extractOperatorFromCommitment(commitment); - - // Find the middleware address for this operator - address middleware = _findMiddleware(operator); - if (middleware == address(0)) { - revert OperatorNotInSet(operator, 0); - } - - // Check which protocol the middleware belongs to - ITaiyiRegistryCoordinator.RestakingProtocol protocol = ITaiyiRegistryCoordinator( - TAIYI_REGISTRY_COORDINATOR - ).getMiddlewareProtocol(middleware); - - // Execute slashing based on protocol - bool executed = _executeSlashingByProtocol( - operator, middleware, challengerContract, commitment.payload, protocol - ); - - // If direct execution is requested, execute the slashing - if (executed) { - slashedCommitments[commitmentHash] = true; - emit SlashingResult(operator, true); - } - - // Always return 0 for slashAmountGwei - // This is because collateral management is handled by EigenLayer/Symbiotic - return 0; - } - /// @dev Extract the operator address from a commitment /// @param commitment The commitment to extract from /// @return operator The extracted operator address diff --git a/test/EigenLayerMiddleware.t.sol b/test/EigenLayerMiddleware.t.sol index 672f292..e58bc1b 100644 --- a/test/EigenLayerMiddleware.t.sol +++ b/test/EigenLayerMiddleware.t.sol @@ -258,6 +258,7 @@ contract EigenlayerMiddlewareTest is Test, G2Operations { slasher.setTaiyiRegistryCoordinator(address(registryCoordinator)); vm.stopPrank(); + vm.roll(uint256(eigenLayerDeployer.MIN_WITHDRAWAL_DELAY() + 1000)); // Perform the slashing via the Registry uint256 slashAmount = registry.slashCommitment(registrationRoot, commitment, evidence); diff --git a/test/utils/EigenlayerDeployer.sol b/test/utils/EigenlayerDeployer.sol index cda97b5..472e979 100644 --- a/test/utils/EigenlayerDeployer.sol +++ b/test/utils/EigenlayerDeployer.sol @@ -108,7 +108,7 @@ contract EigenlayerDeployer is Operators { uint256 REQUIRED_BALANCE_WEI = 32 ether; uint64 MAX_PARTIAL_WTIHDRAWAL_AMOUNT_GWEI = 1 ether / 1e9; uint64 GOERLI_GENESIS_TIME = 1_616_508_000; - uint32 MIN_WITHDRAWAL_DELAY = 86_400; + uint32 public MIN_WITHDRAWAL_DELAY = 86_400; address pauser; address unpauser; diff --git a/test/utils/MockChallenger.sol b/test/utils/MockChallenger.sol index a8dc068..20ab6a2 100644 --- a/test/utils/MockChallenger.sol +++ b/test/utils/MockChallenger.sol @@ -54,7 +54,7 @@ contract MockLinglongChallenger is ILinglongChallenger { } function getSlashAmount() external pure returns (uint256) { - return 1 ether; + return 1e18; // 100 WAD percent } function verifyProof(bytes memory) external pure returns (VerificationStatus) {