Skip to content

Latest commit

 

History

History
1743 lines (1372 loc) · 53.3 KB

ILoanTokenWRBTC.md

File metadata and controls

1743 lines (1372 loc) · 53.3 KB

The FeeSharingCollector contract. (ILoanTokenWRBTC.sol)

View Source: contracts/governance/FeeSharingCollector/FeeSharingCollector.sol

↗ Extends: SafeMath96, IFeeSharingCollector, Ownable, FeeSharingCollectorStorage

ILoanTokenWRBTC contract

This contract withdraws fees to be paid to SOV Stakers from the protocol. Stakers call withdraw() to get their share of the fees. *

Contract Members

Constants & Variables

//internal members
address internal constant ZERO_ADDRESS;

//public members
address public constant RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;

Events

event FeeWithdrawnInRBTC(address indexed sender, uint256  amount);
event TokensTransferred(address indexed sender, address indexed token, uint256  amount);
event CheckpointAdded(address indexed sender, address indexed token, uint256  amount);
event UserFeeWithdrawn(address indexed sender, address indexed receiver, address indexed token, uint256  amount);
event UserFeeProcessedNoWithdraw(address indexed sender, address indexed token, uint256  prevProcessedCheckpoints, uint256  newProcessedCheckpoints);
event FeeAMMWithdrawn(address indexed sender, address indexed converter, uint256  amount);
event WhitelistedConverter(address indexed sender, address  converter);
event UnwhitelistedConverter(address indexed sender, address  converter);
event RBTCWithdrawn(address indexed sender, address indexed receiver, uint256  amount);

Modifiers

oneTimeExecution

modifier oneTimeExecution(bytes4 _funcSig) internal

Arguments

Name Type Description
_funcSig bytes4

validFromCheckpointParam

Validates if the checkpoint is payable for the user

modifier validFromCheckpointParam(uint256 _fromCheckpoint, address _user, address _token) internal

Arguments

Name Type Description
_fromCheckpoint uint256
_user address
_token address

Functions


constructor

fallback function to support rbtc transfer when unwrap the wrbtc.

function () external payable
Source Code
on() external payable {}

withdrawFees

⤾ overrides IFeeSharingCollector.withdrawFees

Withdraw fees for the given token: lendingFee + tradingFee + borrowingFee the fees (except SOV) will be converted in wRBTC form, and then will be transferred to wRBTC loan pool. For SOV, it will be directly deposited into the feeSharingCollector from the protocol. *

function withdrawFees(address[] _tokens) external nonpayable

Arguments

Name Type Description
_tokens address[] array address of the token
Source Code
on withdrawFees(address[] calldata _tokens) external {
        for (uint256 i = 0; i < _tokens.length; i++) {
            require(
                Address.isContract(_tokens[i]),
                "FeeSharingCollector::withdrawFees: token is not a contract"
            );
        }

        uint256 wrbtcAmountWithdrawn = protocol.withdrawFees(_tokens, address(this));

        IWrbtcERC20 wRBTCToken = protocol.wrbtcToken();

        if (wrbtcAmountWithdrawn > 0) {
            // unwrap the wrbtc to rbtc, and hold the rbtc.
            wRBTCToken.withdraw(wrbtcAmountWithdrawn);

            /// @notice Update unprocessed amount of tokens
            uint96 amount96 =
                safe96(
                    wrbtcAmountWithdrawn,
                    "FeeSharingCollector::withdrawFees: wrbtc token amount exceeds 96 bits"
                );

            _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, amount96);
        }

        // note deprecated event since we unify the wrbtc & rbtc
        // emit FeeWithdrawn(msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, poolTokenAmount);

        // note new emitted event
        emit FeeWithdrawnInRBTC(msg.sender, wrbtcAmountWithdrawn);
    }

withdrawFeesAMM

Withdraw amm fees for the given converter addresses: protocolFee from the conversion the fees will be converted in wRBTC form, and then will be transferred to wRBTC loan pool *

function withdrawFeesAMM(address[] _converters) public nonpayable

Arguments

