Introduction
This Temperature Check aims to gauge community interest in a BSN bribe marketplace for Stakehouse LSD Node Operators to incentivize stakers to fund specific validators via Fren Delegation. Currently, there are no incentives for stakers to use Fren Delegation instead of the Giant Pools. This proposal would allow validators to deposit BSN in a smart contract where stakers who deposited via Fren Delegation may claim the tokens, proportional to their deposit amount multiplied by a rewards ratio set by the validator. This proposal would benefit the validators who are waiting for ETH and stakers who are seeking higher BSN rewards for their deposits. A Proof-of-Concept smart contract and dApp have already been deployed and successfully tested in Goerli testnet.
This Temperature Check outlines an initial project scope, predicted impact, timeline, and required resources for the proposed grant application. If the community expresses a positive opinion of this Temperature Check in Discord and the forums, then a Grant Application will be submitted in the Community Applications category.
Background
When stakers deposit via Fren Delegation, or any other means of directly depositing ETH to a validators SavETH and MEVFees pools, they receive a derivative token dstETH or ETHLP which is unique to the validator they deposited to. Since this derivative token is 1:1 with ETH, the balance of these derivative tokens represents exactly how much ETH the staker deposited.
Given a validator’s BLS key and a staker’s address, a Solidity smart contract can determine how much ETH the staker deposited into the validator’s pools. This ability makes possible a marketplace where validators can bribe stakers with BSN rewards.
dstETH
Derivative token received by stakers when they deposit ETH directly to a validators Protected Staking pool (SavETH).
ETHLP
Derivative token received by stakers when they deposit ETH directly to a validators MEVFees Pool.
BSNVault
BSNVault is the smart contract where validators deposit BSN and stakers claim rewards.
High-level Overview
A node runner who holds BSN, and is waiting for ETH before they can stake their validator, may deposit BSN into the BSNVault on the dApp to become incentivized. Each BSN deposit to the BSNVault requires the validator’s BLS key, a total amount of BSN to deposit, and a BSN/ETH rewards ratio. Each incentivized validator appears in the dApp along with the rewards ratio and total BSN deposit amount.
A staker who wishes to earn more BSN rewards may deposit to an incentivized validator via Fren Delegation. After the incentivized validator has staked and minted derivative tokens, the staker may claim their BSN rewards on the dApp.
A validator may only have 1 active BSN bribe at any given time, and each bribe is active for 1 year. A validator can deposit more BSN to a bribe while it’s active, and can withdraw unclaimed BSN after the bribe expires. Unclaimed BSN can only be withdrawn to the address the validator was registered with on Stakehouse LSD (the node runner’s address).
Implementation details
Checking derivative token balances
To get the balance of the derivative dstETH and ETHLP tokens, the BSNVault makes several external calls to various Stakehouse contracts.
stakeHouseKnotInfo(bytes) on StakehouseUniverse returns the “applicant” or Smart Wallet of a validator.
owner() of the Smart Wallet returns the LiquidStakingManager of the validator.
savETHVault() and stakingFundsVault() on the LiquidStakingManager returns the SavETH and MEVFees pool addresses of the validator.
lpTokenForKnot(bytes) on the SavETH and MEVFees pools returns the dstETH and ETHLP token addresses of the validator.
balanceOf(address) on the dstETH and ETHLP tokens returns the balance of the derivative tokens for the validator held by the given address.
Node runner address from BLS key
To get the Node Runner’s address for a given BLS key (for withdrawing unclaimed BSN deposits), the BSNVault makes the following external calls to Stakehouse contracts:
stakeHouseKnotInfo(bytes) on StakehouseUniverse returns the “applicant” or Smart Wallet of a validator.
owner() of the Smart Wallet returns the LiquidStakingManager of the validator.
nodeRunnerOfSmartWallet(address) on the LiquidStakingManager returns the node runners address.
BSNVault public functions
-
depositBSN(bsnAmount, bsnToETHRatio, validatorBLSKey)
- Requires bsnToEthRatio and bsnAmount both be greater than 0
- If a bribe already exists for the validatorBLSKey, then
- Transfer BSN to contract (requires approval)
- Increment bsnAmount on the BSNDeposit
- Do not apply the new bsnToETHRatio if it’s lower than existing ratio (to prevent baiting, ie validator sets very high bsnEthRatio only to lower it right before minting derivatives)
- If no bribe exists, then
-
Transfer BSN to contract (requires approval)
-
Add BSNDeposit to bsnDeposits mapping
-
Push new validator BLS key to the blsDepositKeys array
-
Increment the blsDepositKeyIndex variable
-
claim(validatorBLSKey)
-
- Requires the msg.sender hasn’t already claimed rewards for the validator by checking claimedDeposits mapping.
- Requires msg.sender’s balance of derivative dstETH and ETHLP tokens be greater than 0.
- Requires the BSNDeposit bsnAmount be greater than or equal to the claim amount
- Claim amount is equal to (dstETH + ETHLP balances) * bsnEthRatio (for example, if a staker deposits all 24 ETH to Protected Staking and 4 ETH to MEV staking via Fren Delegation and the bsnEthRatio is 1000000, then the claim amount is 28000000)
- Decrement BSNDeposit bsnAmount for the bribe
- Push validator BLS key to claimedDeposits for msg.sender
- Transfer BSN tokens to msg.sender
-
withdrawRemainingBSN(validatorBLSKey)
- Requires the bribe expiration date be in the past and the bibe amount be greater than zero
- Temporarily store the remaining BSN amount in a variable.
- Delete the bribe’s bsnDeposit
- Transfer the amount of remaining BSN to the validator owner (node runner)
Several helper functions:
- getSavETHandMEVFeesPoolsByBLS(bytes calldata validatorBLSKey)
- getLPTokensByBLS(bytes calldata validatorBLSKey)
- ethDepositsByBLSKeyAndAddress(bytes calldata validatorBLSKey, address depositor)
- claimable(bytes calldata validatorBLSKey)
- hasClaimed(bytes calldata validatorBLSKey, address recipient)
- getNodeRunnerAddress(bytes calldata validatorBLSKey)
BSNVault structures
struct BSNDeposit{
uint256 bsnAmount;
uint256 bsnToEthRatio;
uint256 expiration;
}
BSNVault public variables
mapping(bytes => BSNDeposit) public bsnDeposits
- Maps validatorBLSKeys to BSNDeposit structures.
bytes public blsDepositKeys; - An array of validator BLS keys which have deposited BSN to the vault.
uint256 public blsDepositKeyIndex; - Index representing number of unique validators who have deposited to the vault.
mapping(address => bytes) public claimedDeposits; - Maps staker addresses to a list of validator BLS keys
address public bsnToken
address public stakehouseUniverse
Caveats
Stakers must wait until the validator mints derivative tokens to claim their BSN rewards. This is due to an obstacle in finding the LP token addresses given a validator BLS key that hasn’t yet been staked and minted.
The process of determining how much ETH a staker deposited by checking their balance of derivative dstETH and ETHLP tokens relies on those tokens never being transferred by the staker.
If an incentivized validator is funded by the Giant Pool, then the proportion of BSN in the bribe will be unclaimable.
Grant Application
Applicant background
JohnBrown has over 5 years of experience in software development, and 1 of those years was working with Ethereum and DeFi. The applicant has developed and deployed other dApps for token locking and distributions, and for direct depositing ETH to Stakehouse validators, and has extensive experience with web3 in Python and Javascript. The applicant may be contacted on Discord: JohnBrown#0339.
Project scope
The scope of this grant should be limited to open-source development and testing of the BSNVault contract and Bribe marketplace dApp.
The applicant is not responsible for hosting the dApp or deploying the BSNVault to mainnet. Anyone can host the dApp and deploy the BSNVault since the code will be open source.
Objectives for BSNVault contract:
- Allow anyone to incentivize a validator by depositing BSN tokens and specifying a BSN to ETH rewards ratio.
- Allow stakers to claim BSN rewards proportional to their dstETH and ETHLP balances multiplied by the BSN to ETH ratio.
- Prevent stakers from claiming rewards more than once per validator
- Allow anyone to deposit additional BSN into existing bribes
- Prevent validators from lowering the BSN to ETH rewards ratio after the initial deposit
- Allow validators to withdraw remaining BSN after a year from the original deposit.
Objectives for dApp:
- Intuitive and user-friendly UI
- Allow BSN depositors to approve BSNVault to spend BSN
- Allow deposits of BSN to BSNVault
- Enable stakers to claim BSN from bribes they’re eligible for
- Allow withdrawing leftover BSN to node runners (after 1 year expiration)
Impact
There are currently 17 validators waiting for ETH from the Giant Pool or Fren Delegation before they can stake. 17 validators * 28 ETH = 476 ETH needed to fund the waiting validators. Since the Giant Pool is first come, first serve, most validators will be too slow to claim ETH from there. We’ve already seen bots claiming ETH the moment the Giant Pools have a sufficient amount.
If Node Runners could incentivize stakers to fund their validators via Fren Delegation with BSN bribes, then some validators who would otherwise be waiting months to stake can do so much faster. Similarly, stakers who would be waiting weeks or months for their Giant Pool deposits to be staked can deposit to an incentivized validator which should be staked sooner.
There’s an incentive for BSN buyers to join the ecosystem as stakers since bribe rewards are BSN.
Timeline
Months since grant accepted - Objective
1 BSNVault contract running in Goerli testnet
Code for BSNVault contract and dApp open-sourced on Github
BSNVault: depositBSN()
BSNVault: claim()
BSNVault: withdrawRemainingBSN()
dApp: Approve & Deposit BSN to BSNVault
dApp: Claim BSN from BSNVault
dApp: Withdraw expired BSN to node runner
dApp: Top-up bribes with additional BSN and increase BSN/ETH ratio
2 UI/UX enhancements
Software quality assurance, stress testing, penetration testing
Documentation and deployment instructions for dApp and BSNVault
Conclusion
This bribe marketplace based on Fren Delegation will provide a way for validators to become staked much quicker, and for stakers to earn more BSN rewards. The Stakehouse LSD ecosystem would benefit from validators competing to pay stakers the most BSN per ETH, instead of racing to the Giant Pool. I recommend that the Grant Council issue 3 million BSN tokens for the completion and open-sourcing of this project.