knBONE

link to knBONE source code (will update when protocol goes live)

knBONE is the core contract which acts as a liquid staking pool. The contract is responsible for deposits, withdrawals, minting and burning liquid tokens, delegating funds to node operators, applying fees and distributing rewards.

knBONE contract also defines knBONE, an ERC20 token that represents the account's share of the BONE tokens inside K9 Finance DAO protocol. It is a non-rebasable token, which means that the amount of tokens in the user's wallet is not going to change by itself, only by user actions. During time, the value of this token is changing, since the amount of BONE tokens inside the protocol is not constant. knBONE will be integrated in variety of DeFi applications across Ethereum and Shibarium.

knBONE is inherited from IKnBONE, ERC20Upgradeable, AccessControlUpgradeable, PausableUpgradeable

Variables

IERC20Upgradeable public token; - BONE token address INodeOperatorRegistry public nodeOperatorRegistry; - NodeOpeartorRegistry contract address IStakeManager public stakeManager; - Shibarium StakeManager contract address IUnstBONE public unstBONE; - UnstBONE contract address IInstantPool public instantPool; - InstantPool contract address IDepositManager public depositManager; - DepositManager address of the bridge in Shibarium (this bridge is owned by K9 Finance DAO) IBridge public bridge; - Bridge contract address in Ethereum address public l2Staking; - Real Yield Staking contract address that will receive a share of rewards from Liquid Staking address public dao; - DAO Treasury reward address (this address does not necessarily have a DAO role) that will receive a share of rewards from Liquid Staking FeeDistribution public entityFees; - Protocol fee distribution structure uint256 public instantPoolUsageFee; - Fee percentage that user pays when withdrawing instant reward uint256 public totalBuffered; - amount of BONE that is buffered but not delegated, includes reservedFunds uint256 public delegationLowerBound; - the minimum required for successful delegate() on this contract uint256 public rewardDistributionLowerBound; - the minimum reward amount that is required for successful distributeRewards() on this contract uint256 public reservedFunds; - replenished if, when creating a request from a user, some amount did not fit into our requests to validators (included in totalBuffered) bytes32 public constant DAO_ROLE = keccak256("DAO_ROLE"); - dao role identifier bytes32 public constant PAUSE_ROLE = keccak256("PAUSE_ROLE"); - pauser role identifier bytes32 public constant UNPAUSE_ROLE = keccak256("UNPAUSE_ROLE"); - unpauser role identifier bytes32 public constant BRIDGE_ROLE = keccak256("BRIDGE_ROLE"); - bridge executor role identifier (should be granted to bridge) RequestWithdraw[] public knBONEWithdrawRequest; - an array of withdrawal request structures specifically for withdrawal to this contract (will be filled in only when creating a withdrawal request from the validator to KnBONE for reasons other than the user’s withdrawal, filled in when rebalanceDelegatedTokens() and withdrawTotalDelegated()) mapping(uint256 => RequestWithdraw[]) public token2WithdrawRequests; - for each unstBONE tokenID returns an array of withdrawal request structures uint8 public protocolFee; - Protocol fee total percentage which will then be distributed in accordance with entityFees

Structures

RequestWithdraw

Withdrawal requests structure

NameDescription

uint256 amount2WithdrawFromKnBONE

BONE amount to withdraw

uint256 validatorNonce

filled in as ValidatorShare.unboundNonces(address(this)) or 0 if the sub-application amount did not fit into our requests to validators

uint256 requestEpoch

when withdrawal is available, filled in as StakeManager.epoch() + StakeManager.withdrawalDelay()

address validatorAddress

ValidatorShare address or zero address in case if the sub-request amount does not fit into our requests to validators

struct RequestWithdraw {
uint256 amount2WithdrawFromKnBONE;
uint256 validatorNonce;
uint256 requestEpoch;
address validatorAddress;
}

FeeDistribution

Protocol fee distribution structure

NameDescription

dao

DAO Treasury protocol fee share

operators

Node operators protocol fee share

instantPool

Instant reward pool protocol fee share

staking

Real Yield Staking rewards protocol fee share

struct FeeDistribution {
uint8 dao; 
uint8 operators; 
uint8 instantPool;
uint8 staking;
}

Events

event SubmitEvent(address indexed _from, uint256 _amount, address indexed _receiver, bool _transferToL2); - upon submit() call

event InstantPoolWithdraw(address indexed _from, uint256 _amountWithFeeInBONE, uint256 _feeAmountInBONE); - when withdrawing using only instant pool, BONE amounts are provided

event RequestWithdrawEvent(address indexed _from, uint256 _amountInBONE); - when withdrawing using only withdrawal request, BONE amount is provided

event RequestWithdrawSplit(address indexed _from, uint256 _totalAmountInKnBONE); - upon completion of the transaction requestWithdrawSplit(), amount knBONE amount is provided

event DistributeRewardsEvent(uint256 indexed _amount, uint256 indexed totalPooledBefore, uint256 indexed totalPooledAfter); - upon distribureRewards() call