Name Type Description
_converters address[] array addresses of the converters
Source Code
on withdrawFeesAMM(address[] memory _converters) public {
        IWrbtcERC20 wRBTCToken = protocol.wrbtcToken();

        // Validate
        _validateWhitelistedConverter(_converters);

        uint96 totalPoolTokenAmount;
        for (uint256 i = 0; i < _converters.length; i++) {
            uint256 wrbtcAmountWithdrawn =
                IConverterAMM(_converters[i]).withdrawFees(address(this));

            if (wrbtcAmountWithdrawn > 0) {
                // unwrap wrbtc to rbtc, and hold the rbtc
                wRBTCToken.withdraw(wrbtcAmountWithdrawn);

                /// @notice Update unprocessed amount of tokens
                uint96 amount96 =
                    safe96(
                        wrbtcAmountWithdrawn,
                        "FeeSharingCollector::withdrawFeesAMM: wrbtc token amount exceeds 96 bits"
                    );

                totalPoolTokenAmount = add96(
                    totalPoolTokenAmount,
                    amount96,
                    "FeeSharingCollector::withdrawFeesAMM: total wrbtc token amount exceeds 96 bits"
                );

                emit FeeAMMWithdrawn(msg.sender, _converters[i], wrbtcAmountWithdrawn);
            }
        }

        if (totalPoolTokenAmount > 0) {
            _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, totalPoolTokenAmount);
        }
    }

transferTokens

⤾ overrides IFeeSharingCollector.transferTokens

Transfer tokens to this contract.

function transferTokens(address _token, uint96 _amount) public nonpayable

Arguments

Name Type Description
_token address Address of the token.
_amount uint96 Amount to be transferred.
Source Code
on transferTokens(address _token, uint96 _amount) public {
        require(_token != ZERO_ADDRESS, "FeeSharingCollector::transferTokens: invalid address");
        require(_amount > 0, "FeeSharingCollector::transferTokens: invalid amount");

        /// @notice Transfer tokens from msg.sender
        bool success = IERC20(_token).transferFrom(address(msg.sender), address(this), _amount);
        require(success, "Staking::transferTokens: token transfer failed");

        // if _token is wrbtc, need to unwrap it to rbtc
        IWrbtcERC20 wrbtcToken = protocol.wrbtcToken();
        if (_token == address(wrbtcToken)) {
            wrbtcToken.withdraw(_amount);
            _token = RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;
        }

        _addCheckpoint(_token, _amount);

        emit TokensTransferred(msg.sender, _token, _amount);
    }

transferRBTC

Transfer RBTC / native tokens to this contract.

function transferRBTC() external payable
Source Code
on transferRBTC() external payable {
        uint96 _amount = uint96(msg.value);
        require(_amount > 0, "FeeSharingCollector::transferRBTC: invalid value");

        _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, _amount);

        emit TokensTransferred(msg.sender, ZERO_ADDRESS, _amount);
    }

_addCheckpoint

Add checkpoint with accumulated amount by function invocation.

function _addCheckpoint(address _token, uint96 _amount) internal nonpayable

Arguments

Name Type Description
_token address Address of the token.
_amount uint96
Source Code
on _addCheckpoint(address _token, uint96 _amount) internal {
        if (block.timestamp - lastFeeWithdrawalTime[_token] >= FEE_WITHDRAWAL_INTERVAL) {
            lastFeeWithdrawalTime[_token] = block.timestamp;
            uint96 amount =
                add96(
                    unprocessedAmount[_token],
                    _amount,
                    "FeeSharingCollector::_addCheckpoint: amount exceeds 96 bits"
                );

            /// @notice Reset unprocessed amount of tokens to zero.
            unprocessedAmount[_token] = 0;

            /// @notice Write a regular checkpoint.
            _writeTokenCheckpoint(_token, amount);
        } else {
            unprocessedAmount[_token] = add96(
                unprocessedAmount[_token],
                _amount,
                "FeeSharingCollector::_addCheckpoint: unprocessedAmount exceeds 96 bits"
            );
        }
    }

_withdraw

function _withdraw(address _token, uint32 _maxCheckpoints, address _receiver) internal nonpayable

Arguments

