Rebalance WUSD

In the event that the pooled stablecoin supply collateralizing WUSD deviates from the WUSD supply, it is possible to rebalance the WUSD supply to restore equilibrium.

  • collateral supply > WUSD supply -> credit rebalancing situation

  • collateral supply < WUSD supply -> possible debit rebalancing situation

The differences function of the WUSDExtensionController contract is responsible for checking and quantifying the difference between the collateral supply and WUSD supply:

function differences()
    public
    view
    returns (uint256 credit, uint256 debt)
{

It retrieves the WUSD supply by calling the totalSupply function on the native WUSD collection. Then, for every pool of every AMM supported by the WUSD protocol, it retrieves the amount of stablecoins pooled as collateral:

uint256 totalSupply = INativeV1(_collection).totalSupply(_wusdObjectId);
uint256 effectiveAmount = 0;
for(uint256 i = 0; i < _allowedAMMs.length; i++) {
    for(uint256 j = 0; j < _allowedAMMs[i].liquidityPools.length; j++) {
        effectiveAmount += _normalizeAndSumAmounts(i, j, 0);
    }
}

Then we may be faced with either of the two possible rebalancing situations described above:

credit = effectiveAmount > totalSupply
    ? effectiveAmount - totalSupply
    : 0;
debt = totalSupply > effectiveAmount
    ? totalSupply - effectiveAmount
    : 0;

Rebalance by Credit

To perform a credit rebalancing, it is necessary to use the rebalanceByCredit public function of the WUSDExtensionController contract.

If the rebalance can be performed, the WUSD extension's mintForRebalanceByCredit function is called to mint the required amount of WUSD:

uint256 credit = WUSDExtension(_extension).mintForRebalanceByCredit(_allowedAMMs);
uint256 availableCredit = credit;

The mintForRebalanceByCredit function automatically mints the amount of WUSD equal to the difference between the collateral supply and the WUSD supply, and sends it to the WUSDExtensionController contract.

Then, the newly minted WUSD is distributed as follows:

  • 2% to the executor of the rebalancing (as a reward)

if(_rebalanceByCreditPercentageForCaller > 0) {
    IERC20(_wusdInteroperableInterfaceAddress).transfer(msg.sender, reward = _calculatePercentage(credit, _rebalanceByCreditPercentageForCaller));
    availableCredit -= reward;
}
if(availableCredit > 0) {
   IERC20(_wusdInteroperableInterfaceAddress).transfer(IMVDProxy(IDoubleProxy(_doubleProxy).proxy()).getMVDWalletAddress(), availableCredit);
}
for(uint256 i = 0; i < _rebalanceByCreditReceivers.length; i++) {
    IERC20(_wusdInteroperableInterfaceAddress).transfer(_rebalanceByCreditReceivers[i], reward = _calculatePercentage(credit, _rebalanceByCreditPercentages[i]));
    availableCredit -= reward;
}
 if(_wusdNote2Percentage > 0) {
     IERC20(_wusdInteroperableInterfaceAddress).transfer(_wusdNote2Controller, reward = _calculatePercentage(credit, _wusdNote2Percentage));
     availableCredit -= reward;
 }
if(_wusdNote5Percentage > 0) {
    IERC20(_wusdInteroperableInterfaceAddress).transfer(_wusdNote5Controller, reward = _calculatePercentage(credit, _wusdNote5Percentage));
    availableCredit -= reward;
}

Rebalance by Debit

For debit rebalancing, the difference between the WUSD supply and the collateral supply must be equal to or greater than the minimumRebalanceByDebtAmount amount set up in the contract.

To perform a debit rebalance, use the safeTransferFrom or safeBatchTransferFrom method directly from the WUSD token collection itself, as follows:

  • from -> address sender

  • to -> WUSDExtensionController address

  • objectId/s -> WUSD object Id

  • amount/s -> WUSD amount to rebalance, or an array containing the amounts in the case of safeBatchTransferFrom

  • data

Regarding the data input:

The payload must contain a value equal to "1" to rebalance the WUSD token amount. If the value passed is other than 1, a burn is called. In addition, the payload must contain the value "2" or "5" depending on the credit note (x2 or x5) to be obtained from the rebalance.

The onERC1155Received/onERC1155BatchReceived function rebalances the WUSD amount that arrives in theWUSDExtensionController contract by calling internally the _onSingleReceived function. It takes the payload sent via safeTransferFrom/safeBatchTransferFrom and distinguishes between two cases: if the payload value is equal to 1, it will perform a rebalance; if different from 1, it will perform a burn:

if(action == 1) {
    _rebalanceByDebt(from, value, payload);
} else {
    _burn(from, value, payload);
}

The _rebalanceByDebt function calculates the amount to rebalance using the differences function and checks that this amount is at least equal to the minimumRebalanceByDebtAmount :

(, uint256 debt) = differences();
require(debt >= minimumRebalanceByDebtAmount, "Insufficient debt");

Then the payload is decoded to retrieve the information about the desired credit note (x2/x5)

uint256 note = abi.decode(payload, (uint256))

Subsequently, the safeApprove function is called to allow the extension to use the amount of WUSD to be rebalanced, and to allow the extension _burnFor function, passing the objectId of either the x2 or the x5 credit note as requested:

_safeApprove(_wusdInteroperableInterfaceAddress, _extension, INativeV1(_collection).toInteroperableInterfaceAmount(_wusdObjectId, value));
WUSDExtension(_extension).burnFor(note == 2 ? _wusdNote2ObjectId : _wusdNote5ObjectId, value, from);

So, the _burnFor method of the extension contract takes the WUSD amount from the WUSDExtensionController via _safeTransferFrom and burns that amount by calling burn

 _safeTransferFrom(_mainItemInteroperableAddress, msg.sender, address(this), INativeV1(_collection).toInteroperableInterfaceAmount(_mainItemObjectId, value));
 INativeV1(_collection).burn(_mainItemObjectId, value);

Finally, the proportionate amount of requested credit notes (x2 or x5) are minted and sent to the user who called the rebalance by debit operation.

Please refer to the WUSD Frontend Integration section for more details.

Last updated