Ensure that the contract verifies whether the caller has approved the required amount for burning before calling updateNetUsdTokenIssuance()
.
function withdrawUsdTokenFromMarket(uint128 marketId, uint256 amount) external onlyRegisteredEngine(marketId) {
// loads the market's data and connected vaults
Market.Data storage market = Market.loadLive(marketId);
uint256[] memory connectedVaults = market.getConnectedVaultsIds();
// once the unrealized debt is distributed update credit delegated
// by these vaults to the market
Vault.recalculateVaultsCreditCapacity(connectedVaults);
// cache the market's total debt and delegated credit
SD59x18 marketTotalDebtUsdX18 = market.getTotalDebt();
UD60x18 delegatedCreditUsdX18 = market.getTotalDelegatedCreditUsd();
// calculate the market's credit capacity
SD59x18 creditCapacityUsdX18 = Market.getCreditCapacityUsd(delegatedCreditUsdX18, marketTotalDebtUsdX18);
// enforces that the market has enough credit capacity, if it's a listed market it must always have some
// delegated credit, see Vault.Data.lockedCreditRatio.
// NOTE: additionally, the ADL system if functioning properly must ensure that the market always has credit
// capacity to cover USD Token mint requests. Deleverage happens when the perps engine calls
// CreditDelegationBranch::getAdjustedProfitForMarketId.
// NOTE: however, it still is possible to fall into a scenario where the credit capacity is <= 0, as the
// delegated credit may be provided in form of volatile collateral assets, which could go down in value as
// debt reaches its ceiling. In that case, the market will run out of mintable USD Token and the mm engine
// must settle all outstanding debt for USDC, in order to keep previously paid USD Token fully backed.
if (creditCapacityUsdX18.lte(SD59x18_ZERO)) {
revert Errors.InsufficientCreditCapacity(marketId, creditCapacityUsdX18.intoInt256());
}
// uint256 -> UD60x18
// NOTE: we don't need to scale decimals here as it's known that USD Token has 18 decimals
UD60x18 amountX18 = ud60x18(amount);
// prepare the amount of usdToken that will be minted to the perps engine;
// initialize to default non-ADL state
uint256 amountToMint = amount;
+ MarketMakingEngineConfiguration.Data storage marketMakingEngineConfiguration =
+ MarketMakingEngineConfiguration.load();
+ UsdToken usdToken = UsdToken(marketMakingEngineConfiguration.usdTokenOfEngine[msg.sender]);
+ // Check allowance before burning tokens
+ uint256 allowance = usdToken.allowance(msg.sender, address(this));
+ require(allowance >= amount, "Insufficient allowance for burn");
// now we realize the added usd debt of the market
// note: USD Token is assumed to be 1:1 with the system's usd accounting
if (market.isAutoDeleverageTriggered(delegatedCreditUsdX18, marketTotalDebtUsdX18)) {
// if the market is in the ADL state, it reduces the requested USD
// Token amount by multiplying it by the ADL factor, which must be < 1
UD60x18 adjustedUsdTokenToMintX18 =
market.getAutoDeleverageFactor(delegatedCreditUsdX18, marketTotalDebtUsdX18).mul(amountX18);
amountToMint = adjustedUsdTokenToMintX18.intoUint256();
market.updateNetUsdTokenIssuance(adjustedUsdTokenToMintX18.intoSD59x18());
} else {
// if the market is not in the ADL state, it realizes the full requested USD Token amount
market.updateNetUsdTokenIssuance(amountX18.intoSD59x18());
}
// loads the market making engine configuration storage pointer
- MarketMakingEngineConfiguration.Data storage marketMakingEngineConfiguration =
- MarketMakingEngineConfiguration.load();
// mint USD Token to the perps engine
- UsdToken usdToken = UsdToken(marketMakingEngineConfiguration.usdTokenOfEngine[msg.sender]);
usdToken.mint(msg.sender, amountToMint);
// emit an event
emit LogWithdrawUsdTokenFromMarket(msg.sender, marketId, amount, amountToMint);
}