Name Type Description
_token address
_maxCheckpoints uint32
_receiver address
Source Code
on _withdraw(
        address _token,
        uint32 _maxCheckpoints,
        address _receiver
    ) internal {
        /// @dev Prevents block gas limit hit when processing checkpoints
        require(
            _maxCheckpoints > 0,
            "FeeSharingCollector::withdraw: _maxCheckpoints should be positive"
        );

        address wRBTCAddress = address(protocol.wrbtcToken());
        address loanPoolTokenWRBTC = _getAndValidateLoanPoolWRBTC(wRBTCAddress);

        address user = msg.sender;
        if (_receiver == ZERO_ADDRESS) {
            _receiver = msg.sender;
        }
        uint256 processedUserCheckpoints = processedCheckpoints[user][_token];
        (uint256 amount, uint256 end) =
            _getAccumulatedFees(user, _token, processedUserCheckpoints, _maxCheckpoints);
        if (amount == 0) {
            if (end > processedUserCheckpoints) {
                emit UserFeeProcessedNoWithdraw(msg.sender, _token, processedUserCheckpoints, end);
                processedCheckpoints[user][_token] = end;
                return;
            } else {
                // getting here most likely means smth wrong with the state
                revert("FeeSharingCollector::withdrawFees: no tokens for withdrawal");
            }
        }

        processedCheckpoints[user][_token] = end;
        if (loanPoolTokenWRBTC == _token) {
            // We will change, so that feeSharingCollector will directly burn then loanToken (IWRBTC) to rbtc and send to the user --- by call burnToBTC function
            ILoanTokenWRBTC(_token).burnToBTC(_receiver, amount, false);
        } else {
            // Previously it directly send the loanToken to the user
            require(
                IERC20(_token).transfer(_receiver, amount),
                "FeeSharingCollector::withdraw: withdrawal failed"
            );
        }

        emit UserFeeWithdrawn(msg.sender, _receiver, _token, amount);
    }

withdraw

⤾ overrides IFeeSharingCollector.withdraw

Withdraw accumulated fee to the message sender. * The Sovryn protocol collects fees on every trade/swap and loan. These fees will be distributed to SOV stakers based on their voting power as a percentage of total voting power. Therefore, staking more SOV and/or staking for longer will increase your share of the fees generated, meaning you will earn more from staking. * This function will directly burnToBTC and use the msg.sender (user) as the receiver *

function withdraw(address _token, uint32 _maxCheckpoints, address _receiver) public nonpayable nonReentrant 

Arguments

Name Type Description
_token address RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.
_maxCheckpoints uint32 Maximum number of checkpoints to be processed. Must be positive value.
_receiver address The receiver of tokens or msg.sender
Source Code
on withdraw(
        address _token,
        uint32 _maxCheckpoints,
        address _receiver
    ) public nonReentrant {
        _withdraw(_token, _maxCheckpoints, _receiver);
    }

withdrawStartingFromCheckpoint

Withdraw accumulated fee to the message sender/receiver. * The Sovryn protocol collects fees on every trade/swap and loan. These fees will be distributed to SOV stakers based on their voting power as a percentage of total voting power. * This function will directly burnToBTC and use the msg.sender (user) as the receiver *

function withdrawStartingFromCheckpoint(address _token, uint256 _fromCheckpoint, uint32 _maxCheckpoints, address _receiver) public nonpayable validFromCheckpointParam nonReentrant 

Arguments

Name Type Description
_token address RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.
_fromCheckpoint uint256 Skips all the checkpoints before '_fromCheckpoint' should be calculated offchain with getNextPositiveUserCheckpoint function
_maxCheckpoints uint32 Maximum number of checkpoints to be processed.
_receiver address The receiver of tokens or msg.sender
Source Code
on withdrawStartingFromCheckpoint(
        address _token,
        uint256 _fromCheckpoint,
        uint32 _maxCheckpoints,
        address _receiver
    ) public validFromCheckpointParam(_fromCheckpoint, msg.sender, _token) nonReentrant {
        // @dev e.g. _fromCheckpoint == 10 meaning we should set 9 user's processed checkpoints
        // after _withdraw() the user's processedCheckpoints should be 10
        uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);
        if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {
            processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;
        }
        _withdraw(_token, _maxCheckpoints, _receiver);
    }

_withdrawRBTC

function _withdrawRBTC(uint32 _maxCheckpoints, address _receiver) internal nonpayable

Arguments

