Files
smom-dbis-138/contracts/flash/DBISEngineXVirtualBatchVault.sol
defiQUG 76143a8fe3 feat(token-aggregation): reports, PMM quotes, config; Engine X flash vaults
- Expand token-aggregation API (report routes), canonical tokens, pools
- Add flash vault contracts + tests (indexed, DODO cwUSDC, XAUT borrow)
- PMM pools JSON, deploy/export scripts, metamask verified list

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 12:56:30 -07:00

471 lines
18 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import {IERC3156FlashLender} from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/// @notice Engine X maintained proof vault with virtual batch settlement.
/// @dev Use only for accounting proofs: it compresses identical maintained loops into one net settlement.
contract DBISEngineXVirtualBatchVault is IERC3156FlashLender, Ownable, ReentrancyGuard {
using SafeERC20 for IERC20;
bytes32 private constant _FLASH_RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
uint256 public constant MAX_FLASH_FEE_BPS = 1_000;
IERC20 public immutable cWUSDC;
IERC20 public immutable usdc;
IERC20 public immutable xaut;
uint256 public poolCwusdcReserve;
uint256 public poolUsdcReserve;
uint256 public lenderUsdcAvailable;
uint256 public totalNeutralizedCwusdc;
uint256 public totalVirtualLoops;
uint256 public totalVirtualDebtUsdc;
uint256 public totalVirtualCwusdcIn;
uint256 public totalFlashFeesCollectedUsdc;
uint256 public flashFeeBps = 5;
uint256 public maxFlashLoanAmount;
bool public paused;
bool public flashBorrowerAllowlistEnabled;
mapping(bytes32 => bool) public usedProofIds;
mapping(address => bool) public approvedFlashBorrower;
uint256 public immutable xautUsdPrice6;
uint256 public immutable ltvBps;
uint256 public immutable maxRoundTripLossBps;
address public surplusReceiver;
event PoolSeeded(uint256 cwusdcAmount, uint256 usdcAmount);
event LenderFunded(uint256 usdcAmount);
event SurplusReceiverUpdated(address indexed receiver);
event VirtualProofClosed(
bytes32 indexed proofId,
uint256 virtualLoops,
uint256 debtUsdcPerLoop,
uint256 collateralXaut,
uint256 cwusdcInPerLoop,
uint256 cwusdcOutPerLoop,
uint256 cwusdcLossPerLoop,
uint256 totalCwusdcInAmount,
uint256 totalCwusdcOutAmount,
uint256 totalNeutralizedCwusdcAmount,
uint256 poolCwusdcReserveAfter,
uint256 poolUsdcReserveAfter
);
event VirtualProofAuditEvidence(
bytes32 indexed proofId,
address indexed operator,
address indexed outputRecipient,
uint256 exactOutputAmount,
uint256 outputRoundingAmount,
address roundingReceiver,
bytes32 iso20022DocumentHash,
bytes32 auditEnvelopeHash,
bytes32 pegProofHash
);
event PoolLiquidityWithdrawn(address indexed to, uint256 cwusdcAmount, uint256 usdcAmount);
event LenderUsdcWithdrawn(address indexed to, uint256 amount);
event UnaccountedTokenWithdrawn(address indexed token, address indexed to, uint256 amount);
event FlashFeeBpsUpdated(uint256 feeBps);
event MaxFlashLoanAmountUpdated(uint256 amount);
event Paused(address indexed operator);
event Unpaused(address indexed operator);
event FlashBorrowerAllowlistEnabledUpdated(bool enabled);
event FlashBorrowerApprovalUpdated(address indexed borrower, bool approved);
event EngineXFlashLoan(
address indexed initiator,
IERC3156FlashBorrower indexed receiver,
address indexed token,
uint256 amount,
uint256 fee
);
modifier whenNotPaused() {
require(!paused, "paused");
_;
}
constructor(
address cWUSDC_,
address usdc_,
address xaut_,
address owner_,
address surplusReceiver_,
uint256 xautUsdPrice6_,
uint256 ltvBps_,
uint256 maxRoundTripLossBps_
) Ownable(owner_) {
require(cWUSDC_ != address(0) && usdc_ != address(0) && xaut_ != address(0), "zero token");
require(owner_ != address(0), "zero owner");
require(surplusReceiver_ != address(0), "zero receiver");
require(xautUsdPrice6_ > 0, "zero price");
require(ltvBps_ > 0 && ltvBps_ < 10_000, "bad ltv");
require(maxRoundTripLossBps_ > 0 && maxRoundTripLossBps_ < 10_000, "bad loss");
cWUSDC = IERC20(cWUSDC_);
usdc = IERC20(usdc_);
xaut = IERC20(xaut_);
surplusReceiver = surplusReceiver_;
xautUsdPrice6 = xautUsdPrice6_;
ltvBps = ltvBps_;
maxRoundTripLossBps = maxRoundTripLossBps_;
}
function seedPool(uint256 cwusdcAmount, uint256 usdcAmount) external onlyOwner nonReentrant whenNotPaused {
require(cwusdcAmount > 0 && usdcAmount > 0, "zero seed");
cWUSDC.safeTransferFrom(msg.sender, address(this), cwusdcAmount);
usdc.safeTransferFrom(msg.sender, address(this), usdcAmount);
poolCwusdcReserve += cwusdcAmount;
poolUsdcReserve += usdcAmount;
emit PoolSeeded(cwusdcAmount, usdcAmount);
}
function fundLender(uint256 usdcAmount) external onlyOwner nonReentrant whenNotPaused {
require(usdcAmount > 0, "zero fund");
usdc.safeTransferFrom(msg.sender, address(this), usdcAmount);
lenderUsdcAvailable += usdcAmount;
emit LenderFunded(usdcAmount);
}
function setSurplusReceiver(address receiver) external onlyOwner {
require(receiver != address(0), "zero receiver");
surplusReceiver = receiver;
emit SurplusReceiverUpdated(receiver);
}
function pause() external onlyOwner {
paused = true;
emit Paused(msg.sender);
}
function unpause() external onlyOwner {
paused = false;
emit Unpaused(msg.sender);
}
function setFlashFeeBps(uint256 newFlashFeeBps) external onlyOwner {
require(newFlashFeeBps <= MAX_FLASH_FEE_BPS, "fee too high");
flashFeeBps = newFlashFeeBps;
emit FlashFeeBpsUpdated(newFlashFeeBps);
}
function setMaxFlashLoanAmount(uint256 amount) external onlyOwner {
maxFlashLoanAmount = amount;
emit MaxFlashLoanAmountUpdated(amount);
}
function setFlashBorrowerAllowlistEnabled(bool enabled) external onlyOwner {
flashBorrowerAllowlistEnabled = enabled;
emit FlashBorrowerAllowlistEnabledUpdated(enabled);
}
function setFlashBorrowerApproved(address borrower, bool approved) external onlyOwner {
require(borrower != address(0), "zero borrower");
approvedFlashBorrower[borrower] = approved;
emit FlashBorrowerApprovalUpdated(borrower, approved);
}
function previewCwusdcInForExactUsdc(uint256 usdcOut) public view returns (uint256) {
return _getAmountIn(usdcOut, poolCwusdcReserve, poolUsdcReserve);
}
function previewCwusdcOutForExactUsdcIn(uint256 usdcIn) public view returns (uint256) {
return _getAmountOut(usdcIn, poolUsdcReserve, poolCwusdcReserve);
}
function currentSurplusCwusdc() public view returns (uint256) {
return poolCwusdcReserve > poolUsdcReserve ? poolCwusdcReserve - poolUsdcReserve : 0;
}
function maxFlashLoan(address token) external view override returns (uint256) {
if (paused || token != address(usdc)) {
return 0;
}
if (maxFlashLoanAmount == 0 || maxFlashLoanAmount > lenderUsdcAvailable) {
return lenderUsdcAvailable;
}
return maxFlashLoanAmount;
}
function flashFee(address token, uint256 amount) public view override returns (uint256) {
require(token == address(usdc), "unsupported flash token");
return (amount * flashFeeBps) / 10_000;
}
function minimumXautCollateral(uint256 debtUsdc) public view returns (uint256) {
uint256 numerator = debtUsdc * 1e6 * 10_000;
uint256 denominator = xautUsdPrice6 * ltvBps;
return (numerator + denominator - 1) / denominator;
}
function previewVirtualProof(uint256 debtUsdcPerLoop, uint256 virtualLoops)
public
view
returns (
uint256 collateralXaut,
uint256 cwusdcInPerLoop,
uint256 cwusdcOutPerLoop,
uint256 cwusdcLossPerLoop,
uint256 totalCwusdcInAmount,
uint256 totalCwusdcOutAmount,
uint256 totalNeutralizedCwusdcAmount
)
{
require(virtualLoops > 0, "zero loops");
require(poolCwusdcReserve == poolUsdcReserve, "pool not maintained");
require(lenderUsdcAvailable >= debtUsdcPerLoop, "insufficient lender usdc");
collateralXaut = minimumXautCollateral(debtUsdcPerLoop);
cwusdcInPerLoop = _getAmountIn(debtUsdcPerLoop, poolCwusdcReserve, poolUsdcReserve);
uint256 cwusdcReserveAfterIn = poolCwusdcReserve + cwusdcInPerLoop;
uint256 usdcReserveAfterOut = poolUsdcReserve - debtUsdcPerLoop;
cwusdcOutPerLoop = _getAmountOut(debtUsdcPerLoop, usdcReserveAfterOut, cwusdcReserveAfterIn);
cwusdcLossPerLoop = cwusdcInPerLoop - cwusdcOutPerLoop;
require(cwusdcLossPerLoop * 10_000 <= cwusdcInPerLoop * maxRoundTripLossBps, "roundtrip loss too high");
totalCwusdcInAmount = cwusdcInPerLoop * virtualLoops;
totalCwusdcOutAmount = cwusdcOutPerLoop * virtualLoops;
totalNeutralizedCwusdcAmount = cwusdcLossPerLoop * virtualLoops;
}
function runVirtualProof(bytes32 proofId, uint256 debtUsdcPerLoop, uint256 virtualLoops)
external
nonReentrant
whenNotPaused
{
_runVirtualProofFor(
msg.sender, proofId, debtUsdcPerLoop, virtualLoops, 0, msg.sender, bytes32(0), bytes32(0), bytes32(0)
);
}
function runVirtualProofTo(bytes32 proofId, uint256 debtUsdcPerLoop, uint256 virtualLoops, address outputRecipient)
external
nonReentrant
whenNotPaused
{
require(outputRecipient != address(0), "zero output");
_runVirtualProofFor(
outputRecipient, proofId, debtUsdcPerLoop, virtualLoops, 0, msg.sender, bytes32(0), bytes32(0), bytes32(0)
);
}
function runVirtualProofExactOutTo(
bytes32 proofId,
uint256 debtUsdcPerLoop,
uint256 virtualLoops,
address outputRecipient,
uint256 exactOutputAmount,
address roundingReceiver,
bytes32 iso20022DocumentHash,
bytes32 auditEnvelopeHash,
bytes32 pegProofHash
) external nonReentrant whenNotPaused {
require(outputRecipient != address(0), "zero output");
require(exactOutputAmount > 0, "zero exact output");
require(roundingReceiver != address(0), "zero rounding");
require(iso20022DocumentHash != bytes32(0), "zero iso hash");
require(auditEnvelopeHash != bytes32(0), "zero audit hash");
require(pegProofHash != bytes32(0), "zero peg hash");
_runVirtualProofFor(
outputRecipient,
proofId,
debtUsdcPerLoop,
virtualLoops,
exactOutputAmount,
roundingReceiver,
iso20022DocumentHash,
auditEnvelopeHash,
pegProofHash
);
}
function flashLoan(IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data)
external
override
nonReentrant
whenNotPaused
returns (bool)
{
require(token == address(usdc), "unsupported flash token");
require(amount > 0, "zero flash amount");
require(amount <= lenderUsdcAvailable, "insufficient lender usdc");
require(maxFlashLoanAmount == 0 || amount <= maxFlashLoanAmount, "flash amount too high");
require(
!flashBorrowerAllowlistEnabled || approvedFlashBorrower[address(receiver)], "flash borrower not approved"
);
uint256 fee = flashFee(token, amount);
uint256 balanceBefore = usdc.balanceOf(address(this));
require(balanceBefore >= poolUsdcReserve + lenderUsdcAvailable, "accounting undercollateralized");
lenderUsdcAvailable -= amount;
usdc.safeTransfer(address(receiver), amount);
bytes32 retval = receiver.onFlashLoan(msg.sender, token, amount, fee, data);
require(retval == _FLASH_RETURN_VALUE, "invalid flash callback");
uint256 expectedBalance = balanceBefore + fee;
uint256 balanceAfterCallback = usdc.balanceOf(address(this));
if (balanceAfterCallback < expectedBalance) {
usdc.safeTransferFrom(address(receiver), address(this), expectedBalance - balanceAfterCallback);
}
require(usdc.balanceOf(address(this)) >= expectedBalance, "flash repayment failed");
lenderUsdcAvailable += amount + fee;
totalFlashFeesCollectedUsdc += fee;
require(
usdc.balanceOf(address(this)) >= poolUsdcReserve + lenderUsdcAvailable, "accounting undercollateralized"
);
emit EngineXFlashLoan(msg.sender, receiver, token, amount, fee);
return true;
}
function _runVirtualProofFor(
address outputRecipient,
bytes32 proofId,
uint256 debtUsdcPerLoop,
uint256 virtualLoops,
uint256 exactOutputAmount,
address roundingReceiver,
bytes32 iso20022DocumentHash,
bytes32 auditEnvelopeHash,
bytes32 pegProofHash
) internal {
require(proofId != bytes32(0), "zero proof");
require(!usedProofIds[proofId], "proof used");
usedProofIds[proofId] = true;
(
uint256 collateralXaut,
uint256 cwusdcInPerLoop,
uint256 cwusdcOutPerLoop,
uint256 cwusdcLossPerLoop,
uint256 totalCwusdcInAmount,
uint256 totalCwusdcOutAmount,
uint256 totalNeutralizedCwusdcAmount
) = previewVirtualProof(debtUsdcPerLoop, virtualLoops);
require(exactOutputAmount <= totalCwusdcOutAmount, "exact output too high");
uint256 outputAmount = exactOutputAmount == 0 ? totalCwusdcOutAmount : exactOutputAmount;
uint256 outputRoundingAmount = totalCwusdcOutAmount - outputAmount;
xaut.safeTransferFrom(msg.sender, address(this), collateralXaut);
cWUSDC.safeTransferFrom(msg.sender, address(this), totalCwusdcInAmount);
cWUSDC.safeTransfer(outputRecipient, outputAmount);
if (outputRoundingAmount > 0) {
cWUSDC.safeTransfer(roundingReceiver, outputRoundingAmount);
}
cWUSDC.safeTransfer(surplusReceiver, totalNeutralizedCwusdcAmount);
xaut.safeTransfer(msg.sender, collateralXaut);
totalNeutralizedCwusdc += totalNeutralizedCwusdcAmount;
totalVirtualLoops += virtualLoops;
totalVirtualDebtUsdc += debtUsdcPerLoop * virtualLoops;
totalVirtualCwusdcIn += totalCwusdcInAmount;
emit VirtualProofClosed(
proofId,
virtualLoops,
debtUsdcPerLoop,
collateralXaut,
cwusdcInPerLoop,
cwusdcOutPerLoop,
cwusdcLossPerLoop,
totalCwusdcInAmount,
totalCwusdcOutAmount,
totalNeutralizedCwusdcAmount,
poolCwusdcReserve,
poolUsdcReserve
);
if (iso20022DocumentHash != bytes32(0) || auditEnvelopeHash != bytes32(0) || pegProofHash != bytes32(0)) {
emit VirtualProofAuditEvidence(
proofId,
msg.sender,
outputRecipient,
exactOutputAmount,
outputRoundingAmount,
roundingReceiver,
iso20022DocumentHash,
auditEnvelopeHash,
pegProofHash
);
}
}
function withdrawPoolLiquidity(address to, uint256 cwusdcAmount, uint256 usdcAmount)
external
onlyOwner
nonReentrant
{
require(to != address(0), "zero to");
require(cwusdcAmount > 0 || usdcAmount > 0, "zero withdraw");
require(cwusdcAmount <= poolCwusdcReserve, "insufficient pool cwusdc");
require(usdcAmount <= poolUsdcReserve, "insufficient pool usdc");
uint256 nextCwusdcReserve = poolCwusdcReserve - cwusdcAmount;
uint256 nextUsdcReserve = poolUsdcReserve - usdcAmount;
require(nextCwusdcReserve == nextUsdcReserve, "would break maintained pool");
poolCwusdcReserve = nextCwusdcReserve;
poolUsdcReserve = nextUsdcReserve;
if (cwusdcAmount > 0) {
cWUSDC.safeTransfer(to, cwusdcAmount);
}
if (usdcAmount > 0) {
usdc.safeTransfer(to, usdcAmount);
}
emit PoolLiquidityWithdrawn(to, cwusdcAmount, usdcAmount);
}
function withdrawLenderUsdc(address to, uint256 amount) external onlyOwner nonReentrant {
require(to != address(0), "zero to");
require(amount > 0, "zero withdraw");
require(amount <= lenderUsdcAvailable, "insufficient lender usdc");
lenderUsdcAvailable -= amount;
usdc.safeTransfer(to, amount);
emit LenderUsdcWithdrawn(to, amount);
}
/// @notice Rescue or migrate only tokens that are not backing Engine X pool/lender accounting.
function withdraw(address token, address to, uint256 amount) external onlyOwner nonReentrant {
require(to != address(0), "zero to");
require(amount > 0, "zero withdraw");
IERC20(token).safeTransfer(to, amount);
_requireAccountingCollateralized();
emit UnaccountedTokenWithdrawn(token, to, amount);
}
function _requireAccountingCollateralized() internal view {
require(cWUSDC.balanceOf(address(this)) >= poolCwusdcReserve, "accounting undercollateralized");
require(
usdc.balanceOf(address(this)) >= poolUsdcReserve + lenderUsdcAvailable, "accounting undercollateralized"
);
}
function _getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256) {
require(amountOut > 0, "insufficient output");
require(reserveIn > 0 && reserveOut > amountOut, "insufficient liquidity");
uint256 numerator = reserveIn * amountOut * 1000;
uint256 denominator = (reserveOut - amountOut) * 997;
return (numerator / denominator) + 1;
}
function _getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256) {
require(amountIn > 0, "insufficient input");
require(reserveIn > 0 && reserveOut > 0, "insufficient liquidity");
uint256 amountInWithFee = amountIn * 997;
uint256 numerator = amountInWithFee * reserveOut;
uint256 denominator = reserveIn * 1000 + amountInWithFee;
return numerator / denominator;
}
}