@@ -730,6 +730,159 @@ describe("SSVNetwork Integration - Staking (Enhanced)", () => {
730730 } ) ;
731731 } ) ;
732732
733+ describe ( "Explicit EB staking revenue checks" , async function ( ) {
734+ it ( "liquidating an explicit EB=64 cluster stops further staking revenue accrual" , async function ( ) {
735+ const { network, views, ssvToken } = await networkHelpers . loadFixture ( deployFullSSVNetworkFixture ) ;
736+
737+ await ssvToken . mint ( staker . address , STAKE_AMOUNT ) ;
738+ await ssvToken . connect ( staker ) . approve ( await network . getAddress ( ) , STAKE_AMOUNT ) ;
739+ await network . connect ( staker ) . stake ( STAKE_AMOUNT ) ;
740+
741+ const operatorIds = await registerOperators ( network , operatorOwner , 4 ) ;
742+ await whitelistAddresses ( network , operatorOwner , operatorIds , [ clusterOwner . address ] ) ;
743+ await network . connect ( clusterOwner ) . registerValidator (
744+ makePublicKey ( 9101 ) ,
745+ operatorIds ,
746+ DEFAULT_SHARES ,
747+ EMPTY_CLUSTER ,
748+ { value : DEFAULT_ETH_REGISTER_VALUE }
749+ ) ;
750+
751+ const allSigners = await connection . ethers . getSigners ( ) ;
752+ const oracles = allSigners . slice ( 10 , 14 ) ;
753+ for ( let i = 0 ; i < 4 ; i ++ ) {
754+ await network . replaceOracle ( i + 1 , oracles [ i ] . address ) ;
755+ }
756+
757+ const clusterId = computeClusterId ( clusterOwner . address , operatorIds ) ;
758+ const ebBlock = Number ( await connection . ethers . provider . getBlockNumber ( ) ) ;
759+ const { root, proofs } = generateMerkleForClusterEB ( connection , [
760+ { clusterId, effectiveBalance : 64 } ,
761+ ] ) ;
762+ await commitEBRoot ( network , root , ebBlock , oracles ) ;
763+
764+ const clusterBeforeUpdate = await getCurrentClusterState ( connection , network , clusterOwner . address , operatorIds ) ;
765+ await network . updateClusterBalance (
766+ ebBlock ,
767+ clusterOwner . address ,
768+ operatorIds . map ( ( id ) => BigInt ( id ) ) ,
769+ {
770+ validatorCount : Number ( clusterBeforeUpdate . validatorCount ) ,
771+ networkFeeIndex : BigInt ( clusterBeforeUpdate . networkFeeIndex ) ,
772+ index : BigInt ( clusterBeforeUpdate . index ) ,
773+ active : clusterBeforeUpdate . active ,
774+ balance : BigInt ( clusterBeforeUpdate . balance ) ,
775+ } ,
776+ 64 ,
777+ proofs [ clusterId ] ,
778+ ) ;
779+
780+ const earningsBefore = await views . getNetworkEarnings ( ) ;
781+ await connection . networkHelpers . mine ( 100n ) ;
782+ const earningsBeforeLiquidation = await views . getNetworkEarnings ( ) ;
783+ const preLiquidationDelta = earningsBeforeLiquidation - earningsBefore ;
784+ expect ( preLiquidationDelta ) . to . be . greaterThan ( 0n ) ;
785+
786+ const clusterBeforeLiquidation = await getCurrentClusterState ( connection , network , clusterOwner . address , operatorIds ) ;
787+ await network . connect ( clusterOwner ) . liquidate (
788+ clusterOwner . address ,
789+ operatorIds ,
790+ {
791+ validatorCount : Number ( clusterBeforeLiquidation . validatorCount ) ,
792+ networkFeeIndex : BigInt ( clusterBeforeLiquidation . networkFeeIndex ) ,
793+ index : BigInt ( clusterBeforeLiquidation . index ) ,
794+ active : clusterBeforeLiquidation . active ,
795+ balance : BigInt ( clusterBeforeLiquidation . balance ) ,
796+ } ,
797+ ) ;
798+
799+ const earningsImmediatelyAfterLiquidation = await views . getNetworkEarnings ( ) ;
800+ await connection . networkHelpers . mine ( 100n ) ;
801+ const earningsAfterLiquidation = await views . getNetworkEarnings ( ) ;
802+ const postLiquidationDelta = earningsAfterLiquidation - earningsImmediatelyAfterLiquidation ;
803+ expect ( postLiquidationDelta ) . to . equal ( 0n ) ;
804+ } ) ;
805+
806+ it ( "staking revenue doubles when explicit EB increases from 64 to 128" , async function ( ) {
807+ const { network, views, ssvToken } = await networkHelpers . loadFixture ( deployFullSSVNetworkFixture ) ;
808+
809+ await ssvToken . mint ( staker . address , STAKE_AMOUNT ) ;
810+ await ssvToken . connect ( staker ) . approve ( await network . getAddress ( ) , STAKE_AMOUNT ) ;
811+ await network . connect ( staker ) . stake ( STAKE_AMOUNT ) ;
812+
813+ const operatorIds = await registerOperators ( network , operatorOwner , 4 ) ;
814+ await whitelistAddresses ( network , operatorOwner , operatorIds , [ clusterOwner . address ] ) ;
815+ await network . connect ( clusterOwner ) . registerValidator (
816+ makePublicKey ( 9102 ) ,
817+ operatorIds ,
818+ DEFAULT_SHARES ,
819+ EMPTY_CLUSTER ,
820+ { value : DEFAULT_ETH_REGISTER_VALUE }
821+ ) ;
822+
823+ const allSigners = await connection . ethers . getSigners ( ) ;
824+ const oracles = allSigners . slice ( 10 , 14 ) ;
825+ for ( let i = 0 ; i < 4 ; i ++ ) {
826+ await network . replaceOracle ( i + 1 , oracles [ i ] . address ) ;
827+ }
828+
829+ await network . updateMinBlocksBetweenUpdates ( 1n ) ;
830+
831+ const clusterId = computeClusterId ( clusterOwner . address , operatorIds ) ;
832+ const eb64Block = Number ( await connection . ethers . provider . getBlockNumber ( ) ) ;
833+ const merkle64 = generateMerkleForClusterEB ( connection , [ { clusterId, effectiveBalance : 64 } ] ) ;
834+ await commitEBRoot ( network , merkle64 . root , eb64Block , oracles ) ;
835+ const clusterBefore64 = await getCurrentClusterState ( connection , network , clusterOwner . address , operatorIds ) ;
836+ await network . updateClusterBalance (
837+ eb64Block ,
838+ clusterOwner . address ,
839+ operatorIds . map ( ( id ) => BigInt ( id ) ) ,
840+ {
841+ validatorCount : Number ( clusterBefore64 . validatorCount ) ,
842+ networkFeeIndex : BigInt ( clusterBefore64 . networkFeeIndex ) ,
843+ index : BigInt ( clusterBefore64 . index ) ,
844+ active : clusterBefore64 . active ,
845+ balance : BigInt ( clusterBefore64 . balance ) ,
846+ } ,
847+ 64 ,
848+ merkle64 . proofs [ clusterId ] ,
849+ ) ;
850+
851+ const earningsBefore64 = await views . getNetworkEarnings ( ) ;
852+ await connection . networkHelpers . mine ( 100n ) ;
853+ const earningsAfter64 = await views . getNetworkEarnings ( ) ;
854+ const delta64 = earningsAfter64 - earningsBefore64 ;
855+
856+ await connection . networkHelpers . mine ( 1n ) ;
857+ const eb128Block = Number ( await connection . ethers . provider . getBlockNumber ( ) ) ;
858+ const merkle128 = generateMerkleForClusterEB ( connection , [ { clusterId, effectiveBalance : 128 } ] ) ;
859+ await commitEBRoot ( network , merkle128 . root , eb128Block , oracles ) ;
860+ const clusterBefore128 = await getCurrentClusterState ( connection , network , clusterOwner . address , operatorIds ) ;
861+ await network . updateClusterBalance (
862+ eb128Block ,
863+ clusterOwner . address ,
864+ operatorIds . map ( ( id ) => BigInt ( id ) ) ,
865+ {
866+ validatorCount : Number ( clusterBefore128 . validatorCount ) ,
867+ networkFeeIndex : BigInt ( clusterBefore128 . networkFeeIndex ) ,
868+ index : BigInt ( clusterBefore128 . index ) ,
869+ active : clusterBefore128 . active ,
870+ balance : BigInt ( clusterBefore128 . balance ) ,
871+ } ,
872+ 128 ,
873+ merkle128 . proofs [ clusterId ] ,
874+ ) ;
875+
876+ const earningsBefore128 = await views . getNetworkEarnings ( ) ;
877+ await connection . networkHelpers . mine ( 100n ) ;
878+ const earningsAfter128 = await views . getNetworkEarnings ( ) ;
879+ const delta128 = earningsAfter128 - earningsBefore128 ;
880+
881+ expect ( delta64 ) . to . be . greaterThan ( 0n ) ;
882+ expect ( delta128 ) . to . equal ( delta64 * 2n ) ;
883+ } ) ;
884+ } ) ;
885+
733886 describe ( "Multisig Accounts" , async function ( ) {
734887
735888 it ( "Multisig contract stakes SSV tokens" , async function ( ) {
0 commit comments