Name Type Description
_maxCheckpoints uint32
_receiver address
Source Code
on _withdrawRBTC(uint32 _maxCheckpoints, address _receiver) internal {
        uint256 wrbtcAmount;
        uint256 rbtcAmount;
        uint256 iWrbtcAmount;
        uint256 endRBTC;
        uint256 endWRBTC;
        uint256 endIWRBTC;
        uint256 iWRBTCloanAmountPaid;
        address user = msg.sender;

        IWrbtcERC20 wrbtcToken = protocol.wrbtcToken();

        address loanPoolTokenWRBTC = _getAndValidateLoanPoolWRBTC(address(wrbtcToken));

        if (_receiver == ZERO_ADDRESS) {
            _receiver = msg.sender;
        }

        (rbtcAmount, wrbtcAmount, iWrbtcAmount, endRBTC, endWRBTC, endIWRBTC) = _getRBTCBalances(
            user,
            _maxCheckpoints
        );

        if (rbtcAmount > 0) {
            processedCheckpoints[user][RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT] = endRBTC;
        }

        // unwrap the wrbtc
        if (wrbtcAmount > 0) {
            processedCheckpoints[user][address(wrbtcToken)] = endWRBTC;
            wrbtcToken.withdraw(wrbtcAmount);
        }

        // pull out the iWRBTC to rbtc to this feeSharingCollector contract
        if (iWrbtcAmount > 0) {
            processedCheckpoints[user][loanPoolTokenWRBTC] = endIWRBTC;
            iWRBTCloanAmountPaid = ILoanTokenWRBTC(loanPoolTokenWRBTC).burnToBTC(
                address(this),
                iWrbtcAmount,
                false
            );
        }

        uint256 totalAmount = rbtcAmount.add(wrbtcAmount).add(iWRBTCloanAmountPaid);
        require(totalAmount > 0, "FeeSharingCollector::withdrawFees: no rbtc for a withdrawal");

        // withdraw everything
        (bool success, ) = _receiver.call.value(totalAmount)("");
        require(success, "FeeSharingCollector::withdrawRBTC: Withdrawal failed");

        emit RBTCWithdrawn(user, _receiver, totalAmount);
    }

withdrawRBTC

withdraw all of the RBTC balance based on particular checkpoints * RBTC balance consists of:

  • rbtc balance
  • wrbtc balance which will be unwrapped to rbtc
  • iwrbtc balance which will be unwrapped to rbtc *
function withdrawRBTC(uint32 _maxCheckpoints, address _receiver) external nonpayable nonReentrant 

Arguments

Name Type Description
_maxCheckpoints uint32 Maximum number of checkpoints to be processed to workaround block gas limit
_receiver address An optional tokens receiver (msg.sender used if 0)
Source Code
on withdrawRBTC(uint32 _maxCheckpoints, address _receiver) external nonReentrant {
        _withdrawRBTC(_maxCheckpoints, _receiver);
    }

withdrawRBTCStartingFromCheckpoint

Withdraw all of the RBTC balance based starting from a specific checkpoint The function was designed to skip checkpoints with no fees for users * RBTC balance consists of:

  • rbtc balance
  • wrbtc balance which will be unwrapped to rbtc
  • iwrbtc balance which will be unwrapped to rbtc *
function withdrawRBTCStartingFromCheckpoint(uint256 _fromCheckpoint, uint32 _maxCheckpoints, address _receiver) external nonpayable validFromCheckpointParam nonReentrant 

Arguments

Name Type Description
_fromCheckpoint uint256 Skips all the checkpoints before '_fromCheckpoint' should be calculated offchain with getNextPositiveUserCheckpoint function
_maxCheckpoints uint32 Maximum number of checkpoints to be processed to workaround block gas limit
_receiver address An optional tokens receiver (msg.sender used if 0)
Source Code
on withdrawRBTCStartingFromCheckpoint(
        uint256 _fromCheckpoint,
        uint32 _maxCheckpoints,
        address _receiver
    )
        external
        validFromCheckpointParam(_fromCheckpoint, msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT)
        nonReentrant
    {
        // @dev e.g. _fromCheckpoint == 10
        // after _withdraw() user's processedCheckpoints should be 10 =>
        // set processed checkpoints = 9, next maping index = 9 (10th checkpoint)
        uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);
        if (
            prevFromCheckpoint >
            processedCheckpoints[msg.sender][RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT]
        ) {
            processedCheckpoints[msg.sender][
                RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT
            ] = prevFromCheckpoint;
        }
        _withdrawRBTC(_maxCheckpoints, _receiver);
    }

getNextPositiveUserCheckpoint

Returns first user's checkpoint with weighted stake > 0 *

function getNextPositiveUserCheckpoint(address _user, address _token, uint256 _startFrom, uint256 _maxCheckpoints) external view
returns(checkpointNum uint256, hasSkippedCheckpoints bool, hasFees bool)

Arguments

Name Type Description
_user address The address of the user or contract.
_token address RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.
_startFrom uint256 Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.
_maxCheckpoints uint256 Max checkpoints to process in a row to avoid timeout error

Returns

[checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]