event WithdrawTotalDelegatedEvent( address indexed _from, uint256 indexed _amount ); - upon withdrawTotalDelegated() call

event DelegateEvent(uint256 indexed _amountDelegated, uint256 indexed _remainder ); - upon delegate() call

eventClaimTokensEvent(address indexed _from, uint256 indexed _id, uint256 indexed _amountClaimed); - upon claimTokens() call

event SetNodeOperatorRegistryAddress(address indexed _newNodeOperatorRegistryAddress ); - upon setNodeOperatorRegistryAddress() call

event SetDelegationLowerBound(uint256 indexed _delegationLowerBound); - upon setDelegationLowerBound() call

event SetRewardDistributionLowerBound(uint256 oldRewardDistributionLowerBound, uint256 newRewardDistributionLowerBound ); - upon setRewardDistributionLowerBound() call

event SetUnstBONE(address oldUnstBONE, address newUnstBONE); - upon setUnstBONE() call

event SetDaoAddress(address oldDaoAddress, address newDaoAddress); - upon setDaoAddress() call

event SetFees(uint256 daoFee, uint256 operatorsFee, uint256 instantPoolFee, uint256 stakingFee); - upon setFees() call

event SetProtocolFee(uint8 oldProtocolFee, uint8 newProtocolFee); - upon setProtocolFee() call

event SetInstantPoolUsageFee(uint256 oldInstantPoolUsageFee, uint256 newInstantPoolUsageFee); - upon setInstantPoolUsageFee() call

event SetInstantPool(address instantPool); - upon setInstantPool() call

event SetDepositManager(address depositManager);- upon setDepositManager() call

event SetBridge(address bridge); - upon setBridge() call

event SetL2Staking(address l2Staking); - upon setL2Staking() call

event ClaimTotalDelegatedEvent(address indexed validatorShare, uint256 indexed amountClaimed ); - upon claimTokensFromValidatorToContract() call

View functions

name()

function name() returns (string)

Returns the name of the token

symbol()

function symbol() returns (string)

Returns the symbol of the token, usually a shorter version of the name

decimals()

function decimals() returns (uint8)

Returns the number of decimals for getting user representation of a token amount.

totalSupply()

function totalSupply() returns (uint256)

Returns the amount of tokens in existence.

balanceOf()

function balanceOf(address _account) returns (uint256)

Returns the amount of tokens owned by the _account

getTotalWithdrawRequest

function getTotalWithdrawRequest()
        public
        view
        returns (RequestWithdraw[] memory)

Returns the entire knBONEWithdrawRequest array.

getTotalStake

function getTotalStake(IValidatorShare _validatorShare)
        public
        view
        returns (uint256, uint256)

The same as ValidatorShare.getTotalStake(address(this)). API for getting total stake of this contract from validatorShare.

getLiquidRewards

function getLiquidRewards(IValidatorShare _validatorShare)
        external
        view
        returns (uint256)

The same as ValidatorShare.getLiquidRewards(address(this)). API for liquid rewards of this contract from validatorShare.

getTotalStakeAcrossAllValidators

function getTotalStakeAcrossAllValidators()
        public
        view
        returns (uint256)

Returns the BONE amount staked in all validators.

getTotalPooledBONE

function getTotalPooledBONE() public view returns (uint256)

Returns total pooled BONE as getTotalStakeAcrossAllValidators() + totalBuffered + calculatePendingBufferedTokens() - reservedFunds

getToken2WithdrawRequests

function getToken2WithdrawRequests(uint256 _tokenId)
        external
        view
        returns (RequestWithdraw[] memory)

Returns the withdrawal request structure for tokenID.

getBONEFromTokenId

function getBONEFromTokenId(uint256 _tokenId)
        external
        view
        returns (uint256)

Retrieves the amount of BONE that will be claimed from the unstBONE NFT request.

convertKnBONEToBONE

function convertKnBONEToBONE(uint256 _amountInKnBONE)
        external
        view
        returns (
            uint256 amountInBONE,
            uint256 totalKnBONEAmount,
            uint256 totalPooledBONE
        )

Calculates BONE amount from the provided knBONE amount.

convertBONEToKnBONE

function convertBONEToKnBONE(uint256 _amountInBONE)
        public
        view
        returns (
            uint256 amountInKnBONE,
            uint256 totalKnBONESupply,
            uint256 totalPooledBONE
        )

Calculates knBONE amount from the provided BONE amount.

Methods

initialize

function initialize(
        INodeOperatorRegistry _nodeOperatorRegistry,
        IERC20Upgradeable _token,
        address _dao,
        IStakeManager _stakeManager,
        IUnstBONE _unstBONE,
        IInstantPool _instantPool,
        IDepositManager _depositManager,
        IBridgeETH _bridge,
        address _l2Staking
    ) external initializer

Initializer function, not called after initialization.

submit

function submit(uint256 _amount, address _receiver, bool _transferToL2)
        external
        whenNotPaused
        nonReentrant
        returns (uint256)

