编译器
0.8.28+commit.7893614a
文件 1 的 23:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 23:AggregatorV3Interface.sol
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
文件 3 的 23:ArbitrageV5.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "src/interfaces/IWETH.sol";
import "src/interfaces/IPriceFeedAggregator.sol";
import "src/interfaces/IReserveHolderV2.sol";
import "src/interfaces/IArbitrageERC20.sol";
import "src/library/ExternalContractAddresses.sol";
import "src/library/uniswap/UniswapV2Library.sol";
import "src/interfaces/IArbitrageV5.sol";
contract ArbitrageV5 is IArbitrageV5, ReentrancyGuard, Ownable {
using SafeERC20 for IERC20;
using SafeERC20 for IArbitrageERC20;
uint256 public constant BASE_PRICE = 1e8;
uint256 public constant USC_TARGET_PRICE = 1e8;
uint256 public constant POOL_FEE = 30;
uint256 public constant MAX_FEE = 100_00;
uint256 public constant F = ((MAX_FEE - POOL_FEE) * 1e18) / MAX_FEE;
uint16 public constant MAX_PRICE_TOLERANCE = 100_00;
address public constant WETH = ExternalContractAddresses.WETH;
address public constant STETH = ExternalContractAddresses.stETH;
IUniswapV2Router02 public constant swapRouter = IUniswapV2Router02(ExternalContractAddresses.UNI_V2_SWAP_ROUTER);
IUniswapV2Factory public constant poolFactory = IUniswapV2Factory(ExternalContractAddresses.UNI_V2_POOL_FACTORY);
IArbitrageERC20 public immutable USC;
IArbitrageERC20 public immutable CHI;
IPriceFeedAggregator public immutable priceFeedAggregator;
IReserveHolderV2 public reserveHolder;
uint256 public pegPriceToleranceAbs;
uint256 public mintBurnFee;
uint256 public maxMintBurnPriceDiff;
uint16 public maxMintBurnReserveTolerance;
uint16 public chiPriceTolerance;
uint16 public priceTolerance;
bool public mintPaused;
bool public burnPaused;
uint256 public totalMintedUsc;
mapping(address => bool) public isArbitrager;
mapping(address => bool) public isPrivileged;
mapping(address => uint256) public reserveMintTxLimit;
mapping(address => uint256) public reserveBurnTxLimit;
modifier onlyArbitrager() {
if (!isArbitrager[msg.sender]) {
revert NotArbitrager(msg.sender);
}
_;
}
modifier whenMintNotPaused() {
if (mintPaused) {
revert ContractIsPaused();
}
_;
}
modifier whenBurnNotPaused() {
if (burnPaused) {
revert ContractIsPaused();
}
_;
}
modifier onlyWhenMintableOrBurnable() {
uint256 ethPrice = priceFeedAggregator.peek(WETH);
uint256 uscSpotPrice = _calculateUscSpotPrice(ethPrice);
if (!_almostEqualAbs(uscSpotPrice, USC_TARGET_PRICE, maxMintBurnPriceDiff)) {
revert PriceIsNotPegged();
}
(, uint256 reserveDiff, uint256 reserveValue) = _getReservesData();
if (reserveDiff > Math.mulDiv(reserveValue, maxMintBurnReserveTolerance, MAX_PRICE_TOLERANCE)) {
revert ReserveDiffTooBig();
}
_;
}
modifier onlyBellowMintLimit(address reserveAsset, uint256 amount) {
if (reserveMintTxLimit[reserveAsset] < amount) {
revert ReserveTxLimitExceeded();
}
_;
}
modifier onlyBellowBurnLimit(address reserveAsset, uint256 amount) {
if (reserveBurnTxLimit[reserveAsset] < amount) {
revert ReserveTxLimitExceeded();
}
_;
}
constructor(
IArbitrageERC20 _USC,
IArbitrageERC20 _CHI,
IPriceFeedAggregator _priceFeedAggregator,
IReserveHolderV2 _reserveHolder
) Ownable() {
USC = _USC;
CHI = _CHI;
priceFeedAggregator = _priceFeedAggregator;
reserveHolder = _reserveHolder;
mintPaused = false;
burnPaused = false;
IERC20(STETH).approve(address(reserveHolder), type(uint256).max);
}
function setReserveHolder(address _reserveHolder) external onlyOwner {
reserveHolder = IReserveHolderV2(_reserveHolder);
}
function setPegPriceToleranceAbs(uint256 _priceTolerance) external override onlyOwner {
pegPriceToleranceAbs = _priceTolerance;
}
function setMintPause(bool isPaused) external onlyOwner {
mintPaused = isPaused;
}
function setBurnPause(bool isPaused) external onlyOwner {
burnPaused = isPaused;
}
function setPriceTolerance(uint16 _priceTolerance) external onlyOwner {
if (_priceTolerance > MAX_PRICE_TOLERANCE) {
revert ToleranceTooBig(_priceTolerance);
}
priceTolerance = _priceTolerance;
emit SetPriceTolerance(_priceTolerance);
}
function setChiPriceTolerance(uint16 _chiPriceTolerance) external onlyOwner {
if (_chiPriceTolerance > MAX_PRICE_TOLERANCE) {
revert ToleranceTooBig(_chiPriceTolerance);
}
chiPriceTolerance = _chiPriceTolerance;
emit SetChiPriceTolerance(_chiPriceTolerance);
}
function setMaxMintBurnPriceDiff(uint256 _maxMintBurnPriceDiff) external onlyOwner {
maxMintBurnPriceDiff = _maxMintBurnPriceDiff;
emit SetMaxMintBurnPriceDiff(_maxMintBurnPriceDiff);
}
function setMaxMintBurnReserveTolerance(uint16 _maxMintBurnReserveTolerance) external onlyOwner {
if (_maxMintBurnReserveTolerance > MAX_PRICE_TOLERANCE) {
revert ToleranceTooBig(_maxMintBurnReserveTolerance);
}
maxMintBurnReserveTolerance = _maxMintBurnReserveTolerance;
emit SetMaxMintBurnReserveTolerance(_maxMintBurnReserveTolerance);
}
function setMintBurnFee(uint16 _mintBurnFee) external onlyOwner {
if (_mintBurnFee > MAX_FEE) {
revert FeeTooBig(_mintBurnFee);
}
mintBurnFee = _mintBurnFee;
emit SetMintBurnFee(_mintBurnFee);
}
function setReserveMintTxLimit(address reserveAsset, uint256 limit) external onlyOwner {
reserveMintTxLimit[reserveAsset] = limit;
emit SetReserveMintTxLimit(reserveAsset, limit);
}
function setReserveBurnTxLimit(address reserveAsset, uint256 limit) external onlyOwner {
reserveBurnTxLimit[reserveAsset] = limit;
emit SetReserveBurnTxLimit(reserveAsset, limit);
}
function updateArbitrager(address arbitrager, bool status) external onlyOwner {
isArbitrager[arbitrager] = status;
emit UpdateArbitrager(arbitrager, status);
}
function updatePrivileged(address account, bool status) external onlyOwner {
isPrivileged[account] = status;
emit UpdatePrivileged(account, status);
}
function claimRewards(IERC20[] memory tokens, uint256[] memory amounts) external onlyOwner {
for (uint256 i = 0; i < tokens.length; i++) {
IERC20 token = tokens[i];
uint256 amount = amounts[i];
token.safeTransfer(msg.sender, amount);
if (address(token) == address(USC)) {
if (amount < totalMintedUsc) {
totalMintedUsc -= amount;
} else {
totalMintedUsc = 0;
}
}
}
}
function rewardUSC(uint256 amount) external onlyOwner {
USC.safeTransferFrom(msg.sender, address(this), amount);
totalMintedUsc += amount;
emit RewardUSC(amount);
}
function mint(address token, uint256 amount, address receiver)
external
whenMintNotPaused
nonReentrant
onlyWhenMintableOrBurnable
onlyBellowMintLimit(token, amount)
returns (uint256)
{
uint256 fee = Math.mulDiv(amount, mintBurnFee, MAX_FEE);
uint256 amountAfterFee = amount - fee;
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
IERC20(token).approve(address(reserveHolder), amountAfterFee);
reserveHolder.deposit(token, amountAfterFee);
return _mint(amountAfterFee, token, receiver);
}
function mint(address receiver)
external
payable
whenMintNotPaused
nonReentrant
onlyWhenMintableOrBurnable
onlyBellowMintLimit(address(WETH), msg.value)
returns (uint256)
{
uint256 ethAmount = msg.value;
uint256 fee = Math.mulDiv(ethAmount, mintBurnFee, MAX_FEE);
uint256 ethAmountAfterFee = ethAmount - fee;
IWETH(WETH).deposit{value: ethAmount}();
IERC20(WETH).safeTransfer(address(reserveHolder), ethAmountAfterFee);
return _mint(ethAmountAfterFee, WETH, receiver);
}
function burn(uint256 amount, address reserveToReceive)
external
whenBurnNotPaused
nonReentrant
onlyWhenMintableOrBurnable
onlyBellowBurnLimit(reserveToReceive, amount)
returns (uint256)
{
uint256 reservePrice = priceFeedAggregator.peek(reserveToReceive);
USC.safeTransferFrom(msg.sender, address(this), amount);
amount -= (amount * mintBurnFee) / MAX_FEE;
USC.burn(amount);
uint256 reserveAmountToRedeem = Math.mulDiv(amount, USC_TARGET_PRICE, reservePrice);
reserveHolder.redeem(reserveAmountToRedeem, reserveToReceive);
IERC20(reserveToReceive).safeTransfer(msg.sender, reserveAmountToRedeem);
emit Burn(msg.sender, amount, reserveAmountToRedeem, reserveToReceive);
return reserveAmountToRedeem;
}
function executeArbitrageWithReserveSell(uint256 maxChiSpotPrice, SwapParams[] calldata swapParams)
external
returns (uint256)
{
for (uint256 i = 0; i < swapParams.length; i++) {
reserveHolder.swapReserveForEth(
swapParams[i].reserveAsset, swapParams[i].amountIn, swapParams[i].minAmountOut
);
}
return executeArbitrage(maxChiSpotPrice);
}
function executeArbitrage(uint256 maxChiSpotPrice) public override nonReentrant onlyArbitrager returns (uint256) {
_validateArbitrage(maxChiSpotPrice);
return _executeArbitrage();
}
function getArbitrageData()
public
view
returns (bool isPriceAtPeg, bool isPriceAboveTarget, bool isExcessOfReserves, uint256 reserveDiff)
{
uint256 ethPrice = priceFeedAggregator.peek(WETH);
uint256 uscPrice = _getAndValidateUscPrice(ethPrice);
uint256 reserveValue;
(isExcessOfReserves, reserveDiff, reserveValue) = _getReservesData();
isPriceAboveTarget = uscPrice >= USC_TARGET_PRICE;
return (
_almostEqualAbs(uscPrice, USC_TARGET_PRICE, pegPriceToleranceAbs),
isPriceAboveTarget,
isExcessOfReserves,
reserveDiff
);
}
function _executeArbitrage() internal returns (uint256) {
(bool isPriceAtPeg, bool isPriceAboveTarget, bool isExcessOfReserves, uint256 reserveDiff) = getArbitrageData();
uint256 ethPrice = priceFeedAggregator.peek(WETH);
if (isPriceAtPeg) {
if (isExcessOfReserves) {
return _arbitrageAtPegExcessOfReserves(reserveDiff, ethPrice);
} else {
return _arbitrageAtPegDeficitOfReserves(reserveDiff, ethPrice);
}
} else if (isPriceAboveTarget) {
if (isExcessOfReserves) {
return _arbitrageAbovePegExcessOfReserves(reserveDiff, ethPrice);
} else {
return _arbitrageAbovePegDeficitOfReserves(reserveDiff, ethPrice);
}
} else {
if (isExcessOfReserves) {
return _arbitrageBellowPegExcessOfReserves(reserveDiff, ethPrice);
} else {
return _arbitrageBellowPegDeficitOfReserves(reserveDiff, ethPrice);
}
}
}
function _mint(uint256 amount, address token, address receiver) private returns (uint256) {
uint256 usdValue;
if (token == WETH) {
uint256 ethPrice = priceFeedAggregator.peek(WETH);
usdValue = _convertTokenAmountToUsdValue(amount, ethPrice);
} else {
uint256 tokenPrice = priceFeedAggregator.peek(token);
usdValue = _convertTokenAmountToUsdValue(amount, tokenPrice);
}
uint256 uscAmountToMint = _convertUsdValueToTokenAmount(usdValue, USC_TARGET_PRICE);
USC.mint(receiver, uscAmountToMint);
emit Mint(msg.sender, token, amount, uscAmountToMint);
return uscAmountToMint;
}
function _arbitrageAbovePegExcessOfReserves(uint256 reserveDiff, uint256 ethPrice) private returns (uint256) {
uint256 deltaUSC = _calculateDeltaUSC(ethPrice);
USC.mint(address(this), deltaUSC);
uint256 ethAmountReceived = _swap(address(USC), WETH, deltaUSC);
uint256 deltaUsd = _convertTokenAmountToUsdValue(deltaUSC, USC_TARGET_PRICE);
uint256 deltaInETH = _convertUsdValueToTokenAmount(deltaUsd, ethPrice);
if (deltaInETH > ethAmountReceived) {
revert DeltaBiggerThanAmountReceivedETH(deltaInETH, ethAmountReceived);
}
uint256 ethAmountToSwap;
uint256 ethAmountForReserves;
if (deltaUsd > reserveDiff) {
ethAmountToSwap = _convertUsdValueToTokenAmount(reserveDiff, ethPrice);
ethAmountForReserves = _convertUsdValueToTokenAmount(deltaUsd, ethPrice) - ethAmountToSwap;
IERC20(WETH).safeTransfer(address(reserveHolder), ethAmountForReserves);
} else {
ethAmountToSwap = _convertUsdValueToTokenAmount(deltaUsd, ethPrice);
}
uint256 chiAmountReceived = _swap(WETH, address(CHI), ethAmountToSwap);
CHI.burn(chiAmountReceived);
uint256 rewardAmount = ethAmountReceived - ethAmountToSwap - ethAmountForReserves;
uint256 rewardValue = _convertTokenAmountToUsdValue(rewardAmount, ethPrice);
emit ExecuteArbitrage(msg.sender, 1, deltaUsd, reserveDiff, ethPrice, rewardValue);
return rewardValue;
}
function _arbitrageAbovePegDeficitOfReserves(uint256 reserveDiff, uint256 ethPrice) private returns (uint256) {
uint256 deltaUSC = _calculateDeltaUSC(ethPrice);
USC.mint(address(this), deltaUSC);
uint256 ethAmountReceived = _swap(address(USC), WETH, deltaUSC);
uint256 deltaUsd = _convertTokenAmountToUsdValue(deltaUSC, USC_TARGET_PRICE);
uint256 deltaInETH = _convertUsdValueToTokenAmount(deltaUsd, ethPrice);
if (deltaInETH > ethAmountReceived) {
revert DeltaBiggerThanAmountReceivedETH(deltaInETH, ethAmountReceived);
}
IERC20(WETH).safeTransfer(address(reserveHolder), deltaInETH);
uint256 rewardAmount = ethAmountReceived - deltaInETH;
uint256 rewardValue = _convertTokenAmountToUsdValue(rewardAmount, ethPrice);
emit ExecuteArbitrage(msg.sender, 2, deltaUsd, reserveDiff, ethPrice, rewardValue);
return rewardValue;
}
function _arbitrageBellowPegExcessOfReserves(uint256 reserveDiff, uint256 ethPrice) private returns (uint256) {
uint256 uscAmountToFreeze;
uint256 uscAmountToBurn;
uint256 deltaETH = _calculateDeltaETH(ethPrice);
uint256 deltaUsd = _convertTokenAmountToUsdValue(deltaETH, ethPrice);
if (deltaUsd > reserveDiff) {
uscAmountToFreeze = _convertUsdValueToTokenAmount(reserveDiff, USC_TARGET_PRICE);
uscAmountToBurn = _convertUsdValueToTokenAmount(deltaUsd - reserveDiff, USC_TARGET_PRICE);
} else {
uscAmountToFreeze = _convertUsdValueToTokenAmount(deltaUsd, USC_TARGET_PRICE);
}
reserveHolder.redeem(deltaETH, address(WETH));
uint256 uscAmountReceived = _swap(WETH, address(USC), deltaETH);
if (uscAmountReceived < uscAmountToFreeze) {
uscAmountToFreeze = uscAmountReceived;
}
if (uscAmountToBurn > 0) {
USC.burn(uscAmountToBurn);
}
uint256 rewardAmount = uscAmountReceived - uscAmountToFreeze - uscAmountToBurn;
uint256 rewardValue = _convertTokenAmountToUsdValue(rewardAmount, USC_TARGET_PRICE);
emit ExecuteArbitrage(msg.sender, 3, deltaUsd, reserveDiff, ethPrice, rewardValue);
return rewardValue;
}
function _arbitrageBellowPegDeficitOfReserves(uint256 reserveDiff, uint256 ethPrice) private returns (uint256) {
uint256 ethAmountToRedeem;
uint256 ethAmountFromChi;
uint256 deltaETH = _calculateDeltaETH(ethPrice);
uint256 deltaUsd = _convertTokenAmountToUsdValue(deltaETH, ethPrice);
if (deltaUsd > reserveDiff) {
ethAmountFromChi = _convertUsdValueToTokenAmount(reserveDiff, ethPrice);
ethAmountToRedeem = deltaETH - ethAmountFromChi;
reserveHolder.redeem(ethAmountToRedeem, address(WETH));
} else {
ethAmountFromChi = deltaETH;
}
uint256 uscAmountToBurn = _convertUsdValueToTokenAmount(deltaUsd, USC_TARGET_PRICE);
uint256 uscAmountReceived;
{
if (ethAmountFromChi > 0) {
uint256 chiAmountToMint = _getAmountInForAmountOut(address(CHI), WETH, ethAmountFromChi);
CHI.mint(address(this), chiAmountToMint);
_swap(address(CHI), WETH, chiAmountToMint);
}
uscAmountReceived = _swap(WETH, address(USC), ethAmountFromChi + ethAmountToRedeem);
}
if (uscAmountToBurn > 0) {
USC.burn(uscAmountToBurn);
}
{
uint256 rewardAmount = uscAmountReceived - uscAmountToBurn;
uint256 rewardValue = _convertTokenAmountToUsdValue(rewardAmount, USC_TARGET_PRICE);
emit ExecuteArbitrage(msg.sender, 4, deltaUsd, reserveDiff, ethPrice, rewardValue);
return rewardValue;
}
}
function _arbitrageAtPegExcessOfReserves(uint256 reserveDiff, uint256 ethPrice) private returns (uint256) {
uint256 uscAmountToMint = _convertUsdValueToTokenAmount(reserveDiff, USC_TARGET_PRICE);
USC.mint(address(this), uscAmountToMint);
totalMintedUsc += uscAmountToMint;
emit ExecuteArbitrage(msg.sender, 5, 0, reserveDiff, ethPrice, 0);
return 0;
}
function _arbitrageAtPegDeficitOfReserves(uint256 reserveDiff, uint256 ethPrice) private returns (uint256) {
uint256 reserveDiffInUsc = _convertUsdValueToTokenAmount(reserveDiff, USC_TARGET_PRICE);
uint256 uscAmountToBurn;
uint256 ethToGet;
if (reserveDiffInUsc > totalMintedUsc) {
uscAmountToBurn = totalMintedUsc;
uint256 ethToGetInUsd = _convertTokenAmountToUsdValue(reserveDiffInUsc - totalMintedUsc, USC_TARGET_PRICE);
ethToGet = _convertUsdValueToTokenAmount(ethToGetInUsd, ethPrice);
} else {
uscAmountToBurn = reserveDiffInUsc;
ethToGet = 0;
}
uint256 chiToCoverEth;
if (ethToGet > 0) {
chiToCoverEth = _getAmountInForAmountOut(address(CHI), WETH, ethToGet);
}
CHI.mint(address(this), chiToCoverEth);
if (ethToGet > 0) {
uint256 ethReceived = _swap(address(CHI), WETH, chiToCoverEth);
IERC20(WETH).safeTransfer(address(reserveHolder), ethReceived);
}
if (uscAmountToBurn > 0) {
USC.burn(uscAmountToBurn);
totalMintedUsc -= uscAmountToBurn;
}
emit ExecuteArbitrage(msg.sender, 6, 0, reserveDiff, ethPrice, 0);
return 0;
}
function _getReservesData()
public
view
returns (bool isExcessOfReserves, uint256 reserveDiff, uint256 reserveValue)
{
reserveValue = reserveHolder.getReserveValue();
uint256 uscTotalSupplyValue = _convertTokenAmountToUsdValue(USC.totalSupply(), USC_TARGET_PRICE);
if (reserveValue > uscTotalSupplyValue) {
isExcessOfReserves = true;
reserveDiff = (reserveValue - uscTotalSupplyValue);
} else {
isExcessOfReserves = false;
reserveDiff = (uscTotalSupplyValue - reserveValue);
}
}
function _getAndValidateUscPrice(uint256 ethPrice) private view returns (uint256) {
uint256 uscPrice = priceFeedAggregator.peek(address(USC));
uint256 uscSpotPrice = _calculateUscSpotPrice(ethPrice);
uint256 priceDiff = _absDiff(uscSpotPrice, uscPrice);
uint256 maxPriceDiff = Math.mulDiv(uscPrice, priceTolerance, MAX_PRICE_TOLERANCE);
if (priceDiff > maxPriceDiff) {
revert PriceSlippageTooBig();
}
return uscSpotPrice;
}
function _validateArbitrage(uint256 maxChiSpotPrice) private view {
if (!isPrivileged[msg.sender]) {
uint256 ethPrice = priceFeedAggregator.peek(WETH);
uint256 chiSpotPrice = _calculateChiSpotPrice(ethPrice);
if (maxChiSpotPrice != 0 && chiSpotPrice > maxChiSpotPrice) {
revert ChiSpotPriceTooBig();
}
if (maxChiSpotPrice == 0) {
uint256 chiOraclePrice = priceFeedAggregator.peek(address(CHI));
if (!_almostEqualRel(chiSpotPrice, chiOraclePrice, chiPriceTolerance)) {
revert ChiPriceNotPegged(chiSpotPrice, chiOraclePrice);
}
}
}
}
function _calculateUscSpotPrice(uint256 ethPrice) private view returns (uint256) {
(uint256 reserveUSC, uint256 reserveWETH) =
UniswapV2Library.getReserves(address(poolFactory), address(USC), address(WETH));
uint256 uscFor1ETH = UniswapV2Library.quote(1 ether, reserveWETH, reserveUSC);
return Math.mulDiv(ethPrice, 1 ether, uscFor1ETH);
}
function _calculateChiSpotPrice(uint256 ethPrice) private view returns (uint256) {
(uint256 reserveCHI, uint256 reserveWETH) =
UniswapV2Library.getReserves(address(poolFactory), address(CHI), address(WETH));
uint256 chiFor1ETH = UniswapV2Library.quote(1 ether, reserveWETH, reserveCHI);
return Math.mulDiv(ethPrice, 1 ether, chiFor1ETH);
}
function _calculateDelta(uint256 reserveIn, uint256 priceIn, uint256 reserveOut, uint256 priceOut)
public
pure
returns (uint256)
{
uint256 b = Math.mulDiv(reserveIn, 1e18 + F, 1e18);
uint256 b_sqr = Math.mulDiv(b, b, 1e18);
uint256 c_1 = Math.mulDiv(reserveIn, reserveIn, 1e18);
uint256 c_2 = Math.mulDiv(Math.mulDiv(reserveIn, reserveOut, 1e18), priceOut, priceIn);
uint256 c;
uint256 root;
if (c_1 > c_2) {
c = c_1 - c_2;
uint256 d = Math.mulDiv(4 * F, c, 1e18);
root = Math.sqrt(b_sqr - d) * 1e9;
} else {
c = c_2 - c_1;
uint256 d = Math.mulDiv(4 * F, c, 1e18);
root = Math.sqrt(b_sqr + d) * 1e9;
}
uint256 delta = Math.mulDiv(1e18, root - b, 2 * F);
return delta;
}
function _calculateDeltaUSC(uint256 ethPrice) public view returns (uint256) {
(uint256 reserveUSC, uint256 reserveWETH) =
UniswapV2Library.getReserves(address(poolFactory), address(USC), address(WETH));
return _calculateDelta(reserveUSC, USC_TARGET_PRICE, reserveWETH, ethPrice);
}
function _calculateDeltaETH(uint256 ethPrice) public view returns (uint256) {
(uint256 reserveUSC, uint256 reserveWETH) =
UniswapV2Library.getReserves(address(poolFactory), address(USC), address(WETH));
return _calculateDelta(reserveWETH, ethPrice, reserveUSC, USC_TARGET_PRICE);
}
function _makePath(address t1, address t2) internal pure returns (address[] memory path) {
path = new address[](2);
path[0] = t1;
path[1] = t2;
}
function _makePath(address t1, address t2, address t3) internal pure returns (address[] memory path) {
path = new address[](3);
path[0] = t1;
path[1] = t2;
path[2] = t3;
}
function _swap(address tokenIn, address tokenOut, uint256 amount) private returns (uint256) {
address[] memory path;
if (tokenIn != WETH && tokenOut != WETH) {
path = _makePath(tokenIn, WETH, tokenOut);
} else {
path = _makePath(tokenIn, tokenOut);
}
IERC20(tokenIn).approve(address(swapRouter), amount);
uint256[] memory amounts = swapRouter.swapExactTokensForTokens(amount, 0, path, address(this), block.timestamp);
uint256 amountReceived = amounts[path.length - 1];
return amountReceived;
}
function _getAmountInForAmountOut(address tIn, address tOut, uint256 amountOut) internal view returns (uint256) {
(uint256 rIn, uint256 rOut) = UniswapV2Library.getReserves(address(poolFactory), tIn, tOut);
return UniswapV2Library.getAmountIn(amountOut, rIn, rOut);
}
function _convertUsdValueToTokenAmount(uint256 usdValue, uint256 price) internal pure returns (uint256) {
return Math.mulDiv(usdValue, 1e18, price);
}
function _convertTokenAmountToUsdValue(uint256 amount, uint256 price) internal pure returns (uint256) {
return Math.mulDiv(amount, price, 1e18);
}
function _absDiff(uint256 a, uint256 b) internal pure returns (uint256) {
return (a > b) ? a - b : b - a;
}
function _almostEqualAbs(uint256 price1, uint256 price2, uint256 delta) internal pure returns (bool) {
return _absDiff(price1, price2) <= delta;
}
function _almostEqualRel(uint256 price1, uint256 price2, uint256 delta) internal pure returns (bool) {
(uint256 highPrice, uint256 lowPrice) = price1 > price2 ? (price1, price2) : (price2, price1);
uint256 priceDiff = highPrice - lowPrice;
uint256 maxPriceDiff = Math.mulDiv(highPrice, delta, MAX_PRICE_TOLERANCE);
return priceDiff <= maxPriceDiff;
}
receive() external payable {}
}
文件 4 的 23:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 5 的 23:ExternalContractAddresses.sol
pragma solidity ^0.8.0;
library ExternalContractAddresses {
address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant stETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
address public constant eETH = 0x35fA164735182de50811E8e2E824cFb9B6118ac2;
address public constant weETH = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;
address public constant eETH_POOL = 0x308861A430be4cce5502d0A12724771Fc6DaF216;
address public constant UNI_V2_SWAP_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address public constant UNI_V3_SWAP_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
address public constant UNI_V2_POOL_FACTORY = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
address public constant ETH_USD_CHAINLINK_FEED = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419;
address public constant STETH_USD_CHAINLINK_FEED = 0xCfE54B5cD566aB89272946F602D76Ea879CAb4a8;
address public constant WEETH_ETH_CHAINLINK_FEED = 0x5c9C449BbC9a6075A2c061dF312a35fd1E05fF22;
address public constant CURVE_ETH_STETH_POOL = 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022;
address public constant ONE_INCH_ROUTER = 0x111111125421cA6dc452d289314280a0f8842A65;
}
文件 6 的 23:IArbitrageERC20.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IArbitrageERC20 is IERC20 {
function mint(address to, uint256 amount) external;
function burn(uint256 amount) external;
}
文件 7 的 23:IArbitrageV5.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IArbitrageV5 {
struct SwapParams {
address reserveAsset;
uint256 amountIn;
uint256 minAmountOut;
}
error DeltaBiggerThanAmountReceivedETH(uint256 deltaETH, uint256 receivedETH);
error ToleranceTooBig(uint16 _tolerance);
error PriceSlippageTooBig();
error NotArbitrager(address account);
error PriceIsNotPegged();
error ReserveDiffTooBig();
error ChiPriceNotPegged(uint256 spotPrice, uint256 twapPrice);
error FeeTooBig(uint256 fee);
error ChiSpotPriceTooBig();
error ContractIsPaused();
error ReserveTxLimitExceeded();
event SetPriceTolerance(uint16 priceTolerance);
event Mint(address indexed account, address token, uint256 amount, uint256 uscAmount);
event ExecuteArbitrage(
address indexed account,
uint256 indexed arbNum,
uint256 deltaUsd,
uint256 reserveDiff,
uint256 ethPrice,
uint256 rewardValue
);
event UpdateArbitrager(address indexed account, bool status);
event SetMaxMintBurnPriceDiff(uint256 maxMintBurnPriceDiff);
event SetChiPriceTolerance(uint16 chiPriceTolerance);
event SetMaxMintBurnReserveTolerance(uint16 maxBurnReserveTolerance);
event SetMintBurnFee(uint256 mintFee);
event UpdatePrivileged(address indexed privileged, bool isPrivileged);
event Burn(address account, uint256 amount, uint256 reserveReceived, address reserve);
event RewardUSC(uint256 amount);
event SetReserveMintTxLimit(address reserveAsset, uint256 limit);
event SetReserveBurnTxLimit(address reserveAsset, uint256 limit);
function setReserveHolder(address _reserveHolder) external;
function setPegPriceToleranceAbs(uint256 _priceTolerance) external;
function setPriceTolerance(uint16 _priceTolerance) external;
function setReserveMintTxLimit(address reserveAsset, uint256 limit) external;
function setReserveBurnTxLimit(address reserveAsset, uint256 limit) external;
function mint(address receiver) external payable returns (uint256 uscAmount);
function mint(address token, uint256 amount, address receiver) external returns (uint256 uscAmount);
function executeArbitrageWithReserveSell(uint256 chiSpotPrice, SwapParams[] memory swapParams)
external
returns (uint256);
function executeArbitrage(uint256 maxChiSpotPrice) external returns (uint256 rewardValue);
function getArbitrageData()
external
view
returns (bool isPriceAtPeg, bool isPriceAboveTarget, bool isExcessOfReserves, uint256 reserveDiff);
function updateArbitrager(address account, bool status) external;
function claimRewards(IERC20[] memory tokens, uint256[] memory amounts) external;
function rewardUSC(uint256 amount) external;
function setMaxMintBurnPriceDiff(uint256 _maxMintBurnPriceDiff) external;
function setChiPriceTolerance(uint16 _chiPriceTolerance) external;
function setMaxMintBurnReserveTolerance(uint16 _maxMintBurnReserveTolerance) external;
function setMintBurnFee(uint16 _mintBurnFee) external;
function updatePrivileged(address account, bool status) external;
function burn(uint256 amount, address reserveToReceive) external returns (uint256 ethAmount);
function setMintPause(bool isPaused) external;
function setBurnPause(bool isPaused) external;
}
文件 8 的 23:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 9 的 23:IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 10 的 23:IOracle.sol
pragma solidity ^0.8.0;
interface IOracle {
function name() external view returns (string memory name);
function decimals() external view returns (uint8 decimals);
function peek() external view returns (uint256 price);
}
文件 11 的 23:IPriceFeedAggregator.sol
pragma solidity ^0.8.0;
import "src/interfaces/IOracle.sol";
interface IPriceFeedAggregator {
event SetPriceFeed(address indexed base, address indexed feed);
error ZeroAddress();
function setPriceFeed(address base, address feed) external;
function priceFeeds(address base) external view returns (IOracle feed);
function peek(address base) external view returns (uint256 price);
}
文件 12 的 23:IReserveHolderV2.sol
pragma solidity ^0.8.0;
interface IReserveHolderV2 {
struct ReserveAssetInfo {
uint256 totalDeposited;
uint256 totalClaimed;
address underlyingAsset;
address swapAdapter;
uint256 percentage;
}
event SetArbitrager(address indexed arbitrager, bool enabled);
event SetClaimer(address indexed claimer);
event SetRebalancer(address indexed rebalancer, bool enabled);
event SetSwapTolerance(uint256 swapTolerance);
event AddReserveAsset(address indexed reserveAsset);
event SetReserveAssetAdapter(address indexed reserveAsset, address adapter);
event SetReserveAssetPercentage(address indexed reserveAsset, uint256 percentage);
event Deposit(address indexed account, address indexed reserveAsset, uint256 amount);
event Rebalance();
event Redeem(address indexed account, address indexed reserve, uint256 amount);
event ClaimRewards(address indexed account);
event Claimed(address indexed account, address indexed reserveAsset, uint256 amount);
error NotArbitrager();
error NotClaimer();
error NotRebalancer();
error PercentageTooHigh();
error AssetAlreadyAdded();
error SlippageTooBig();
function getReserveAssets() external view returns (address[] memory reserveAssets);
function setArbitrager(address arbitrager, bool status) external;
function setClaimer(address claimer) external;
function setRebalancer(address rebalancer, bool status) external;
function setSwapTolerance(uint256 swapTolerance) external;
function addReserveAsset(address reserveAsset, address reserveAdapter, uint256 reservePercentage) external;
function setReserveAssetAdapter(address reserveAsset, address adapter) external;
function setReserveAssetPercentage(address reserveAsset, uint256 percentage) external;
function getReserveValue() external view returns (uint256 reserveValue);
function deposit(address reserveAsset, uint256 amount) external;
function rebalance(uint256[] memory spotPrices) external;
function redeem(uint256 amount, address reserve) external returns (uint256 wethAmount);
function claimRewards(address account) external;
function swapReserveForEth(address reserve, uint256 amountIn, uint256 minAmountOut) external;
}
文件 13 的 23:IUniswapV2Factory.sol
pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
文件 14 的 23:IUniswapV2Pair.sol
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
文件 15 的 23:IUniswapV2Router01.sol
pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
文件 16 的 23:IUniswapV2Router02.sol
pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
文件 17 的 23:IWETH.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}
文件 18 的 23:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1, "Math: mulDiv overflow");
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
文件 19 的 23:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 20 的 23:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
文件 21 的 23:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
文件 22 的 23:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x, "ds-math-add-overflow");
}
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x - y) <= x, "ds-math-sub-underflow");
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
}
}
文件 23 的 23:UniswapV2Library.sol
pragma solidity ^0.8.0;
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "./SafeMath.sol";
library UniswapV2Library {
using SafeMath for uint256;
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES");
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), "UniswapV2Library: ZERO_ADDRESS");
}
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
factory,
keccak256(abi.encodePacked(token0, token1)),
hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"
)
)
)
)
);
}
function getReserves(address factory, address tokenA, address tokenB)
internal
view
returns (uint256 reserveA, uint256 reserveB)
{
(address token0,) = sortTokens(tokenA, tokenB);
(uint256 reserve0, uint256 reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) internal pure returns (uint256 amountB) {
require(amountA > 0, "UniswapV2Library: INSUFFICIENT_AMOUNT");
require(reserveA > 0 && reserveB > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY");
amountB = amountA.mul(reserveB) / reserveA;
}
function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut)
internal
pure
returns (uint256 amountOut)
{
require(amountIn > 0, "UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT");
require(reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY");
uint256 amountInWithFee = amountIn.mul(997);
uint256 numerator = amountInWithFee.mul(reserveOut);
uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut)
internal
pure
returns (uint256 amountIn)
{
require(amountOut > 0, "UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT");
require(reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY");
uint256 numerator = reserveIn.mul(amountOut).mul(1000);
uint256 denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
function getAmountsOut(address factory, uint256 amountIn, address[] memory path)
internal
view
returns (uint256[] memory amounts)
{
require(path.length >= 2, "UniswapV2Library: INVALID_PATH");
amounts = new uint256[](path.length);
amounts[0] = amountIn;
for (uint256 i; i < path.length - 1; i++) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i], path[i + 1]);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
function getAmountsIn(address factory, uint256 amountOut, address[] memory path)
internal
view
returns (uint256[] memory amounts)
{
require(path.length >= 2, "UniswapV2Library: INVALID_PATH");
amounts = new uint256[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint256 i = path.length - 1; i > 0; i--) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i - 1], path[i]);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
}
{
"compilationTarget": {
"src/ArbitrageV5.sol": "ArbitrageV5"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@chainlink/=lib/chainlink/",
":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":@uniswap/v2-core/=lib/v2-core/",
":@uniswap/v2-periphery/=lib/v2-periphery/",
":@uniswap/v3-core/=lib/v3-core/",
":@uniswap/v3-periphery/=lib/v3-periphery/",
":chainlink/=lib/chainlink/",
":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":openzeppelin-foundry-upgrades-0.3.6/=dependencies/openzeppelin-foundry-upgrades-0.3.6/",
":openzeppelin-foundry-upgrades/=dependencies/openzeppelin-foundry-upgrades-0.3.6/src/",
":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
":solidity-stringutils/=dependencies/openzeppelin-foundry-upgrades-0.3.6/lib/solidity-stringutils/",
":v2-core/=lib/v2-core/contracts/",
":v2-periphery/=lib/v2-periphery/contracts/",
":v3-core/=lib/v3-core/",
":v3-periphery/=lib/v3-periphery/contracts/"
]
}
[{"inputs":[{"internalType":"contract IArbitrageERC20","name":"_USC","type":"address"},{"internalType":"contract IArbitrageERC20","name":"_CHI","type":"address"},{"internalType":"contract IPriceFeedAggregator","name":"_priceFeedAggregator","type":"address"},{"internalType":"contract IReserveHolderV2","name":"_reserveHolder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"spotPrice","type":"uint256"},{"internalType":"uint256","name":"twapPrice","type":"uint256"}],"name":"ChiPriceNotPegged","type":"error"},{"inputs":[],"name":"ChiSpotPriceTooBig","type":"error"},{"inputs":[],"name":"ContractIsPaused","type":"error"},{"inputs":[{"internalType":"uint256","name":"deltaETH","type":"uint256"},{"internalType":"uint256","name":"receivedETH","type":"uint256"}],"name":"DeltaBiggerThanAmountReceivedETH","type":"error"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"FeeTooBig","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotArbitrager","type":"error"},{"inputs":[],"name":"PriceIsNotPegged","type":"error"},{"inputs":[],"name":"PriceSlippageTooBig","type":"error"},{"inputs":[],"name":"ReserveDiffTooBig","type":"error"},{"inputs":[],"name":"ReserveTxLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint16","name":"_tolerance","type":"uint16"}],"name":"ToleranceTooBig","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserveReceived","type":"uint256"},{"indexed":false,"internalType":"address","name":"reserve","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"arbNum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deltaUsd","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserveDiff","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardValue","type":"uint256"}],"name":"ExecuteArbitrage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"uscAmount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardUSC","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"chiPriceTolerance","type":"uint16"}],"name":"SetChiPriceTolerance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxMintBurnPriceDiff","type":"uint256"}],"name":"SetMaxMintBurnPriceDiff","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"maxBurnReserveTolerance","type":"uint16"}],"name":"SetMaxMintBurnReserveTolerance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"mintFee","type":"uint256"}],"name":"SetMintBurnFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"priceTolerance","type":"uint16"}],"name":"SetPriceTolerance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"reserveAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"SetReserveBurnTxLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"reserveAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"SetReserveMintTxLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"UpdateArbitrager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"privileged","type":"address"},{"indexed":false,"internalType":"bool","name":"isPrivileged","type":"bool"}],"name":"UpdatePrivileged","type":"event"},{"inputs":[],"name":"BASE_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CHI","outputs":[{"internalType":"contract IArbitrageERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"F","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PRICE_TOLERANCE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOL_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USC","outputs":[{"internalType":"contract IArbitrageERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USC_TARGET_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"priceIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"},{"internalType":"uint256","name":"priceOut","type":"uint256"}],"name":"_calculateDelta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"ethPrice","type":"uint256"}],"name":"_calculateDeltaETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"ethPrice","type":"uint256"}],"name":"_calculateDeltaUSC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_getReservesData","outputs":[{"internalType":"bool","name":"isExcessOfReserves","type":"bool"},{"internalType":"uint256","name":"reserveDiff","type":"uint256"},{"internalType":"uint256","name":"reserveValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"reserveToReceive","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chiPriceTolerance","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxChiSpotPrice","type":"uint256"}],"name":"executeArbitrage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxChiSpotPrice","type":"uint256"},{"components":[{"internalType":"address","name":"reserveAsset","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"internalType":"struct IArbitrageV5.SwapParams[]","name":"swapParams","type":"tuple[]"}],"name":"executeArbitrageWithReserveSell","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getArbitrageData","outputs":[{"internalType":"bool","name":"isPriceAtPeg","type":"bool"},{"internalType":"bool","name":"isPriceAboveTarget","type":"bool"},{"internalType":"bool","name":"isExcessOfReserves","type":"bool"},{"internalType":"uint256","name":"reserveDiff","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isArbitrager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isPrivileged","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintBurnPriceDiff","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintBurnReserveTolerance","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintBurnFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pegPriceToleranceAbs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolFactory","outputs":[{"internalType":"contract IUniswapV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedAggregator","outputs":[{"internalType":"contract IPriceFeedAggregator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceTolerance","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"reserveBurnTxLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserveHolder","outputs":[{"internalType":"contract IReserveHolderV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"reserveMintTxLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rewardUSC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isPaused","type":"bool"}],"name":"setBurnPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_chiPriceTolerance","type":"uint16"}],"name":"setChiPriceTolerance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxMintBurnPriceDiff","type":"uint256"}],"name":"setMaxMintBurnPriceDiff","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_maxMintBurnReserveTolerance","type":"uint16"}],"name":"setMaxMintBurnReserveTolerance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_mintBurnFee","type":"uint16"}],"name":"setMintBurnFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isPaused","type":"bool"}],"name":"setMintPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_priceTolerance","type":"uint256"}],"name":"setPegPriceToleranceAbs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_priceTolerance","type":"uint16"}],"name":"setPriceTolerance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"reserveAsset","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setReserveBurnTxLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_reserveHolder","type":"address"}],"name":"setReserveHolder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"reserveAsset","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setReserveMintTxLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalMintedUsc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"arbitrager","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"updateArbitrager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"updatePrivileged","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]