Source Code
on getNextPositiveUserCheckpoint(
        address _user,
        address _token,
        uint256 _startFrom,
        uint256 _maxCheckpoints
    )
        external
        view
        returns (
            uint256 checkpointNum,
            bool hasSkippedCheckpoints,
            bool hasFees
        )
    {
        if (staking.isVestingContract(_user)) {
            return (0, false, false);
        }
        require(_maxCheckpoints > 0, "_maxCheckpoints must be > 0");

        uint256 totalCheckpoints = totalTokenCheckpoints[_token];
        uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];

        if (processedUserCheckpoints >= totalCheckpoints || totalCheckpoints == 0) {
            return (totalCheckpoints, false, false);
        }

        uint256 startFrom =
            _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;

        uint256 end = startFrom.add(_maxCheckpoints);
        if (end >= totalCheckpoints) {
            end = totalCheckpoints;
        }

        // @note here processedUserCheckpoints is a number of processed checkpoints and
        // also an index for the next checkpoint because an array index starts wtih 0
        for (uint256 i = startFrom; i < end; i++) {
            Checkpoint storage tokenCheckpoint = tokenCheckpoints[_token][i];
            uint96 weightedStake =
                staking.getPriorWeightedStake(
                    _user,
                    tokenCheckpoint.blockNumber - 1,
                    tokenCheckpoint.timestamp
                );
            if (weightedStake > 0) {
                // i is the index and we need to return checkpoint num which is i + 1
                return (i + 1, i > processedUserCheckpoints, true);
            }
        }
        return (end, end > processedUserCheckpoints, false);
    }

getAccumulatedFees

Get the accumulated loan pool fee of the message sender.

function getAccumulatedFees(address _user, address _token) public view
returns(uint256)

Arguments

Name Type Description
_user address The address of the user or contract.
_token address RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.

Returns

The accumulated fee for the message sender.

Source Code
on getAccumulatedFees(address _user, address _token) public view returns (uint256) {
        uint256 amount;
        (amount, ) = _getAccumulatedFees({
            _user: _user,
            _token: _token,
            _startFrom: 0,
            _maxCheckpoints: 0
        });
        return amount;
    }

getAccumulatedFeesForCheckpointsRange

Get the accumulated fee rewards for the message sender for a checkpoints range *

function getAccumulatedFeesForCheckpointsRange(address _user, address _token, uint256 _startFrom, uint32 _maxCheckpoints) external view
returns(uint256)

Arguments

Name Type Description
_user address The address of a user (staker) or contract.
_token address RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.
_startFrom uint256 Checkpoint to start calculating fees from.
_maxCheckpoints uint32 maxCheckpoints to get accumulated fees for the _user

Returns

The accumulated fees rewards for the _user in the given checkpoints interval: [_startFrom, _startFrom + maxCheckpoints].

Source Code
on getAccumulatedFeesForCheckpointsRange(
        address _user,
        address _token,
        uint256 _startFrom,
        uint32 _maxCheckpoints
    ) external view returns (uint256) {
        uint256 amount;
        (amount, ) = _getAccumulatedFees(_user, _token, _startFrom, _maxCheckpoints);
        return amount;
    }

_getAccumulatedFees

Gets accumulated fees for a user starting from a given checkpoint *

function _getAccumulatedFees(address _user, address _token, uint256 _startFrom, uint32 _maxCheckpoints) internal view
returns(feesAmount uint256, endCheckpoint uint256)

Arguments

Name Type Description
_user address Address of the user's account.
_token address RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.
_startFrom uint256 Checkpoint num to start calculations from *
_maxCheckpoints uint32 Max checkpoints to process at once to fit into block gas limit

Returns

feesAmount - accumulated fees amount

Source Code
on _getAccumulatedFees(
        address _user,
        address _token,
        uint256 _startFrom,
        uint32 _maxCheckpoints
    ) internal view returns (uint256 feesAmount, uint256 endCheckpoint) {
        if (staking.isVestingContract(_user)) {
            return (0, 0);
        }
        uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];
        uint256 startOfRange =
            _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;
        endCheckpoint = _maxCheckpoints > 0
            ? _getEndOfRange(startOfRange, _token, _maxCheckpoints)
            : totalTokenCheckpoints[_token];

        if (startOfRange >= totalTokenCheckpoints[_token]) {
            return (0, endCheckpoint);
        }

        uint256 cachedLockDate = 0;
        uint96 cachedWeightedStake = 0;
        // @note here processedUserCheckpoints is a number of processed checkpoints and
        // also an index for the next checkpoint because an array index starts wtih 0
        for (uint256 i = startOfRange; i < endCheckpoint; i++) {
            Checkpoint memory checkpoint = tokenCheckpoints[_token][i];
            uint256 lockDate = staking.timestampToLockDate(checkpoint.timestamp);
            uint96 weightedStake;
            if (lockDate == cachedLockDate) {
                weightedStake = cachedWeightedStake;
            } else {
                /// @dev We need to use "checkpoint.blockNumber - 1" here to calculate weighted stake
                /// For the same block like we did for total voting power in _writeTokenCheckpoint
                weightedStake = staking.getPriorWeightedStake(
                    _user,
                    checkpoint.blockNumber - 1,
                    checkpoint.timestamp
                );
                cachedWeightedStake = weightedStake;
                cachedLockDate = lockDate;
            }
            uint256 share =
                uint256(checkpoint.numTokens).mul(weightedStake).div(
                    uint256(checkpoint.totalWeightedStake)
                );
            feesAmount = feesAmount.add(share);
        }
        return (feesAmount, endCheckpoint);
    }