Send funds to knBONE contract and mint knBONE to receiver. Requires that msg.sender has approved _amount of BONE to this contract.

  • _amount - Amount of BONE sent from msg.sender to this contract

  • _receiver - receiver address

  • _transferToL2 - whether or not transfer knBONE to Shibarium

requestWithdrawSplit

function requestWithdrawSplit(uint256 _instantPoolAmount, 
      uint256 _requestWithdrawAmount, address _user) 
       external 
       whenNotPaused 
       nonReentrant 
       returns(uint256)

Request withdrawal function, allows using the instant pool and/or creating requests. _user must be the sender or any address if the function is called from BRIDGE_EXECUTOR_ROLE. When executed:

  • knBONE amount of the withdrawal request is burned

  • knBONE amount that is withdrawn through the Instant pool is sent to the DAO Treasury address.

Returns tokenID if there was a request or 0 if there was no request.

  • _instantPoolAmount - Amount of knBONE that is requested to withdraw using instant reward pool

  • _requestWithdrawAmount - Amount of knBONE that is requested to withdraw using withdrawal request

  • _user - user to withdraw from

delegate

function delegate() external whenNotPaused nonReentrant

Delegates the amount of BONE (totalBuffered - reservedFunds) to validator.

claimTokens

function claimTokens(uint256[] calldata _tokenId) external whenNotPaused

Claims tokens from validator share and sends them to the user. Requires the processed withdrawal request associated with unstBONE NFT.

distributeRewards

function distributeRewards() external whenNotPaused nonReentrant

Distributes the protocol rewards received from validator.

  • Creates a variable totalRewards equal to (contract balance - totalBuffered).

  • Calculates the protocol fee amount based on protocolFee%.

  • Then distributes the protocol fee amount according to the entity fees, the rest is added to totalBuffered for re-delegation.

withdrawTotalDelegated

function withdrawTotalDelegated(address _validatorShare)
        external
        nonReentrant

Called only by NodeOperatorRegistry contract. Creates a withdrawal request of the total delegated amount from the specified ValidatorShare. Withdraws funds from stopped validator.

rebalanceDelegatedTokens

function rebalanceDelegatedTokens() external onlyRole(DAO_ROLE)

Rebalane the system by request withdraw from the validators that contains more token delegated to them.

  • Calculates amountToReDelegate as (totalBuffered - reservedFunds + calculatePendingBufferedTokens()).

  • Sends it intoNodeOperatorRegistry.getValidatorsRebalanceAmount() and gets a response.

  • Based on the response, creates a withdrawal request for each ValidatorShare.

calculatePendingBufferedTokens

function calculatePendingBufferedTokens()
        public
        view
        returns (uint256 pendingBufferedTokens)

Calculate the total amount of BONE stored in knBONEWithdrawRequest array that can not be delegated.

claimTokensFromValidatorToContract

function claimTokensFromValidatorToContract(uint256 _index)
        external
        whenNotPaused
        nonReentrant

Processes the specified request in knBONEWithdrawRequest. Claims tokens from validator share and sends them to the knBONE contract.

Admin Methods

This method can be called by ADMIN-only roles

pause

function pause() external onlyRole(PAUSE_ROLE)

Pause knBONE contract

unpause

function unpause() external onlyRole(UNPAUSE_ROLE)

Unpause knBONE contract

DAO Methods - setters

These methods can be called by DAO-only roles

setProtocolFee

function setProtocolFee(uint8 _newProtocolFee)
     external
     onlyRole(DAO_ROLE)

Sets protocolFee value that will be distributed between receivers.

setInstantPoolUsageFee

function setInstantPoolUsageFee(uint256 _instantPoolUsageFee) 
     external 
     onlyRole(DAO_ROLE)

Sets fee percentage that user pays when withdrawing instant reward

setDaoAddress

function setDaoAddress(address _newDAO)
      external 
      onlyRole(DAO_ROLE)

Sets the DAO Treasury reward address

setNodeOperatorRegistryAddress

function setNodeOperatorRegistryAddress(address _address)
     external
     onlyRole(DAO_ROLE)

Sets nodeOperatorRegistry address

setInstantPool

function setInstantPoolUsageFee(uint256 _instantPoolUsageFee) 
     external 
     onlyRole(DAO_ROLE)

Sets InstantPool address

setDepositManager

function setDepositManager(IDepositManager _depositManager) 
     external 
     onlyRole(DAO_ROLE)

Sets depositManager address

setBridge

function setBridge(IBridge _bridge) external onlyRole(DAO_ROLE)

Sets K9 bridge address

setL2Staking

function setL2Staking(address _l2Staking) external onlyRole(DAO_ROLE)

Sets Real Yield Staking address

setDelegationLowerBound

function setDelegationLowerBound(uint256 _delegationLowerBound)

Function that sets new lower bound for delegation

setRewardDistributionLowerBound

function setRewardDistributionLowerBound(
        uint256 _newRewardDistributionLowerBound
    ) external onlyRole(DAO_ROLE)

Function that sets new lower bound for rewards distribution

Last updated