From a1db3ed102f8058c0a993d1b143f36df5d492142 Mon Sep 17 00:00:00 2001 From: DrZoltanFazekas Date: Wed, 18 Dec 2024 07:43:06 +0100 Subject: [PATCH] Restructure the readme, add more solhint rules --- .solhint.json | 15 ++- README.md | 124 +++++++++++++----------- src/BaseDelegation.sol | 4 +- src/{Delegation.sol => IDelegation.sol} | 2 +- test/BaseDelegation.t.sol | 8 +- test/BlsVerifyPrecompile.t.sol | 1 + test/LiquidDelegation.t.sol | 11 ++- test/NonLiquidDelegation.t.sol | 13 +-- 8 files changed, 105 insertions(+), 73 deletions(-) rename src/{Delegation.sol => IDelegation.sol} (97%) diff --git a/.solhint.json b/.solhint.json index 64a46a5..6bf4464 100644 --- a/.solhint.json +++ b/.solhint.json @@ -8,6 +8,19 @@ "func-visibility": ["warn", {"ignoreConstructors": true}], "gas-custom-errors": "off", "no-empty-blocks": "off", - "no-complex-fallback": "off" + "no-complex-fallback": "off", + "interface-starts-with-i": "warn", + "func-param-name-mixedcase": "warn", + "modifier-name-mixedcase": "warn", + "gas-calldata-parameters": "warn", + "gas-indexed-events": "warn", + "gas-length-in-loops": "warn", + "comprehensive-interface": "warn", + "gas-increment-by-one": "off", + "private-vars-leading-underscore": ["off", {"strict": false}], + "named-parameters-mapping": "off", + "foundry-test-functions": ["off"], + "imports-order": "off", + "max-line-length": ["off", 120] } } diff --git a/README.md b/README.md index a66d362..c31057d 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,21 @@ # Delegated Staking -This repository contains the contracts and scripts needed to activate a validator that users can delegate stake to. Currently, there are two variants of the contracts: +This repository contains the contracts and scripts needed to create a staking pool that users can delegate to. Currently, the contracts exist in two variants: 1. When delegating stake to the **liquid variant**, users receive a non-rebasing liquid staking token (LST) that anyone can send to the validator's contract later on to withdraw the stake plus the corresponding share of the validator rewards. 1. When delegating stake to the **non-liquid variant**, the users can regularly withdraw their share of the rewards without withdrawing their stake. + ## Prerequisites -To interact with the contracts throught the CLI, you can use the Forge scripts provided in this repository and described further below. First, install Foundry (https://book.getfoundry.sh/getting-started/installation) and the OpenZeppelin contracts before proceeding with the deployment: + +To deploy and interact with the contracts throught the CLI, use the Forge scripts provided in this repository and described further below. First, install Foundry (https://book.getfoundry.sh/getting-started/installation) and the OpenZeppelin contracts before proceeding with the deployment: ``` forge install OpenZeppelin/openzeppelin-contracts-upgradeable --no-commit forge install OpenZeppelin/openzeppelin-contracts --no-commit ``` -To allow stakers to interact with the contracts through your dapp, use the events and methods defined in the `Deposit` interface and the `BaseDelegation` contract: -```solidity -event Staked(address indexed delegator, uint256 amount, bytes data); -event Unstaked(address indexed delegator, uint256 amount, bytes data); -event Claimed(address indexed delegator, uint256 amount, bytes data); - -function stake() external payable; -function unstake(uint256) external returns(uint256 unstakedZil); -function claim() external; - -function getClaimable() external virtual view returns(uint256 total); -function getPendingClaims() external virtual view returns(uint256[2][] memory blockNumbersAndAmounts); -function getMinDelegation() external view returns(uint256 amount); -function getCommission() external view returns(uint256 numerator, uint256 denominator); -function getStake() external view returns(uint256 validatorStake); -``` -as well as the additional events and methods applicable to a specific staking variant only such as -```solidity -function getLST() external view returns(address erc20Contract); -function getPrice() external view returns(uint256 oneTokenToZil); -``` -for liquid staking and -```solidity -event RewardPaid(address indexed delegator, uint256 reward); - -function rewards() external view returns(uint256 total); -function withdrawAllRewards() external returns(uint256 taxedRewards); -function withdrawRewards(uint256 amount) external returns(uint256 taxedRewards); -function stakeRewards() external; -``` -and a few more for the non-liquid variant. - -To enable the tests included in this repository to interact with the Zilliqa 2.0 deposit contract, it must be compiled along with the test contracts. Specify the folder containing the `deposit.sol` file in `remappings.txt`: -``` -@zilliqa/zq2/=/home/user/zq2/zilliqa/src/contracts/ -``` ## Contract Deployment -The delegation contract is used by delegators to stake and unstake ZIL with the respective validator. It acts as the validator node's control address and interacts with the deposit contract. + +The delegation contract manages the stake delegated to the staking pool. It acts as the validator node's control address and interacts with the Zilliqa 2.0 protocol's deposit contract. `BaseDelegation` is an abstract contract that concrete implementations inherit from. `LiquidDelegation` is the initial version of the liquid staking variant of the delegation contract that creates a `NonRebasingLST` contract when it is initialized. `LiquidDelegationV2` contains the full implementation including the LST price calculation and other features. `NonLiquidDelegation` is the initial version of the non-liquid staking variant of the delegation contract. `NonLiquidDelegationV2` contains the full implementation that allows delegators to withdraw rewards. @@ -124,7 +91,8 @@ forge script script/ManageCommission.s.sol --rpc-url http://localhost:4201 --bro using `same` for the second argument to leave the commission percentage unchanged and `true` for the third argument. Replacing the second argument with `same` and the third argument with `false` only displays the current commission rate. -## Validator Activation and Migration +## Validator Activation or Migration + If your node has already been activated as a validator i.e. solo staker, you can migrate it to a staking pool. Run ```bash cast send --legacy --rpc-url http://localhost:4201 --private-key 0x... \ @@ -148,7 +116,11 @@ cast send --legacy --value 10000000ether --rpc-url http://localhost:4201 --priva 0x002408011220d5ed74b09dcbe84d3b32a56c01ab721cf82809848b6604535212a219d35c412f \ 0xb14832a866a49ddf8a3104f8ee379d29c136f29aeb8fccec9d7fb17180b99e8ed29bee2ada5ce390cb704bc6fd7f5ce814f914498376c4b8bc14841a57ae22279769ec8614e2673ba7f36edc5a4bf5733aa9d70af626279ee2b2cde939b4bd8a ``` -with the BLS public key, the peer id and the BLS signature of your node. Note that the peer id must be converted from base58 to hex. Make sure your node is fully synced before you run the above command. +with the BLS public key, the peer id and the BLS signature of your node. Note that the peer id must be converted from base58 to hexadecimal format and you must provide the delegation contract address when generating the BLS signature: +```bash +echo '{"secret_key":"...", "chain_id":..., "address":"0x7a0b7e6d24ede78260c9ddbd98e828b0e11a8ea2"}' | cargo run --bin convert-key +``` +Make sure your node is fully synced before you run the above command. Note that the reward address registered for your validator node will be the address of the delegation contract (the proxy contract to be more precise). @@ -166,11 +138,12 @@ Note that the deposit will not take effect and the node will not start earning r ## Staking and Unstaking -Once the delegation contract has been deployed and upgraded to the latest version, your node can accept delegations. In order to stake e.g. 200 ZIL, your delegators must run + +Once the delegation contract has been deployed and upgraded to the latest version, your node can accept delegations. In order to stake e.g. 200 ZIL, run ```bash forge script script/Stake.s.sol --rpc-url http://localhost:4201 --broadcast --legacy --sig "run(address payable, uint256)" 0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2 200000000000000000000 --private-key 0x... ``` -with the private key of their account. It's important to make sure the account's balance can cover the transaction fees plus the 200 ZIL to be delegated. +with the private key of delegator account. It's important to make sure the account's balance can cover the transaction fees plus the 200 ZIL to be delegated. The output will look like this for liquid staking: ``` @@ -195,7 +168,7 @@ Due to the fact that the above output was generated based on the local script ex cast call 0x9e5c257D1c6dF74EaA54e58CdccaCb924669dc83 "balanceOf(address)(uint256)" 0xd819fFcE7A58b1E835c25617Db7b46a00888B013 --rpc-url http://localhost:4201 | sed 's/\[[^]]*\]//g' ``` -Your delegators can copy the LST address from the above output and add it to their wallet to transfer their liquid staking tokens to another account if they want to. +Copy the LST address from the above output and add it to your wallet if you want to transfer liquid staking tokens to another account. To query the current price of an LST, run ```bash @@ -226,11 +199,11 @@ and like this for the non-liquid variant: Staker balance after: 99698814298179759361224 wei ``` -The ZIL balance hasn't increased because the unstaked amount can not be transferred immediately. To claim the amount that is available after the unbonding period, run +The ZIL balance hasn't increased yet because the unstaked amount can not be transferred immediately. To claim the unstaked amount after the unbonding period, run ```bash forge script script/Claim.s.sol --rpc-url http://localhost:4201 --broadcast --legacy --sig "run(address payable)" 0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2 --private-key 0x... ``` -with the private key of the account that unstaked in the previous step above. +with the private key of the account that unstaked in the previous step. The output will look like this: ``` @@ -239,25 +212,28 @@ The output will look like this: Staker balance after: 99798095485861371162343 wei ``` -To query how much ZIL a user can already claim, run +To query how much ZIL you can already claim, run ```bash cast to-unit $(cast call 0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2 "getClaimable()(uint256)" --from 0xd819fFcE7A58b1E835c25617Db7b46a00888B013 --block latest --rpc-url http://localhost:4201 | sed 's/\[[^]]*\]//g') ether ``` -with the user's address as an argument. +with the address of the account that unstaked above as an argument. +Of course, delegators will not be using the CLI to stake, unstake and claim their funds. To enable delegators to access your staking pool through the staking portal maintained by the Zilliqa team, get in touch and provide your delegation contract address once you have set up the validator node and delegation contract. If you want to integrate staking into your dapp, see the [Development and Testing](#development-and-testing) section below. -## Staking and Withdrawing Rewards -In the liquid staking variant, only you as the node operator can stake the rewards accrued by the node. To do so, run + +## Withdrawing or Staking Rewards + +In the liquid staking variant, you as the node operator can stake the rewards accrued by the node. To do so, run ```bash forge script script/StakeRewards.s.sol --rpc-url http://localhost:4201 --broadcast --legacy --sig "run(address payable)" 0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2 --private-key 0x... ``` -In the non-liquid variant of staking, your delegators can stake or withdraw their share of the rewards. To query the amount of rewards available, run +In the non-liquid variant of staking, delegators can stake or withdraw their share of the rewards. To query the amount of rewards available, run ```bash cast to-unit $(cast call 0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2 "rewards()(uint256)" --from 0xd819fFcE7A58b1E835c25617Db7b46a00888B013 --block latest --rpc-url http://localhost:4201 | sed 's/\[[^]]*\]//g') ether ``` -In case users haven't withdrawn rewards for a long time during which many delegators staked or unstaked, the gas used by the above function might hit the block limit. In this case rewards can be withdrawn from the period between the (un)staking until which they were withdrawn last time and the `n`th subsequent (un)staking. This can be repeated several times to withdraw all rewards using multiple transactions. To calculate the rewards that can be withdrawn in the next transaction, choose a number `0 <= n <= 11000` e.g. `100` and run +In case you haven't withdrawn rewards for a long time during which many delegators staked or unstaked, the gas used by the above function might hit the block limit. In this case rewards can be withdrawn from the period between the (un)staking until which they were withdrawn last time and the `n`th subsequent (un)staking. This can be repeated several times to withdraw all rewards using multiple transactions. To calculate the rewards that can be withdrawn in the next transaction, choose a number `0 <= n <= 11000` e.g. `100` and run ```bash cast to-unit $(cast call 0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2 "rewards(uint64)(uint256)" 100 --from 0xd819fFcE7A58b1E835c25617Db7b46a00888B013 --block latest --rpc-url http://localhost:4201 | sed 's/\[[^]]*\]//g') ether ``` @@ -269,18 +245,25 @@ forge script script/WithdrawRewards.s.sol --rpc-url http://localhost:4201 --broa ``` with the private key of a delegator account. To withdraw as much as possible with the given value of `n` set the amount to `all`. To withdraw the chosen amount without setting `n` replace `n` with `all`. To withdraw all rewards replace both the amount and `n` with `all`. -Last but not least, in order to stake rewards instead of withdrawing them, your delegators can run +Last but not least, in order to stake rewards instead of withdrawing them, run ```bash forge script script/StakeRewards.s.sol --rpc-url http://localhost:4201 --broadcast --legacy --sig "run(address payable)" 0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2 --private-key 0x... ``` using the private key of their account. + ## Development and Testing + Staking pool operators are encouraged to fork and adapt the above contracts to implement features such as instant unstaking for a premium fee, automated staking of rewards to achieve the best possible APR or issuing a rebasing liquid staking token with a constant price of 1 ZIL but holder balances adjusted according to the rewards accrued. The tests included in this repository should also be adjusted and extended accordingly. They can be executed by running ```bash -forge test +PRIVATE_KEY="0x$(openssl rand -hex 32)" forge test +``` + +To enable the tests to interact with the Zilliqa 2.0 deposit contract, the contract must be compiled along with the test contracts. Specify the folder containing the `deposit.sol` file in `remappings.txt`: +``` +@zilliqa/zq2/=/home/user/zq2/zilliqa/src/contracts/ ``` The following bash scripts with verbose output can be used to test staking, unstaking and claiming of unstaked funds as well as withdrawing and staking of rewards and to print the current state of a delegator's stake queried from the validator's local node. Their output is useful for checking the results of these operations. Here a few examples of how to use them (private key replaced with `0x...`): @@ -315,3 +298,36 @@ chmod +x state.sh && ./state.sh 0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2 0xd81 # display the state of the stake of the below delegator at block 4800000 chmod +x state.sh && ./state.sh 0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2 0xd819fFcE7A58b1E835c25617Db7b46a00888B013 4800000 ``` + +Use the events and methods defined in the `IDeposit` interface and the `BaseDelegation` contract to integrate Zilliqa 2.0 staking into your dapp: +```solidity +event Staked(address indexed delegator, uint256 amount, bytes data); +event Unstaked(address indexed delegator, uint256 amount, bytes data); +event Claimed(address indexed delegator, uint256 amount, bytes data); + +function stake() external payable; +function unstake(uint256) external returns(uint256 unstakedZil); +function claim() external; + +function getClaimable() external virtual view returns(uint256 total); +function getPendingClaims() external virtual view returns(uint256[2][] memory blockNumbersAndAmounts); +function getMinDelegation() external view returns(uint256 amount); +function getCommission() external view returns(uint256 numerator, uint256 denominator); +function getStake() external view returns(uint256 validatorStake); +``` + +There are additional events and methods applicable only to a specific staking variant such as +```solidity +function getLST() external view returns(address erc20Contract); +function getPrice() external view returns(uint256 oneTokenToZil); +``` +for liquid staking and +```solidity +event RewardPaid(address indexed delegator, uint256 reward); + +function rewards() external view returns(uint256 total); +function withdrawAllRewards() external returns(uint256 taxedRewards); +function withdrawRewards(uint256 amount) external returns(uint256 taxedRewards); +function stakeRewards() external; +``` +and a few more for the non-liquid variant. diff --git a/src/BaseDelegation.sol b/src/BaseDelegation.sol index e95f15f..3ab1251 100644 --- a/src/BaseDelegation.sol +++ b/src/BaseDelegation.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; -import {Delegation} from "src/Delegation.sol"; +import {IDelegation} from "src/IDelegation.sol"; import {WithdrawalQueue} from "src/WithdrawalQueue.sol"; import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol"; -abstract contract BaseDelegation is Delegation, PausableUpgradeable, Ownable2StepUpgradeable, UUPSUpgradeable, ERC165Upgradeable { +abstract contract BaseDelegation is IDelegation, PausableUpgradeable, Ownable2StepUpgradeable, UUPSUpgradeable, ERC165Upgradeable { using WithdrawalQueue for WithdrawalQueue.Fifo; diff --git a/src/Delegation.sol b/src/IDelegation.sol similarity index 97% rename from src/Delegation.sol rename to src/IDelegation.sol index 6f3cc40..9678e15 100644 --- a/src/Delegation.sol +++ b/src/IDelegation.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; -interface Delegation { +interface IDelegation { // data can store additional information e.g. liquid staking tokens event Staked(address indexed delegator, uint256 amount, bytes data); diff --git a/test/BaseDelegation.t.sol b/test/BaseDelegation.t.sol index 16123be..0d1497f 100644 --- a/test/BaseDelegation.t.sol +++ b/test/BaseDelegation.t.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.26; import {BlsVerifyPrecompile} from "test/BlsVerifyPrecompile.t.sol"; import {BaseDelegation} from "src/BaseDelegation.sol"; import {WithdrawalQueue} from "src/WithdrawalQueue.sol"; -import {Delegation} from "src/Delegation.sol"; +import {IDelegation} from "src/IDelegation.sol"; import {Deposit} from "@zilliqa/zq2/deposit_v3.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import {Test} from "forge-std/Test.sol"; @@ -179,7 +179,7 @@ abstract contract BaseDelegationTest is Test { false, address(delegation) ); - emit Delegation.Staked( + emit IDelegation.Staked( stakers[0], depositAmount, "" @@ -201,7 +201,7 @@ abstract contract BaseDelegationTest is Test { vm.roll(block.number + Deposit(delegation.DEPOSIT_CONTRACT()).blocksPerEpoch() * 2); } - function claimsAfterManyUnstakings(BaseDelegation delegation, uint64 steps) public { + function claimsAfterManyUnstakings(BaseDelegation delegation, uint64 steps) internal { uint256 i; uint256 x; @@ -229,7 +229,7 @@ abstract contract BaseDelegationTest is Test { false, address(delegation) ); - emit Delegation.Staked( + emit IDelegation.Staked( stakers[i-1], steps * x * 1 ether, "" diff --git a/test/BlsVerifyPrecompile.t.sol b/test/BlsVerifyPrecompile.t.sol index dc35fec..d244127 100644 --- a/test/BlsVerifyPrecompile.t.sol +++ b/test/BlsVerifyPrecompile.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.26; contract BlsVerifyPrecompile { + // solhint-disable foundry-test-functions function blsVerify(bytes memory, bytes memory, bytes memory) public pure returns(bool) { return true; } diff --git a/test/LiquidDelegation.t.sol b/test/LiquidDelegation.t.sol index 4ea5839..cadc807 100644 --- a/test/LiquidDelegation.t.sol +++ b/test/LiquidDelegation.t.sol @@ -8,12 +8,13 @@ import {LiquidDelegationV2} from "src/LiquidDelegationV2.sol"; import {NonRebasingLST} from "src/NonRebasingLST.sol"; import {BaseDelegation} from "src/BaseDelegation.sol"; import {WithdrawalQueue} from "src/WithdrawalQueue.sol"; -import {Delegation} from "src/Delegation.sol"; +import {IDelegation} from "src/IDelegation.sol"; import {Deposit} from "@zilliqa/zq2/deposit_v3.sol"; import {Console} from "src/Console.sol"; import {Vm} from "forge-std/Test.sol"; import {console} from "forge-std/console.sol"; +/* solhint-disable func-name-mixedcase */ contract LiquidDelegationTest is BaseDelegationTest { LiquidDelegationV2 internal delegation; NonRebasingLST internal lst; @@ -54,7 +55,7 @@ contract LiquidDelegationTest is BaseDelegationTest { uint256 rewardsBeforeUnstaking, uint256 blocksUntil, DepositMode mode - ) public { + ) internal { delegation = LiquidDelegationV2(proxy); lst = NonRebasingLST(delegation.getLST()); @@ -113,7 +114,7 @@ contract LiquidDelegationTest is BaseDelegationTest { false, address(delegation) ); - emit Delegation.Staked( + emit IDelegation.Staked( stakers[0], delegatedAmount, abi.encode(lst.totalSupply() * delegatedAmount / (delegation.getStake() + delegation.getRewards())) @@ -197,7 +198,7 @@ contract LiquidDelegationTest is BaseDelegationTest { false, address(delegation) ); - emit Delegation.Unstaked( + emit IDelegation.Unstaked( stakers[0], (delegation.getStake() + delegation.getRewards()) * lst.balanceOf(stakers[0]) / lst.totalSupply(), abi.encode(lst.balanceOf(stakers[0])) @@ -279,7 +280,7 @@ contract LiquidDelegationTest is BaseDelegationTest { false, address(delegation) ); - emit Delegation.Claimed( + emit IDelegation.Claimed( stakers[0], unstakedAmount, "" diff --git a/test/NonLiquidDelegation.t.sol b/test/NonLiquidDelegation.t.sol index 1b621d7..4316f56 100644 --- a/test/NonLiquidDelegation.t.sol +++ b/test/NonLiquidDelegation.t.sol @@ -7,13 +7,14 @@ import {NonLiquidDelegation} from "src/NonLiquidDelegation.sol"; import {NonLiquidDelegationV2} from "src/NonLiquidDelegationV2.sol"; import {BaseDelegation} from "src/BaseDelegation.sol"; import {WithdrawalQueue} from "src/WithdrawalQueue.sol"; -import {Delegation} from "src/Delegation.sol"; +import {IDelegation} from "src/IDelegation.sol"; import {Deposit} from "@zilliqa/zq2/deposit_v3.sol"; import {Console} from "src/Console.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {console} from "forge-std/console.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +/* solhint-disable func-name-mixedcase */ contract NonLiquidDelegationTest is BaseDelegationTest { using SafeCast for int256; @@ -113,7 +114,7 @@ contract NonLiquidDelegationTest is BaseDelegationTest { uint256 rewardsBeforeStaking, uint256 rewardsAccruedAfterEach, DepositMode mode - ) public { + ) internal { uint64 steps = withdrawalInSteps; uint256[] memory stakerIndicesBeforeWithdrawals = abi.decode(_stakerIndicesBeforeWithdrawals, (uint256[])); int256[] memory relativeAmountsBeforeWithdrawals = abi.decode(_relativeAmountsBeforeWithdrawals, (int256[])); @@ -500,7 +501,7 @@ contract NonLiquidDelegationTest is BaseDelegationTest { false, address(delegation) ); - emit Delegation.Staked( + emit IDelegation.Staked( stakers[i-1], x * 1 ether, "" @@ -522,7 +523,7 @@ contract NonLiquidDelegationTest is BaseDelegationTest { false, address(delegation) ); - emit Delegation.Unstaked( + emit IDelegation.Unstaked( stakers[i-1], x * 1 ether, "" @@ -567,7 +568,7 @@ contract NonLiquidDelegationTest is BaseDelegationTest { false, address(delegation) ); - emit Delegation.Claimed( + emit IDelegation.Claimed( stakers[i-1], steps / 8 * x * 1 ether, "" @@ -613,7 +614,7 @@ contract NonLiquidDelegationTest is BaseDelegationTest { false, address(delegation) ); - emit Delegation.Staked( + emit IDelegation.Staked( stakers[i-1], x * 1 ether, ""