_getEndOfRange

Withdrawal should only be possible for blocks which were already mined. If the fees are withdrawn in the same block as the user withdrawal they are not considered by the withdrawing logic (to avoid inconsistencies). *

function _getEndOfRange(uint256 _start, address _token, uint32 _maxCheckpoints) internal view
returns(uint256)

Arguments

Name Type Description
_start uint256 Start of the range.
_token address RBTC dummy to fit into existing data structure or SOV. Former address of a pool token.
_maxCheckpoints uint32 Checkpoint index incremental.
Source Code
on _getEndOfRange(
        uint256 _start,
        address _token,
        uint32 _maxCheckpoints
    ) internal view returns (uint256) {
        uint256 nextCheckpointIndex = totalTokenCheckpoints[_token];
        if (nextCheckpointIndex == 0) {
            return 0;
        }
        uint256 end;

        if (_maxCheckpoints == 0) {
            /// @dev All checkpoints will be processed (only for getter outside of a transaction).
            end = nextCheckpointIndex;
        } else {
            end = safe32(
                _start + _maxCheckpoints,
                "FeeSharingCollector::withdraw: checkpoint index exceeds 32 bits"
            );
            if (end > nextCheckpointIndex) {
                end = nextCheckpointIndex;
            }
        }

        /// @dev Withdrawal should only be possible for blocks which were already mined.
        uint32 lastBlockNumber = tokenCheckpoints[_token][end - 1].blockNumber;
        if (block.number == lastBlockNumber) {
            end--;
        }
        return end;
    }

_writeTokenCheckpoint

Write a regular checkpoint w/ the foolowing data: block number, block timestamp, total weighted stake and num of tokens.

function _writeTokenCheckpoint(address _token, uint96 _numTokens) internal nonpayable

Arguments

Name Type Description
_token address The pool token address.
_numTokens uint96 The amount of pool tokens.
Source Code
on _writeTokenCheckpoint(address _token, uint96 _numTokens) internal {
        uint32 blockNumber =
            safe32(
                block.number,
                "FeeSharingCollector::_writeCheckpoint: block number exceeds 32 bits"
            );
        uint32 blockTimestamp =
            safe32(
                block.timestamp,
                "FeeSharingCollector::_writeCheckpoint: block timestamp exceeds 32 bits"
            );
        uint256 nextCheckpointsIndex = totalTokenCheckpoints[_token];

        uint96 totalWeightedStake = _getVoluntaryWeightedStake(blockNumber - 1, block.timestamp);
        require(totalWeightedStake > 0, "Invalid totalWeightedStake");
        if (
            nextCheckpointsIndex > 0 &&
            tokenCheckpoints[_token][nextCheckpointsIndex - 1].blockNumber == blockNumber
        ) {
            tokenCheckpoints[_token][nextCheckpointsIndex - 1]
                .totalWeightedStake = totalWeightedStake;
            tokenCheckpoints[_token][nextCheckpointsIndex - 1].numTokens = _numTokens;
        } else {
            tokenCheckpoints[_token][nextCheckpointsIndex] = Checkpoint(
                blockNumber,
                blockTimestamp,
                totalWeightedStake,
                _numTokens
            );
            totalTokenCheckpoints[_token] = nextCheckpointsIndex + 1;
        }
        emit CheckpointAdded(msg.sender, _token, _numTokens);
    }

_getVoluntaryWeightedStake

function _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp) internal view
returns(totalWeightedStake uint96)

Arguments

