Add Engine X proof vaults
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m31s
CI/CD Pipeline / Security Scanning (push) Successful in 3m56s
CI/CD Pipeline / Lint and Format (push) Failing after 35s
CI/CD Pipeline / Terraform Validation (push) Failing after 31s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 5m14s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 52s
Validation / validate-genesis (push) Successful in 25s
Validation / validate-terraform (push) Failing after 35s
Validation / validate-kubernetes (push) Failing after 7s
Validation / validate-smart-contracts (push) Failing after 7s
Validation / validate-security (push) Failing after 10m7s
Validation / validate-documentation (push) Failing after 16s
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m31s
CI/CD Pipeline / Security Scanning (push) Successful in 3m56s
CI/CD Pipeline / Lint and Format (push) Failing after 35s
CI/CD Pipeline / Terraform Validation (push) Failing after 31s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 5m14s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 52s
Validation / validate-genesis (push) Successful in 25s
Validation / validate-terraform (push) Failing after 35s
Validation / validate-kubernetes (push) Failing after 7s
Validation / validate-smart-contracts (push) Failing after 7s
Validation / validate-security (push) Failing after 10m7s
Validation / validate-documentation (push) Failing after 16s
This commit is contained in:
227
contracts/flash/DBISEngineXMaintainedProofVault.sol
Normal file
227
contracts/flash/DBISEngineXMaintainedProofVault.sol
Normal file
@@ -0,0 +1,227 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
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";
|
||||
|
||||
/// @notice Mainnet proof vault for Engine X with automatic cWUSDC surplus neutralization.
|
||||
/// @dev Surplus cWUSDC is removed from pool reserves and transferred to a neutral receiver.
|
||||
contract DBISEngineXMaintainedProofVault is Ownable {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
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 immutable xautUsdPrice6;
|
||||
uint256 public immutable ltvBps;
|
||||
uint256 public immutable maxRoundTripLossBps;
|
||||
uint256 public immutable maxSurplusDust;
|
||||
|
||||
address public surplusReceiver;
|
||||
|
||||
event PoolSeeded(uint256 cwusdcAmount, uint256 usdcAmount);
|
||||
event LenderFunded(uint256 usdcAmount);
|
||||
event SurplusReceiverUpdated(address indexed receiver);
|
||||
event SurplusNeutralized(bytes32 indexed proofId, uint256 indexed step, address indexed receiver, uint256 amount);
|
||||
event ProofStep(
|
||||
bytes32 indexed proofId,
|
||||
uint256 indexed step,
|
||||
uint256 debtUsdc,
|
||||
uint256 collateralXaut,
|
||||
uint256 cwusdcIn,
|
||||
uint256 cwusdcOut,
|
||||
uint256 cwusdcLoss,
|
||||
uint256 neutralizedCwusdc,
|
||||
uint256 poolCwusdcReserveAfter,
|
||||
uint256 poolUsdcReserveAfter
|
||||
);
|
||||
event ProofClosed(
|
||||
bytes32 indexed proofId,
|
||||
uint256 loops,
|
||||
uint256 totalDebtUsdc,
|
||||
uint256 totalCwusdcIn,
|
||||
uint256 totalNeutralizedCwusdcAmount
|
||||
);
|
||||
event OwnerWithdraw(address indexed token, address indexed to, uint256 amount);
|
||||
|
||||
constructor(
|
||||
address cWUSDC_,
|
||||
address usdc_,
|
||||
address xaut_,
|
||||
address owner_,
|
||||
address surplusReceiver_,
|
||||
uint256 xautUsdPrice6_,
|
||||
uint256 ltvBps_,
|
||||
uint256 maxRoundTripLossBps_,
|
||||
uint256 maxSurplusDust_
|
||||
) 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_;
|
||||
maxSurplusDust = maxSurplusDust_;
|
||||
}
|
||||
|
||||
function seedPool(uint256 cwusdcAmount, uint256 usdcAmount) external onlyOwner {
|
||||
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 {
|
||||
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 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 minimumXautCollateral(uint256 debtUsdc) public view returns (uint256) {
|
||||
uint256 numerator = debtUsdc * 1e6 * 10_000;
|
||||
uint256 denominator = xautUsdPrice6 * ltvBps;
|
||||
return (numerator + denominator - 1) / denominator;
|
||||
}
|
||||
|
||||
function runProof(bytes32 proofId, uint256 debtUsdcPerLoop, uint256 loops) external {
|
||||
_runProofFor(msg.sender, proofId, debtUsdcPerLoop, loops);
|
||||
}
|
||||
|
||||
function runProofBatch(bytes32[] calldata proofIds, uint256[] calldata debtsUsdcPerLoop, uint256[] calldata loops_)
|
||||
external
|
||||
{
|
||||
require(proofIds.length == debtsUsdcPerLoop.length && proofIds.length == loops_.length, "length mismatch");
|
||||
for (uint256 i = 0; i < proofIds.length; i++) {
|
||||
_runProofFor(msg.sender, proofIds[i], debtsUsdcPerLoop[i], loops_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function _runProofFor(address account, bytes32 proofId, uint256 debtUsdcPerLoop, uint256 loops) internal {
|
||||
require(proofId != bytes32(0), "zero proof");
|
||||
require(debtUsdcPerLoop > 0, "zero debt");
|
||||
require(loops > 0 && loops <= 32, "bad loops");
|
||||
|
||||
uint256 collateralPerLoop = minimumXautCollateral(debtUsdcPerLoop);
|
||||
uint256 totalCollateral = collateralPerLoop * loops;
|
||||
uint256 totalDebt;
|
||||
uint256 totalCwusdcIn;
|
||||
uint256 neutralizedInProof;
|
||||
|
||||
xaut.safeTransferFrom(account, address(this), totalCollateral);
|
||||
|
||||
for (uint256 i = 0; i < loops; i++) {
|
||||
require(lenderUsdcAvailable >= debtUsdcPerLoop, "insufficient lender usdc");
|
||||
|
||||
uint256 poolUsdcBefore = poolUsdcReserve;
|
||||
lenderUsdcAvailable -= debtUsdcPerLoop;
|
||||
uint256 cwusdcIn = _getAmountIn(debtUsdcPerLoop, poolCwusdcReserve, poolUsdcReserve);
|
||||
cWUSDC.safeTransferFrom(account, address(this), cwusdcIn);
|
||||
|
||||
poolCwusdcReserve += cwusdcIn;
|
||||
poolUsdcReserve -= debtUsdcPerLoop;
|
||||
lenderUsdcAvailable += debtUsdcPerLoop;
|
||||
|
||||
uint256 cwusdcOut = _getAmountOut(debtUsdcPerLoop, poolUsdcReserve, poolCwusdcReserve);
|
||||
poolUsdcReserve += debtUsdcPerLoop;
|
||||
poolCwusdcReserve -= cwusdcOut;
|
||||
cWUSDC.safeTransfer(account, cwusdcOut);
|
||||
|
||||
uint256 cwusdcLoss = cwusdcIn - cwusdcOut;
|
||||
require(cwusdcLoss * 10_000 <= cwusdcIn * maxRoundTripLossBps, "roundtrip loss too high");
|
||||
require(poolUsdcReserve == poolUsdcBefore, "usdc reserve drift");
|
||||
|
||||
uint256 neutralized = _neutralizeSurplus(proofId, i + 1);
|
||||
neutralizedInProof += neutralized;
|
||||
|
||||
totalDebt += debtUsdcPerLoop;
|
||||
totalCwusdcIn += cwusdcIn;
|
||||
|
||||
emit ProofStep(
|
||||
proofId,
|
||||
i + 1,
|
||||
debtUsdcPerLoop,
|
||||
collateralPerLoop,
|
||||
cwusdcIn,
|
||||
cwusdcOut,
|
||||
cwusdcLoss,
|
||||
neutralized,
|
||||
poolCwusdcReserve,
|
||||
poolUsdcReserve
|
||||
);
|
||||
}
|
||||
|
||||
xaut.safeTransfer(account, totalCollateral);
|
||||
emit ProofClosed(proofId, loops, totalDebt, totalCwusdcIn, neutralizedInProof);
|
||||
}
|
||||
|
||||
function _neutralizeSurplus(bytes32 proofId, uint256 step) internal returns (uint256 neutralized) {
|
||||
uint256 surplus = currentSurplusCwusdc();
|
||||
if (surplus <= maxSurplusDust) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
neutralized = surplus - maxSurplusDust;
|
||||
poolCwusdcReserve -= neutralized;
|
||||
totalNeutralizedCwusdc += neutralized;
|
||||
cWUSDC.safeTransfer(surplusReceiver, neutralized);
|
||||
emit SurplusNeutralized(proofId, step, surplusReceiver, neutralized);
|
||||
}
|
||||
|
||||
function withdraw(address token, address to, uint256 amount) external onlyOwner {
|
||||
require(to != address(0), "zero to");
|
||||
IERC20(token).safeTransfer(to, amount);
|
||||
emit OwnerWithdraw(token, to, amount);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
234
contracts/flash/DBISEngineXProofVault.sol
Normal file
234
contracts/flash/DBISEngineXProofVault.sol
Normal file
@@ -0,0 +1,234 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
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";
|
||||
|
||||
/// @notice Mainnet proof-of-concept vault for the Engine X XAU/USD secured loop.
|
||||
/// @dev This is intentionally small and deterministic: it is not a production lender.
|
||||
contract DBISEngineXProofVault is Ownable {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
IERC20 public immutable cWUSDC;
|
||||
IERC20 public immutable usdc;
|
||||
IERC20 public immutable xaut;
|
||||
|
||||
uint256 public poolCwusdcReserve;
|
||||
uint256 public poolUsdcReserve;
|
||||
uint256 public lenderUsdcAvailable;
|
||||
|
||||
uint256 public immutable xautUsdPrice6;
|
||||
uint256 public immutable ltvBps;
|
||||
uint256 public immutable maxRoundTripLossBps;
|
||||
|
||||
event PoolSeeded(uint256 cwusdcAmount, uint256 usdcAmount);
|
||||
event LenderFunded(uint256 usdcAmount);
|
||||
event ProofStep(
|
||||
bytes32 indexed proofId,
|
||||
uint256 indexed step,
|
||||
uint256 debtUsdc,
|
||||
uint256 collateralXaut,
|
||||
uint256 cwusdcIn,
|
||||
uint256 cwusdcOut,
|
||||
uint256 cwusdcLoss,
|
||||
uint256 poolCwusdcReserveAfter,
|
||||
uint256 poolUsdcReserveAfter
|
||||
);
|
||||
event ProofClosed(bytes32 indexed proofId, uint256 loops, uint256 totalDebtUsdc, uint256 totalCwusdcIn);
|
||||
event OwnerWithdraw(address indexed token, address indexed to, uint256 amount);
|
||||
|
||||
constructor(
|
||||
address cWUSDC_,
|
||||
address usdc_,
|
||||
address xaut_,
|
||||
address owner_,
|
||||
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(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_);
|
||||
xautUsdPrice6 = xautUsdPrice6_;
|
||||
ltvBps = ltvBps_;
|
||||
maxRoundTripLossBps = maxRoundTripLossBps_;
|
||||
}
|
||||
|
||||
function seedPool(uint256 cwusdcAmount, uint256 usdcAmount) external onlyOwner {
|
||||
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 {
|
||||
require(usdcAmount > 0, "zero fund");
|
||||
usdc.safeTransferFrom(msg.sender, address(this), usdcAmount);
|
||||
lenderUsdcAvailable += usdcAmount;
|
||||
emit LenderFunded(usdcAmount);
|
||||
}
|
||||
|
||||
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 minimumXautCollateral(uint256 debtUsdc) public view returns (uint256) {
|
||||
uint256 numerator = debtUsdc * 1e6 * 10_000;
|
||||
uint256 denominator = xautUsdPrice6 * ltvBps;
|
||||
return (numerator + denominator - 1) / denominator;
|
||||
}
|
||||
|
||||
function runProof(bytes32 proofId, uint256 debtUsdcPerLoop, uint256 loops) external {
|
||||
require(proofId != bytes32(0), "zero proof");
|
||||
require(debtUsdcPerLoop > 0, "zero debt");
|
||||
require(loops > 0 && loops <= 32, "bad loops");
|
||||
|
||||
uint256 collateralPerLoop = minimumXautCollateral(debtUsdcPerLoop);
|
||||
uint256 totalCollateral = collateralPerLoop * loops;
|
||||
uint256 totalDebt;
|
||||
uint256 totalCwusdcIn;
|
||||
|
||||
xaut.safeTransferFrom(msg.sender, address(this), totalCollateral);
|
||||
|
||||
for (uint256 i = 0; i < loops; i++) {
|
||||
require(lenderUsdcAvailable >= debtUsdcPerLoop, "insufficient lender usdc");
|
||||
|
||||
uint256 poolCwusdcBefore = poolCwusdcReserve;
|
||||
uint256 poolUsdcBefore = poolUsdcReserve;
|
||||
lenderUsdcAvailable -= debtUsdcPerLoop;
|
||||
uint256 cwusdcIn = _getAmountIn(debtUsdcPerLoop, poolCwusdcReserve, poolUsdcReserve);
|
||||
cWUSDC.safeTransferFrom(msg.sender, address(this), cwusdcIn);
|
||||
|
||||
poolCwusdcReserve += cwusdcIn;
|
||||
poolUsdcReserve -= debtUsdcPerLoop;
|
||||
lenderUsdcAvailable += debtUsdcPerLoop;
|
||||
|
||||
uint256 cwusdcOut = _getAmountOut(debtUsdcPerLoop, poolUsdcReserve, poolCwusdcReserve);
|
||||
poolUsdcReserve += debtUsdcPerLoop;
|
||||
poolCwusdcReserve -= cwusdcOut;
|
||||
cWUSDC.safeTransfer(msg.sender, cwusdcOut);
|
||||
|
||||
uint256 cwusdcLoss = cwusdcIn - cwusdcOut;
|
||||
require(cwusdcLoss * 10_000 <= cwusdcIn * maxRoundTripLossBps, "roundtrip loss too high");
|
||||
require(poolUsdcReserve == poolUsdcBefore, "usdc reserve drift");
|
||||
require(poolCwusdcReserve >= poolCwusdcBefore, "cw reserve drift");
|
||||
|
||||
totalDebt += debtUsdcPerLoop;
|
||||
totalCwusdcIn += cwusdcIn;
|
||||
|
||||
emit ProofStep(
|
||||
proofId,
|
||||
i + 1,
|
||||
debtUsdcPerLoop,
|
||||
collateralPerLoop,
|
||||
cwusdcIn,
|
||||
cwusdcOut,
|
||||
cwusdcLoss,
|
||||
poolCwusdcReserve,
|
||||
poolUsdcReserve
|
||||
);
|
||||
}
|
||||
|
||||
xaut.safeTransfer(msg.sender, totalCollateral);
|
||||
emit ProofClosed(proofId, loops, totalDebt, totalCwusdcIn);
|
||||
}
|
||||
|
||||
function runProofBatch(bytes32[] calldata proofIds, uint256[] calldata debtsUsdcPerLoop, uint256[] calldata loops_)
|
||||
external
|
||||
{
|
||||
require(proofIds.length == debtsUsdcPerLoop.length && proofIds.length == loops_.length, "length mismatch");
|
||||
for (uint256 i = 0; i < proofIds.length; i++) {
|
||||
_runProofFor(msg.sender, proofIds[i], debtsUsdcPerLoop[i], loops_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function _runProofFor(address account, bytes32 proofId, uint256 debtUsdcPerLoop, uint256 loops) internal {
|
||||
require(proofId != bytes32(0), "zero proof");
|
||||
require(debtUsdcPerLoop > 0, "zero debt");
|
||||
require(loops > 0 && loops <= 32, "bad loops");
|
||||
|
||||
uint256 collateralPerLoop = minimumXautCollateral(debtUsdcPerLoop);
|
||||
uint256 totalCollateral = collateralPerLoop * loops;
|
||||
uint256 totalDebt;
|
||||
uint256 totalCwusdcIn;
|
||||
|
||||
xaut.safeTransferFrom(account, address(this), totalCollateral);
|
||||
|
||||
for (uint256 i = 0; i < loops; i++) {
|
||||
require(lenderUsdcAvailable >= debtUsdcPerLoop, "insufficient lender usdc");
|
||||
|
||||
uint256 poolCwusdcBefore = poolCwusdcReserve;
|
||||
uint256 poolUsdcBefore = poolUsdcReserve;
|
||||
lenderUsdcAvailable -= debtUsdcPerLoop;
|
||||
uint256 cwusdcIn = _getAmountIn(debtUsdcPerLoop, poolCwusdcReserve, poolUsdcReserve);
|
||||
cWUSDC.safeTransferFrom(account, address(this), cwusdcIn);
|
||||
|
||||
poolCwusdcReserve += cwusdcIn;
|
||||
poolUsdcReserve -= debtUsdcPerLoop;
|
||||
lenderUsdcAvailable += debtUsdcPerLoop;
|
||||
|
||||
uint256 cwusdcOut = _getAmountOut(debtUsdcPerLoop, poolUsdcReserve, poolCwusdcReserve);
|
||||
poolUsdcReserve += debtUsdcPerLoop;
|
||||
poolCwusdcReserve -= cwusdcOut;
|
||||
cWUSDC.safeTransfer(account, cwusdcOut);
|
||||
|
||||
uint256 cwusdcLoss = cwusdcIn - cwusdcOut;
|
||||
require(cwusdcLoss * 10_000 <= cwusdcIn * maxRoundTripLossBps, "roundtrip loss too high");
|
||||
require(poolUsdcReserve == poolUsdcBefore, "usdc reserve drift");
|
||||
require(poolCwusdcReserve >= poolCwusdcBefore, "cw reserve drift");
|
||||
|
||||
totalDebt += debtUsdcPerLoop;
|
||||
totalCwusdcIn += cwusdcIn;
|
||||
|
||||
emit ProofStep(
|
||||
proofId,
|
||||
i + 1,
|
||||
debtUsdcPerLoop,
|
||||
collateralPerLoop,
|
||||
cwusdcIn,
|
||||
cwusdcOut,
|
||||
cwusdcLoss,
|
||||
poolCwusdcReserve,
|
||||
poolUsdcReserve
|
||||
);
|
||||
}
|
||||
|
||||
xaut.safeTransfer(account, totalCollateral);
|
||||
emit ProofClosed(proofId, loops, totalDebt, totalCwusdcIn);
|
||||
}
|
||||
|
||||
function withdraw(address token, address to, uint256 amount) external onlyOwner {
|
||||
require(to != address(0), "zero to");
|
||||
IERC20(token).safeTransfer(to, amount);
|
||||
emit OwnerWithdraw(token, to, amount);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user