Stakease Integration - How it works

For this integration, the main functions that are being added to the new Pool extension are: deposit and withdraw to/from Stakease.

We also override certain Pool functions and use these new ones inside.

In the deposit function, we track the shares that we receive, as well as stake on behalf of the pool itself for tax purposes in the Stakease system.

/**
     * @dev Deposits a specified amount of BRZ into the staking contract and receives stBRZ tokens in return.
     * @param brzAmount The amount of BRZ to deposit into the staking contract.
     * @return sharesReceived The number of stBRZ shares received in exchange for the BRZ deposit.
     */
    function depositIntoStBRZ(uint brzAmount) internal returns(uint sharesReceived) {
        address localStaking = brzStaking();

        // Calculate the number of stBRZ shares received for the BRZ deposit
        sharesReceived = IStakease(localStaking).getShares(brzAmount);

        // Increase the total stBRZ balance with the received shares
        totalStBRZ += sharesReceived;

        // Approve the staking contract to spend the BRZ tokens
        brzToken.approve(localStaking, brzAmount);

        // Stake the BRZ tokens to receive stBRZ tokens
        IStakease(localStaking).stakeOnBehalfOf(address(this), brzAmount);

        // Return the shares received
        return sharesReceived;
    }

The withdraw function then unstakes on behalf of the pool and updates the total amount with the amount of shares that we received.

/**
     * @dev Withdraws the needed amount from the BRZ and returns the amount used
     * @param brzAmount the amount that is desired to be returned
     * @return sharesWithdrawn The amount of shares withdrawn
     */
    function withdrawFromStBRZ(uint brzAmount) internal returns(uint sharesWithdrawn){
        address localStaking = brzStaking();

        // Unstake the specified BRZ
        sharesWithdrawn = IStakease(localStaking).unstakeExactBRZOnBehalfOf(address(this),brzAmount);

        // Update the total stBRZ balance by subtracting the withdrawn shares
        totalStBRZ -= sharesWithdrawn;
    }

The most important function is adjustUnderlyingBeforeWithdraw, which calculates the amount that we can withdraw, then basically calculates the value that the stBRZ, last time this function was called, was worth.

And with that value, it calculates the total rewards that were received in this time period.

With the new worth of those tokens we can then calculate a ratio by using the amount of BRZ that we can get now and dividing it through the total amount of staked BRZ that we have. This ratio is then used for the next time to calculate the share worth the last time the function was called.

We then add the total rewards to the capital supply to raise the value of the shares to increase the value of the shares.

 /**
 * @dev Adjusts the underlying BRZ assets before performing a withdrawal.
 * This function calculates and updates the total capital supply for the current cycle based on staking rewards.
 */
function adjustUnderlyingBeforeWithdraw() internal{

  (uint currentCycle, , ) = getCurrentCycleStatus();
  address localStaking = brzStaking();

  // Get the new BRZ value of the total stBRZ balance        
  (uint newBRZValueOfTotalStBRZ,,) =  IStakease(localStaking).calculateMaxBRZThatCanBeWithdrawn(address(this), address(this));

  // Calculate the old BRZ value of the total stBRZ balance based on the last stake ratio
  uint oldBRZValueOfTotalStBRZ= lastStakeRatio == 0 ? newBRZValueOfTotalStBRZ : lastStakeRatio * totalStBRZ / ACCURACY_BASE;

  // Calculate the total staking rewards earned
  uint totalRewards = newBRZValueOfTotalStBRZ-oldBRZValueOfTotalStBRZ;

  // Update the last stake ratio
  lastStakeRatio = newBRZValueOfTotalStBRZ * ACCURACY_BASE / totalStBRZ;

  // Update the total capital supply for the current cycle with the staking rewards
  totalCapitalSupplyPerCycle[currentCycle] += totalRewards;
}

We are overwriting all the balance impacting functions, like direct deposit, direct withdraw.
cancel deposit, finalize withdraw queue, commit standby capital, withdraw standby capital, reduce standby capital, get standby capital worth and has capital management plus claim lay repayment.

Functions like directDeposit, directWithdraw, cancelDeposit, finalize withdraw queue are basically very straightforward.
They just either adjust and withdraw before or deposit after the balance changing action / after the super function was called.

Examples

    /**
     * @dev Deposits an amount of assets into the pool and deposits into stBRZ.
     * @param amount The amount of assets to deposit into the pool.
     * @return The result of the super contract's directDeposit function.
     */
    function directDeposit(uint amount) public override returns(uint){
        uint depositReturn = super.directDeposit(amount);
        depositIntoStBRZ(amount);
        return depositReturn;
    }

    /**
     * @dev Withdraws an amount of assets from the pool and withdraws from stBRZ.
     * @param amount The amount of assets to withdraw from the pool.
     * @return The result of the super contract's directWithdraw function.
     */
    function directWithdraw(uint amount) public override returns(uint){
        (uint currentCycle,,) = getCurrentCycleStatus();
        
        adjustUnderlyingBeforeWithdraw();
        withdrawFromStBRZ(getBRZForShares(amount, currentCycle));
        return super.directWithdraw(amount);
    }

All functions that interact with the stand-by-capital don't adjust the share value and only withdraw. So it won't adjust the total capital supply because the yields of the staked BRZ go to the oracles that committed that stand-by-capital.

Examples

/**
  * @dev Reduces standby capital of the oracle and unstakes the amount needed.
  * @param _oracle The address of the oracle.
  * @param _total The total amount of standby capital to be reduced of the oracle.
  */
function withdrawStandByCapital(address _oracle, uint _total) public override onlyKonaCore returns(uint sharesReduced, uint totalSharesWorth){
        address localStaking = brzStaking();

        sharesReduced = withdrawFromStBRZ(_total);

        (totalSharesWorth,,) = IStakease(localStaking).calculateMaxBRZThatCanBeWithdrawn(address(this), _oracle);

        // Unstake the specified BRZ
        IStakease(localStaking).unstakeExactBRZOnBehalfOf(address(this),_total);

        brzToken.transfer(_oracle, _total);

    }
 /**
  * @dev Reduces standby capital of the oracle and unstakes the amount needed.
  * @param _oracle The address of the oracle.
  * @param _total The total amount of standby capital to be reduced of the oracle.
  */
 function reduceStandByCapital(address _oracle, uint256 _total) public onlyKonaCore returns(uint sharesReduced, uint totalSharesWorth){
        address localStaking = brzStaking();

        sharesReduced = withdrawFromStBRZ(_total);

        (totalSharesWorth,,) = IStakease(localStaking).calculateMaxBRZThatCanBeWithdrawn(address(this), _oracle);

        // Calculate the number of stBRZ shares received for the BRZ deposit
        uint sharesReceived = IStakease(localStaking).getShares(_total);

        // Approve the staking contract to spend the BRZ tokens
        brzToken.approve(localStaking, _total);

        // Stake the BRZ tokens to receive stBRZ tokens
        IStakease(localStaking).stakeOnBehalfOf(address(this), _total);

        totalStBRZ += sharesReceived;
        
    }

In the stakease integration part we also have a permanent flag set that returns true.

So interacting contracts know if they have to expect shares or just the original asset.

 function hasCapitalManagement() public override pure returns(bool){
        return true;
  }