Name Type Description
blockNumber uint32 the blocknumber
timestamp uint256 the timestamp
Source Code
on _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp)
        internal
        view
        returns (uint96 totalWeightedStake)
    {
        uint96 vestingWeightedStake = staking.getPriorVestingWeightedStake(blockNumber, timestamp);
        totalWeightedStake = staking.getPriorTotalVotingPower(blockNumber, timestamp);
        totalWeightedStake = sub96(
            totalWeightedStake,
            vestingWeightedStake,
            "FeeSharingCollector::_getTotalVoluntaryWeightedStake: vested stake exceeds total stake"
        );
    }

addWhitelistedConverterAddress

Whitelisting converter address. *

function addWhitelistedConverterAddress(address converterAddress) external nonpayable onlyOwner 

Arguments

Name Type Description
converterAddress address converter address to be whitelisted.
Source Code
on addWhitelistedConverterAddress(address converterAddress) external onlyOwner {
        require(Address.isContract(converterAddress), "Non contract address given");
        whitelistedConverterList.add(converterAddress);
        emit WhitelistedConverter(msg.sender, converterAddress);
    }

removeWhitelistedConverterAddress

Removing converter address from whitelist. *

function removeWhitelistedConverterAddress(address converterAddress) external nonpayable onlyOwner 

Arguments

Name Type Description
converterAddress address converter address to be removed from whitelist.
Source Code
on removeWhitelistedConverterAddress(address converterAddress) external onlyOwner {
        whitelistedConverterList.remove(converterAddress);
        emit UnwhitelistedConverter(msg.sender, converterAddress);
    }

getWhitelistedConverterList

Getter to query all of the whitelisted converter.

function getWhitelistedConverterList() external view
returns(converterList address[])
Source Code
on getWhitelistedConverterList() external view returns (address[] memory converterList) {
        converterList = whitelistedConverterList.enumerate();
    }

_validateWhitelistedConverter

validate array of given address whether is whitelisted or not.

function _validateWhitelistedConverter(address[] converterAddresses) private view

Arguments

Name Type Description
converterAddresses address[] array of converter addresses.
Source Code
on _validateWhitelistedConverter(address[] memory converterAddresses) private view {
        for (uint256 i = 0; i < converterAddresses.length; i++) {
            require(whitelistedConverterList.contains(converterAddresses[i]), "Invalid Converter");
        }
    }

withdrawWRBTC

function withdrawWRBTC(address receiver, uint256 wrbtcAmount) external nonpayable onlyOwner 

Arguments

Name Type Description
receiver address
wrbtcAmount uint256
Source Code
on withdrawWRBTC(address receiver, uint256 wrbtcAmount) external onlyOwner {
        address wRBTCAddress = address(protocol.wrbtcToken());

        uint256 balance = IERC20(wRBTCAddress).balanceOf(address(this));
        require(wrbtcAmount <= balance, "Insufficient balance");

        IERC20(wRBTCAddress).safeTransfer(receiver, wrbtcAmount);
    }

recoverIncorrectAllocatedFees

This function is dedicated to recover the wrong fee allocation for the 4 year vesting contracts. This function can only be called once The affected tokens to be withdrawn

  1. RBTC
  2. ZUSD
  3. SOV The amount for all of the tokens above is hardcoded The withdrawn tokens will be sent to the owner.
function recoverIncorrectAllocatedFees() external nonpayable oneTimeExecution onlyOwner 
Source Code
on recoverIncorrectAllocatedFees()
        external
        oneTimeExecution(this.recoverIncorrectAllocatedFees.selector)
        onlyOwner
    {
        uint256 rbtcAmount = 878778886164898400;
        uint256 zusdAmount = 16658600400155126000000;
        uint256 sovAmount = 6275898259771202000000;

        address zusdToken = 0xdB107FA69E33f05180a4C2cE9c2E7CB481645C2d;
        address sovToken = 0xEFc78fc7d48b64958315949279Ba181c2114ABBd;

        // Withdraw rbtc
        (bool success, ) = owner().call.value(rbtcAmount)("");
        require(
            success,
            "FeeSharingCollector::recoverIncorrectAllocatedFees: Withdrawal rbtc failed"
        );

        // Withdraw ZUSD
        IERC20(zusdToken).safeTransfer(owner(), zusdAmount);

        // Withdraw SOV
        IERC20(sovToken).safeTransfer(owner(), sovAmount);
    }

getAccumulatedRBTCFeeBalances

view function that calculate the total RBTC that includes:

  • RBTC
  • WRBTC
  • iWRBTC * iWRBTC.tokenPrice()
function getAccumulatedRBTCFeeBalances(address _user) external view
returns(uint256)

Arguments

Name Type Description
_user address address of the user.

Returns

rbtc balance of the given user's address.

Source Code
on getAccumulatedRBTCFeeBalances(address _user) external view returns (uint256) {
        (uint256 _rbtcAmount, uint256 _wrbtcAmount, uint256 _iWrbtcAmount, , , ) =
            _getRBTCBalances(_user, 0);
        IWrbtcERC20 wrbtcToken = protocol.wrbtcToken();
        address loanPoolTokenWRBTC = _getAndValidateLoanPoolWRBTC(address(wrbtcToken));
        uint256 iWRBTCAmountInRBTC =
            _iWrbtcAmount.mul(ILoanTokenWRBTC(loanPoolTokenWRBTC).tokenPrice()).div(1e18);
        return _rbtcAmount.add(_wrbtcAmount).add(iWRBTCAmountInRBTC);
    }

_getRBTCBalances

private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc) *

function _getRBTCBalances(address _user, uint32 _maxCheckpoints) private view
returns(_rbtcAmount uint256, _wrbtcAmount uint256, _iWrbtcAmount uint256, _endRBTC uint256, _endWRBTC uint256, _endIWRBTC uint256)

Arguments

Name Type Description
_user address address of the user.
_maxCheckpoints uint32 maximum checkpoints. *

Returns

_rbtcAmount rbtc amount

Source Code
on _getRBTCBalances(address _user, uint32 _maxCheckpoints)
        private
        view
        returns (
            uint256 _rbtcAmount,
            uint256 _wrbtcAmount,
            uint256 _iWrbtcAmount,
            uint256 _endRBTC,
            uint256 _endWRBTC,
            uint256 _endIWRBTC
        )
    {
        IWrbtcERC20 wrbtcToken = protocol.wrbtcToken();

        address loanPoolTokenWRBTC = _getAndValidateLoanPoolWRBTC(address(wrbtcToken));

        (_rbtcAmount, _endRBTC) = _getAccumulatedFees({
            _user: _user,
            _token: RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT,
            _startFrom: 0,
            _maxCheckpoints: _maxCheckpoints
        });

        (_wrbtcAmount, _endWRBTC) = _getAccumulatedFees({
            _user: _user,
            _token: address(wrbtcToken),
            _startFrom: 0,
            _maxCheckpoints: _maxCheckpoints
        });
        (_iWrbtcAmount, _endIWRBTC) = _getAccumulatedFees({
            _user: _user,
            _token: loanPoolTokenWRBTC,
            _startFrom: 0,
            _maxCheckpoints: _maxCheckpoints
        });
    }

_getAndValidateLoanPoolWRBTC

private function to get and validate the wrbtc loan pool token address based on the wrbtc token address.

function _getAndValidateLoanPoolWRBTC(address _wRBTCAddress) private view
returns(address)

Arguments

Name Type Description
_wRBTCAddress address wrbtc token address. *

Returns

wrbtc loan pool wrbtc token address

Source Code
on _getAndValidateLoanPoolWRBTC(address _wRBTCAddress) private view returns (address) {
        address loanPoolTokenWRBTC = protocol.underlyingToLoanPool(_wRBTCAddress);
        require(
            loanPoolTokenWRBTC != ZERO_ADDRESS,
            "FeeSharingCollector::withdraw: loan wRBTC not found"
        );

        return loanPoolTokenWRBTC;
    }

numTokenCheckpoints

This getter function numTokenCheckpoints is added for backwards compatibility broken when renamed numTokenCheckpoints storage variable to totalTokenCheckpoints. *

function numTokenCheckpoints(address _token) external view
returns(uint256)

Arguments

Name Type Description
_token address token address to get checkpoints for *

Returns

Total token checkpoints

Source Code
on numTokenCheckpoints(address _token) external view returns (uint256) {
        return totalTokenCheckpoints[_token];
    }
}

/*

mint

function mint(address receiver, uint256 depositAmount) external nonpayable
returns(mintAmount uint256)

Arguments

Name Type Description
receiver address
depositAmount uint256
Source Code
on mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);
}

in

burnToBTC

function burnToBTC(address receiver, uint256 burnAmount, bool useLM) external nonpayable
returns(loanAmountPaid uint256)

Arguments

Name Type Description
receiver address
burnAmount uint256
useLM bool
Source Code
on burnToBTC(
        address receiver,
        uint256 burnAmount,
        bool useLM
    ) external returns (uint256 loanAmountPaid);

tokenPrice

function tokenPrice() external view
returns(price uint256)
Source Code
on tokenPrice() external view returns (uint256 price);
}

Contracts