编译器
0.8.26+commit.8a97fa7a
文件 1 的 19:AFiManager.sol
pragma solidity ^0.8.0;
import "./IAFi.sol";
import "./IAFiStorage.sol";
import "./TransferHelper.sol";
import {OwnableDelayModule} from "./OwnableDelayModule.sol";
import {ReentrancyGuard} from "./ReentrancyGuard.sol";
import "./ArrayUtils.sol";
import {SafeERC20} from "./SafeERC20.sol";
import "./IPassiveRebal.sol";
import {IUniswapOracleV3} from "./IUniswapV3.sol";
contract AFiManager is OwnableDelayModule, ReentrancyGuard {
using ArrayUtils for uint[];
using ArrayUtils for address[];
using SafeERC20 for IERC20;
address internal rebal;
uint256 internal preDepositsStablesInUSD;
mapping(address => bool) public isQueueWithdrawUnstakingPaused;
uint256 public rebalfee = 500;
uint256 public rebalFeeUpperLimit = 5000;
bool internal paused;
address[] private _uTokensAfterRebalance;
address[] public tokens;
uint[] internal defaultProportion;
address internal afiOracle;
address internal constant UNISWAP_EXCHANGE =
0xE592427A0AEce92De3Edee1F18E0157C05861564;
mapping(address => mapping(address => bool)) internal underlyingExists;
mapping(address => bool) internal isUnderlyingCommon;
address public rebalanceController;
struct RebalanceData {
IAFi aFiContract;
IAFiStorage _aFiStorage;
IERC20 depositToken;
address newUToken;
address uTokenToRemove;
uint256 scenario;
address[] uTokensAfterS1;
uint256[] uTokenProportions;
uint256[] defaultProportion;
uint256 uTokenToRemoveIndex;
}
event Rebalance(IAFi indexed _aFiContract, uint8 _scenario);
event AddTeamWalletInAFi(address indexed aFiContract, address _wallet);
event WithdrawFromPool(address indexed _aFiContract, address uToken);
event AFiManagerSwap(
IAFi indexed _aFiContract,
address _fromToken,
address _toToken,
uint _amount
);
event SetActiveRebalStatus(address indexed _aFiContract, bool status);
event RebalanceUnderlyingTokens(
address indexed aFiContract,
address _aFiStorage,
address[] newUnderlyingTokens,
address stableCoin,
uint managerFee
);
event UTokenProportionUpdated(
address indexed aFiContract,
uint256[] uTokenProportions
);
event Paused(address account);
event Unpaused(address account);
modifier contractUnpaused() {
require(!paused, "AM08");
_;
}
modifier contractPaused() {
require(paused, "AM09");
_;
}
function compareInt(uint256 val1, uint256 val2) internal pure {
require(val1 == val2, "AM11");
}
function compareAddress(address add1, address add2) internal pure {
require(add1 == add2, "AM002");
}
function pause() external contractUnpaused onlyOwner {
paused = true;
emit Paused(msg.sender);
}
function unPause() external contractPaused onlyOwner {
paused = false;
emit Unpaused(msg.sender);
}
function validateGreaterEqual(uint256 val1, uint256 val2) internal pure {
require(val1 >= val2, "AFS19");
}
function addressCheck(address add1, address add2) internal pure {
require(add1 != add2, "AM04");
}
function getPauseStatus() external view returns (bool) {
return paused;
}
function isPresentCheck(bool isPresent) internal pure {
if (isPresent) revert("AFM03");
}
function setRebalanceController(address _rebalanceController) external onlyOwner {
addressCheck(_rebalanceController, address(0));
rebalanceController = _rebalanceController;
}
function addTeamWalletInAFi(
IAFiStorage _aFiStorage,
address aFiContract,
address _wallet
) external nonReentrant onlyOwner contractUnpaused {
require(_wallet != address(0), "AFM02");
(, bool isPresent) = _aFiStorage.getTeamWalletDetails(aFiContract, _wallet);
isPresentCheck(isPresent);
_aFiStorage.addTeamWallet(aFiContract, _wallet, true, true);
emit AddTeamWalletInAFi(aFiContract, _wallet);
}
function rebalance(
bytes memory data,
RebalanceData memory rebalData,
uint deadline,
uint[] memory minimumReturnAmount,
uint stableAmountOut,
uint256 _rebalFeeToDeduct
) external nonReentrant contractUnpaused {
compareAddress(msg.sender, rebalanceController);
require(rebalData.scenario < 3 && rebalData.scenario > 0, "AM05");
require(rebalData.uTokenToRemove != address(rebalData.depositToken), "AM010");
require(
rebalData._aFiStorage.isAFiActiveRebalanced(address(rebalData.aFiContract)),
"AM00"
);
(, rebal, ) = IAFi(rebalData.aFiContract).getTVLandRebalContractandType();
address[] memory uTokens = IAFi(rebalData.aFiContract).getUTokens();
require(uTokens[rebalData.uTokenToRemoveIndex] == rebalData.uTokenToRemove, "AM12");
if (rebalData.scenario == 2) {
(, bool present) = ArrayUtils.indexOf(uTokens, rebalData.newUToken);
isPresentCheck(present);
validateNewUTokenData(data, rebalData.newUToken);
}else {
require(uTokens.length > 1, "AM032");
}
uint totalReturnedDepositToken;
{
totalReturnedDepositToken = rebalData.depositToken.balanceOf(
address(rebalData.aFiContract)
);
rebalData._aFiStorage._withdrawAll(
address(rebalData.aFiContract),
rebalData.uTokenToRemove
);
convertToStable(
rebalData.aFiContract,
rebalData.uTokenToRemove,
address(rebalData.depositToken),
deadline,
stableAmountOut
);
checkRebalFeesandDeduct(
_rebalFeeToDeduct,
address(rebalData.depositToken),
rebalData.aFiContract
);
totalReturnedDepositToken =
rebalData.depositToken.balanceOf(address(rebalData.aFiContract)) -
totalReturnedDepositToken;
}
(address[] memory inputStables, address[] memory nonOverlappingITokens) = IAFi(
rebalData.aFiContract
).getInputToken();
updateInputTokenData(
address(rebalData.aFiContract),
address(rebalData._aFiStorage),
rebalData.uTokenToRemove,
inputStables,
nonOverlappingITokens
);
defaultProportion = rebalData.defaultProportion;
(, rebalData.defaultProportion) = rebalData.aFiContract.getProportions();
bool isNewTokenPresent;
{
if (rebalData.scenario == 1) {
if (
IPassiveRebal(rebal).getRebalStrategyNumber(address(rebalData.aFiContract)) ==
1
) {
(rebalData.uTokenProportions, ) = updateProportion(
address(rebalData.aFiContract),
rebalData._aFiStorage,
uTokens
);
} else {
rebalData.uTokenProportions = rebalData.defaultProportion;
}
rebalData.uTokensAfterS1 = scenario1Investments(
rebalData,
uTokens,
totalReturnedDepositToken,
deadline,
minimumReturnAmount
);
rebalData.aFiContract.updateuTokAndProp(rebalData.uTokensAfterS1);
} else {
(inputStables, nonOverlappingITokens) = IAFi(rebalData.aFiContract)
.getInputToken();
rebalData.aFiContract.updatePoolData(data);
(, isNewTokenPresent) = ArrayUtils.indexOf(
nonOverlappingITokens,
rebalData.newUToken
);
if (isNewTokenPresent) {
nonOverlappingITokens = removeFromNonOverlappingITokens(
nonOverlappingITokens,
rebalData.newUToken
);
}
IAFi(rebalData.aFiContract).updateInputTokens(nonOverlappingITokens);
uTokens = scenario2Investments(
rebalData.depositToken,
rebalData.uTokenToRemoveIndex,
rebalData.aFiContract,
uTokens,
rebalData.newUToken,
totalReturnedDepositToken,
deadline,
minimumReturnAmount
);
(rebalData.uTokenProportions, ) = updateProportion(
address(rebalData.aFiContract),
rebalData._aFiStorage,
uTokens
);
updateAFiData(
rebalData.aFiContract,
uTokens,
defaultProportion,
rebalData.uTokenProportions
);
}
}
}
function updateAFiData(
IAFi afiContract,
address[] memory uTokens,
uint256[] memory dp,
uint256[] memory cp
) internal {
afiContract.updateDp(dp, cp);
afiContract.updateuTokAndProp(uTokens);
}
function updateInputTokenData(
address aFiContract,
address _aFiStorage,
address uTokenToRemove,
address[] memory inputStables,
address[] memory nonOverlappingITokens
) internal {
(, bool isInputStable) = ArrayUtils.indexOf(inputStables, uTokenToRemove);
if (isInputStable) {
IAFiStorage(_aFiStorage).deletePreDepositedInputToken(
aFiContract,
uTokenToRemove,
IAFi(aFiContract).getcSwapCounter()
);
nonOverlappingITokens = addToNonOverlappingITokens(
nonOverlappingITokens,
uTokenToRemove
);
IAFi(aFiContract).updateInputTokens(nonOverlappingITokens);
}
}
function addToNonOverlappingITokens(
address[] memory _nonOverlappingITokens,
address token
) internal pure returns (address[] memory) {
(, bool isPresent) = ArrayUtils.indexOf(_nonOverlappingITokens, token);
if (!isPresent) {
address[] memory newTokens = new address[](_nonOverlappingITokens.length + 1);
for (uint i = 0; i < _nonOverlappingITokens.length; i++) {
newTokens[i] = _nonOverlappingITokens[i];
}
newTokens[_nonOverlappingITokens.length] = token;
return newTokens;
}
return _nonOverlappingITokens;
}
function removeFromNonOverlappingITokens(
address[] memory _nonOverlappingITokens,
address token
) internal pure returns (address[] memory) {
(, bool isPresent) = ArrayUtils.indexOf(_nonOverlappingITokens, token);
if (isPresent) {
return ArrayUtils.remove(_nonOverlappingITokens, token);
}
return _nonOverlappingITokens;
}
function scenario1Investments(
RebalanceData memory rebalData,
address[] memory uTokens,
uint totalReturnedDepositToken,
uint deadline,
uint[] memory minimumReturnAmount
) internal returns (address[] memory rbtoUTokens) {
uint256 _denominator;
uint256 swapAmount;
for (uint i = 0; i < uTokens.length; i++) {
if (i != rebalData.uTokenToRemoveIndex) {
_denominator += rebalData.defaultProportion[i];
rebalData.scenario += rebalData.uTokenProportions[i];
}
}
address midTok;
uint256[] memory defaultTokens = new uint256[](uTokens.length - 1);
rbtoUTokens = new address[](uTokens.length - 1);
for (uint j = 0; j < uTokens.length; j++) {
if (j != rebalData.uTokenToRemoveIndex) {
uint256 proportion = (rebalData.defaultProportion[j] * 10000000) / _denominator;
if (j > rebalData.uTokenToRemoveIndex) {
defaultTokens[j - 1] = proportion;
rbtoUTokens[j - 1] = uTokens[j];
} else {
rbtoUTokens[j] = uTokens[j];
defaultTokens[j] = proportion;
}
midTok = IUniswapOracleV3(afiOracle).getMidToken(uTokens[j]);
swapAmount =
(rebalData.uTokenProportions[j] * totalReturnedDepositToken) /
rebalData.scenario;
aFiManagerSwap(
address(rebalData.depositToken),
uTokens[j],
swapAmount,
rebalData.aFiContract,
deadline,
midTok,
minimumReturnAmount[j]
);
}
}
(rebalData.uTokenProportions, ) = updateProportion(
address(rebalData.aFiContract),
rebalData._aFiStorage,
rbtoUTokens
);
rebalData.aFiContract.updateDp(defaultTokens, rebalData.uTokenProportions);
emit Rebalance(rebalData.aFiContract, 1);
return rbtoUTokens;
}
function scenario2Investments(
IERC20 depositToken,
uint uTokenToRemoveIndex,
IAFi aFiContract,
address[] memory uTokens,
address newUToken,
uint totalReturnedDepositToken,
uint deadline,
uint[] memory minimumReturnAmount
) internal returns (address[] memory rbtoUTokens) {
{
rbtoUTokens = new address[](uTokens.length);
for (uint j = 0; j < uTokens.length; j++) {
if (j != uTokenToRemoveIndex) {
if (j < uTokenToRemoveIndex) {
rbtoUTokens[j] = uTokens[j];
} else {
rbtoUTokens[j - 1] = uTokens[j];
}
}
}
rbtoUTokens[rbtoUTokens.length - 1] = newUToken;
_uTokensAfterRebalance = rbtoUTokens;
address midTok = IUniswapOracleV3(afiOracle).getMidToken(newUToken);
aFiManagerSwap(
address(depositToken),
newUToken,
totalReturnedDepositToken,
aFiContract,
deadline,
midTok,
minimumReturnAmount[0]
);
}
emit Rebalance(aFiContract, 2);
}
function aFiManagerSwap(
address from,
address to,
uint amount,
IAFi aFiContract,
uint256 deadline,
address midTok,
uint minimumReturnAmount
) internal {
{
aFiContract.swapViaStorageOrManager(
from,
to,
amount,
deadline,
midTok,
minimumReturnAmount
);
}
emit AFiManagerSwap(aFiContract, from, to, amount);
}
function validateNewUTokenData(bytes memory _data, address newUToken) internal pure {
IAFi.PoolsData memory pooldata = abi.decode(_data, (IAFi.PoolsData));
IAFi.UnderlyingData memory uniData = abi.decode(
pooldata.underlyingData,
(IAFi.UnderlyingData)
);
require(
pooldata._underlyingTokensProportion.length == pooldata._compound.length &&
pooldata._compound.length == pooldata.compoundV3Comet.length &&
pooldata.compoundV3Comet.length == pooldata._aaveToken.length,
"AFM05"
);
compareInt(uniData._underlyingTokens.length, 1);
compareInt(pooldata._underlyingTokensProportion[0], 0);
require(uniData._underlyingTokens[0] == newUToken, "AFM08");
}
function setActiveRebalStatus(
IAFiStorage _aFiStorage,
address aFiContract,
bool status
) external nonReentrant onlyOwner contractUnpaused {
_aFiStorage.setActiveRebalancedStatus(aFiContract, status);
emit SetActiveRebalStatus(aFiContract, status);
}
struct AlgoRebalanceData {
IAFi aFiContract;
IAFiStorage _aFiStorage;
bytes underlyingData;
address[] newUnderlyingOracle;
address[] prevUnderlying;
address stableCoin;
uint managerFee;
uint deadline;
uint[] minimumReturnAmount;
uint[] minimumUnderlyingAmount;
}
function balance(address tok, address target) internal view returns (uint256) {
return IERC20(tok).balanceOf(target);
}
function rebalanceUnderlyingTokens(
AlgoRebalanceData memory rebalanceData,
IAFi.SwapParameters memory csParams
) external contractUnpaused {
compareAddress(msg.sender, rebalanceController);
require(rebalanceData.newUnderlyingOracle.length <= 10, "AM07");
rebalanceData.prevUnderlying = rebalanceData.aFiContract.getUTokens();
checkProductType(rebalanceData.aFiContract);
(, rebal, ) = IAFi(rebalanceData.aFiContract).getTVLandRebalContractandType();
(address[] memory iToken, ) = IAFi(rebalanceData.aFiContract).getInputToken();
(iToken, ) = IAFi(rebalanceData.aFiContract).getInputToken();
IPassiveRebal(rebal).initUniStructure(iToken, rebalanceData.underlyingData);
IAFi.UnderlyingData memory underlyingUniData = abi.decode(
rebalanceData.underlyingData,
(IAFi.UnderlyingData)
);
uint stableCoinBalance = balance(
rebalanceData.stableCoin,
address(rebalanceData.aFiContract)
);
uint sameUnderlyingCount = rebalanceAlgo(
rebalanceData.aFiContract,
rebalanceData.underlyingData,
rebalanceData.newUnderlyingOracle,
rebalanceData.prevUnderlying
);
swapUnderlying(
rebalanceData,
underlyingUniData._underlyingTokens,
sameUnderlyingCount,
stableCoinBalance,
(rebalanceData.prevUnderlying.length ==
underlyingUniData._underlyingTokens.length)
);
uint256[] memory newProp = new uint256[](
underlyingUniData._underlyingTokens.length
);
(newProp, ) = updateProportion(
address(rebalanceData.aFiContract),
rebalanceData._aFiStorage,
underlyingUniData._underlyingTokens
);
updateAFiData(
rebalanceData.aFiContract,
underlyingUniData._underlyingTokens,
newProp,
newProp
);
doCswap(rebalanceData.aFiContract, csParams, rebalanceData._aFiStorage);
emit RebalanceUnderlyingTokens(
address(rebalanceData.aFiContract),
address(rebalanceData._aFiStorage),
underlyingUniData._underlyingTokens,
rebalanceData.stableCoin,
rebalanceData.managerFee
);
}
function doCswap(
IAFi afiContract,
IAFi.SwapParameters memory csParams,
IAFiStorage aFiStorage
) internal {
(address[] memory _iToken, ) = afiContract.getInputToken();
uint256 totalPreDepBalance;
for (uint i = 0; i < _iToken.length; i++) {
totalPreDepBalance += getPredepBalInUSDC(
_iToken[i],
address(afiContract),
aFiStorage
);
}
if (totalPreDepBalance >= afiContract.getPreSwapDepositLimit()) {
IUniswapOracleV3(afiOracle).cumulativeSwap(csParams);
}
}
function setafiOracleContract(address _afiOracle) external onlyOwner {
addressCheck(_afiOracle, address(0));
afiOracle = _afiOracle;
}
function setRebalFeeUpperLimit(uint256 _rebalFeeUpperLimit) external onlyOwner {
rebalFeeUpperLimit = _rebalFeeUpperLimit;
}
function setRebalFee(uint256 _rebalfee) external onlyOwner {
require(_rebalfee <= rebalFeeUpperLimit, "AFMO111");
rebalfee = _rebalfee;
}
function rebalanceAlgo(
IAFi aFiContract,
bytes memory uniData,
address[] memory newUnderlyingOracle,
address[] memory prevUnderlying
) internal returns (uint256) {
bool exist;
uint sameUnderlyingCount;
(, rebal, ) = aFiContract.getTVLandRebalContractandType();
IAFi.UnderlyingData memory underlyingUniData = abi.decode(
uniData,
(IAFi.UnderlyingData)
);
for (uint i = 0; i < prevUnderlying.length; i++) {
underlyingExists[address(aFiContract)][prevUnderlying[i]] = true;
}
for (uint i = 0; i < underlyingUniData._underlyingTokens.length; i++) {
if (prevUnderlying.length == underlyingUniData._underlyingTokens.length) {
exist = checkIfUTokenExist(
address(aFiContract),
underlyingUniData._underlyingTokens[i]
);
if (exist) {
isUnderlyingCommon[underlyingUniData._underlyingTokens[i]] = true;
delete exist;
sameUnderlyingCount++;
}
}
IPassiveRebal(rebal).updateOracleData(
underlyingUniData._underlyingTokens[i],
newUnderlyingOracle[i]
);
}
IUniswapOracleV3(afiOracle).updateMidToken(
underlyingUniData._underlyingTokens,
underlyingUniData._underlyingUniPoolToken
);
return sameUnderlyingCount;
}
function swapUnderlying(
AlgoRebalanceData memory rebalanceData,
address[] memory uTokensToAdd,
uint _sameUnderlying,
uint oldBalance,
bool isLengthEqual
) internal {
address midTok;
uint rebalanceAmount;
uint stableCoinBalance;
if (isLengthEqual) {
for (uint i = 0; i < rebalanceData.prevUnderlying.length; i++) {
if (!isUnderlyingCommon[rebalanceData.prevUnderlying[i]]) {
rebalanceAmount = balance(
rebalanceData.prevUnderlying[i],
address(rebalanceData.aFiContract)
);
midTok = IUniswapOracleV3(afiOracle).getMidToken(
rebalanceData.prevUnderlying[i]
);
aFiManagerSwap(
rebalanceData.prevUnderlying[i],
rebalanceData.stableCoin,
rebalanceAmount,
rebalanceData.aFiContract,
rebalanceData.deadline,
midTok,
rebalanceData.minimumReturnAmount[i]
);
}
}
checkRebalFeesandDeduct(
rebalanceData.managerFee,
rebalanceData.stableCoin,
rebalanceData.aFiContract
);
stableCoinBalance = ((
balance(rebalanceData.stableCoin, address(rebalanceData.aFiContract))
) - (oldBalance));
rebalanceAmount = (stableCoinBalance) / (uTokensToAdd.length - _sameUnderlying);
for (uint i = 0; i < uTokensToAdd.length; i++) {
if (!isUnderlyingCommon[uTokensToAdd[i]]) {
midTok = IUniswapOracleV3(afiOracle).getMidToken(uTokensToAdd[i]);
aFiManagerSwap(
rebalanceData.stableCoin,
uTokensToAdd[i],
rebalanceAmount,
rebalanceData.aFiContract,
rebalanceData.deadline,
midTok,
rebalanceData.minimumUnderlyingAmount[i]
);
} else {
delete isUnderlyingCommon[uTokensToAdd[i]];
}
}
} else {
for (uint i = 0; i < rebalanceData.prevUnderlying.length; i++) {
rebalanceAmount = balance(
rebalanceData.prevUnderlying[i],
address(rebalanceData.aFiContract)
);
midTok = IUniswapOracleV3(afiOracle).getMidToken(
rebalanceData.prevUnderlying[i]
);
aFiManagerSwap(
rebalanceData.prevUnderlying[i],
rebalanceData.stableCoin,
rebalanceAmount,
rebalanceData.aFiContract,
rebalanceData.deadline,
midTok,
rebalanceData.minimumReturnAmount[i]
);
}
checkRebalFeesandDeduct(
rebalanceData.managerFee,
rebalanceData.stableCoin,
rebalanceData.aFiContract
);
stableCoinBalance = ((
balance(rebalanceData.stableCoin, address(rebalanceData.aFiContract))
) - (oldBalance));
rebalanceAmount = (stableCoinBalance) / (uTokensToAdd.length);
for (uint i = 0; i < uTokensToAdd.length; i++) {
midTok = IUniswapOracleV3(afiOracle).getMidToken(uTokensToAdd[i]);
aFiManagerSwap(
rebalanceData.stableCoin,
uTokensToAdd[i],
rebalanceAmount,
rebalanceData.aFiContract,
rebalanceData.deadline,
midTok,
rebalanceData.minimumUnderlyingAmount[i]
);
}
}
for (uint256 i = 0; i < rebalanceData.prevUnderlying.length; i++) {
delete underlyingExists[address(rebalanceData.aFiContract)][
rebalanceData.prevUnderlying[i]
];
}
}
function checkRebalFeesandDeduct(
uint256 fee,
address stableCoin,
IAFi aficontract
) internal {
require(fee / (10 ** IERC20(stableCoin).decimals()) <= rebalfee, "AB35");
aficontract.sendProfitOrFeeToManager(msg.sender, fee, stableCoin);
}
function withdrawFromPool(
IAFiStorage _afiStorage,
IAFi aFiContract,
address underlyinToken
) external nonReentrant onlyOwner contractUnpaused {
_afiStorage._withdrawAll(address(aFiContract), underlyinToken);
emit WithdrawFromPool(address(aFiContract), underlyinToken);
}
function updateProportion(
address aFiContract,
IAFiStorage _aFiStorage,
address[] memory uTok
) internal view returns (uint256[] memory prop, uint256 totalProp) {
uint256 totalBalance;
for (uint i = 0; i < uTok.length; i++) {
totalBalance += (_aFiStorage.calcPoolValue(uTok[i], aFiContract) -
getPredepBalInUSDC(uTok[i], aFiContract, _aFiStorage));
}
prop = new uint256[](uTok.length);
unchecked {
for (uint j = 0; j < uTok.length; j++) {
prop[j] =
((_aFiStorage.calcPoolValue(uTok[j], aFiContract) -
getPredepBalInUSDC(uTok[j], aFiContract, _aFiStorage)) * (10000000)) /
(totalBalance);
totalProp = totalProp + prop[j];
}
}
return (prop, totalProp);
}
function getPredepBalInUSDC(
address tok,
address aFiContract,
IAFiStorage _aFiStorage
) internal view returns (uint256 tokPredepInUSD) {
uint256 temp;
uint256 multiplier;
(temp, multiplier) = _aFiStorage.getPriceInUSDC(tok);
uint256 depTok = _aFiStorage.getPreSwapDepositsTokens(
aFiContract,
IAFi(aFiContract).getcSwapCounter(),
tok
);
tokPredepInUSD = (depTok) * (uint(temp));
temp = _aFiStorage.validateAndGetDecimals(tok);
tokPredepInUSD = ((tokPredepInUSD * (10 ** temp)) / (multiplier));
}
function checkIfUTokenExist(
address afiContract,
address uTok
) internal view returns (bool) {
return underlyingExists[afiContract][uTok];
}
function updateStableUnitsInUSD(
uint256 _preDepositsStablesInUSD
) external returns (uint256) {
compareAddress(msg.sender, rebalanceController);
preDepositsStablesInUSD = _preDepositsStablesInUSD;
return _preDepositsStablesInUSD;
}
function getUTokenProportion(
address aFiContract,
address _aFiStorage
)
external
view
returns (uint256[] memory underlyingTokenProportions, uint256 totalProp)
{
(, address rebalAddress, ) = IAFi(aFiContract).getTVLandRebalContractandType();
compareAddress(msg.sender, rebalAddress);
(underlyingTokenProportions, totalProp) = updateProportion(
aFiContract,
IAFiStorage(_aFiStorage),
IAFi(aFiContract).getUTokens()
);
}
function inputTokenUSD(
IAFi aFiContract,
uint256 cSwapCounter,
IAFiStorage _aFiStorage
) public view returns (uint256 totalPreDepositInUSD) {
(address[] memory _iToken, ) = aFiContract.getInputToken();
uint256 depTok;
uint uTokensDecimal;
uint256 price;
uint256 multiplier;
for (uint i = 0; i < _iToken.length; i++) {
(depTok) = _aFiStorage.getPreSwapDepositsTokens(
address(aFiContract),
cSwapCounter,
address(_iToken[i])
);
if (depTok > 0) {
uTokensDecimal = IERC20(_iToken[i]).decimals();
(price, multiplier) = _aFiStorage.getPriceInUSDC(_iToken[i]);
validateGreaterEqual(18, uTokensDecimal);
uTokensDecimal = 18 - uTokensDecimal;
totalPreDepositInUSD += (((depTok) * (10 ** uTokensDecimal) * (uint(price))) /
(multiplier));
}
}
}
function emergencyRebalance(
IAFi aFiContract,
IAFiStorage _aFiStorage,
address uTokenToRemove,
uint256[] memory defProp
) external nonReentrant onlyOwner contractUnpaused {
rebalanceInternal(aFiContract, _aFiStorage, uTokenToRemove, defProp);
}
function rebalanceInternal(
IAFi aFiContract,
IAFiStorage _aFiStorage,
address uTokenToRemove,
uint256[] memory defProp
) internal {
address[] memory uTok = aFiContract.getUTokens();
(uint index, ) = ArrayUtils.indexOf(uTok, uTokenToRemove);
for (uint i = 0; i < uTok.length; i++) {
if (i >= index && i != (uTok.length - 1)) {
uTok[i] = uTok[i + 1];
}
if (i == (uTok.length - 1)) {
assembly {
mstore(uTok, sub(mload(uTok), 1))
}
}
}
compareInt(uTok.length, defProp.length);
_aFiStorage._withdrawAll(address(aFiContract), uTokenToRemove);
(
address[] memory inputStables,
address[] memory nonOverlappingITokens
) = aFiContract.getInputToken();
(, , uint256 productType) = aFiContract.getTVLandRebalContractandType();
if(productType != 3){
updateInputTokenData(
address(aFiContract),
address(_aFiStorage),
uTokenToRemove,
inputStables,
nonOverlappingITokens
);
}
updateAFiData(aFiContract, uTok, defProp, defProp);
}
function checkProductType(IAFi afiContract) internal {
(, , uint256 productType) = afiContract.getTVLandRebalContractandType();
compareInt(productType, 3);
}
function algoRebalance2(
IAFi aFiContract,
IAFiStorage _aFiStorage,
address uTokenToRemove,
uint256[] memory defProp,
address depositTok,
uint256 deadline,
uint256 stableamountOut
) external nonReentrant contractUnpaused {
compareAddress(msg.sender, rebalanceController);
(address[] memory inputStables, ) = aFiContract.getInputToken();
(, bool present) = ArrayUtils.indexOf(inputStables, depositTok);
require(present, "AM003");
rebalanceInternal(aFiContract, _aFiStorage, uTokenToRemove, defProp);
uint256 balToConsider = convertToStable(
aFiContract,
uTokenToRemove,
depositTok,
deadline,
stableamountOut
);
if(uTokenToRemove == depositTok){
balToConsider = _aFiStorage.getPreSwapDepositsTokens(
address(aFiContract),
aFiContract.getcSwapCounter(),
uTokenToRemove
);
}
balToConsider = balance(depositTok, address(aFiContract)) - balToConsider;
_aFiStorage.setPreDepositedInputTokenInRebalance(
address(aFiContract),
aFiContract.getcSwapCounter(),
balToConsider,
depositTok
);
isQueueWithdrawUnstakingPaused[address(aFiContract)] = true;
}
function pauseQueueWithdrawUnstaking(address afiContract, bool status) external {
require(msg.sender == afiOracle, "AM012");
isQueueWithdrawUnstakingPaused[afiContract] = status;
}
function reInitializeVault(
IAFi aFiContract,
IAFiStorage _aFiStorage,
bytes memory uniData,
address[] memory uTokens,
address[] memory oracles,
uint256[] memory defaultProp,
uint256[] memory currentProp,
IAFi.SwapParameters memory csParams
) external contractUnpaused {
compareAddress(msg.sender, rebalanceController);
require(aFiContract.getUTokens().length == 0, "AM15");
require(uTokens.length <= 10, "AM0009");
checkProductType((aFiContract));
IAFi.UnderlyingData memory underlyingUniData = abi.decode(
uniData,
(IAFi.UnderlyingData)
);
updateAFiData(aFiContract, uTokens, defaultProp, currentProp);
(, rebal, ) = IAFi(aFiContract).getTVLandRebalContractandType();
(address[] memory iToken, ) = IAFi(aFiContract).getInputToken();
(iToken, ) = IAFi(aFiContract).getInputToken();
IPassiveRebal(rebal).initUniStructure(iToken, uniData);
IUniswapOracleV3(afiOracle).updateMidToken(
underlyingUniData._underlyingTokens,
underlyingUniData._underlyingUniPoolToken
);
for (uint256 i; i < uTokens.length; i++) {
IPassiveRebal(rebal).updateOracleData(
underlyingUniData._underlyingTokens[i],
oracles[i]
);
}
aFiContract.reinitializeHappened(true);
doCswap(aFiContract, csParams, _aFiStorage);
}
function convertToStable(
IAFi aFiContract,
address uTokenToRemove,
address depositTok,
uint256 deadline,
uint256 stableamountOut
) internal returns (uint256 _stableBalToConsider) {
require(balance(uTokenToRemove, address(aFiContract)) > 0, "AM06");
address midTok = IUniswapOracleV3(afiOracle).getMidToken(uTokenToRemove);
_stableBalToConsider = balance(depositTok, address(aFiContract));
if(uTokenToRemove != depositTok){
aFiManagerSwap(
uTokenToRemove,
depositTok,
balance(uTokenToRemove, address(aFiContract)),
aFiContract,
deadline,
midTok,
stableamountOut
);
}
}
}
文件 2 的 19:Address.sol
pragma solidity ^0.8.0;
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);
}
}
}
文件 3 的 19:ArrayUtils.sol
pragma solidity ^0.8.0;
library ArrayUtils {
function sPopAddress(address[] storage A, uint index) internal {
uint length = A.length;
if (index >= length) {
revert("Error: index out of bounds");
}
for (uint i = index; i < length - 1; i++) {
A[i] = A[i + 1];
}
A.pop();
}
function sPopUint256(uint[] storage A, uint index) internal {
uint length = A.length;
if (index >= length) {
revert("Error: index out of bounds");
}
for (uint i = index; i < length - 1; i++) {
A[i] = A[i + 1];
}
A.pop();
}
function sumOfMArrays(
uint[] memory A,
uint[] memory B
) internal pure returns (uint[] memory sum) {
sum = new uint[](A.length);
for (uint i = 0; i < A.length; i++) {
sum[i] = A[i] + B[i];
}
return sum;
}
function indexOf(address[] memory A, address a) internal pure returns (uint, bool) {
uint length = A.length;
for (uint i = 0; i < length; i++) {
if (A[i] == a) {
return (i, true);
}
}
return (type(uint).max, false);
}
function contains(address[] memory A, address a) internal pure returns (bool) {
(, bool isIn) = indexOf(A, a);
return isIn;
}
function hasDuplicate(address[] memory A) internal pure returns (bool) {
require(A.length > 0, "A is empty");
for (uint i = 0; i < A.length - 1; i++) {
address current = A[i];
for (uint j = i + 1; j < A.length; j++) {
if (current == A[j]) {
return true;
}
}
}
return false;
}
function remove(
address[] memory A,
address a
) internal pure returns (address[] memory) {
(uint index, bool isIn) = indexOf(A, a);
if (!isIn) {
revert("Address not in array.");
} else {
(address[] memory _A, ) = pop(A, index);
return _A;
}
}
function removeStorage(address[] storage A, address a) internal {
(uint index, bool isIn) = indexOf(A, a);
if (!isIn) {
revert("Address not in array.");
} else {
uint lastIndex = A.length - 1;
if (index != lastIndex) {
A[index] = A[lastIndex];
}
A.pop();
}
}
function pop(
address[] memory A,
uint index
) internal pure returns (address[] memory, address) {
uint length = A.length;
require(index < A.length, "Index must be < A length");
address[] memory newAddresses = new address[](length - 1);
for (uint i = 0; i < index; i++) {
newAddresses[i] = A[i];
}
for (uint j = index + 1; j < length; j++) {
newAddresses[j - 1] = A[j];
}
return (newAddresses, A[index]);
}
function extend(
address[] memory A,
address[] memory B
) internal pure returns (address[] memory) {
uint aLength = A.length;
uint bLength = B.length;
address[] memory newAddresses = new address[](aLength + bLength);
for (uint i = 0; i < aLength; i++) {
newAddresses[i] = A[i];
}
for (uint j = 0; j < bLength; j++) {
newAddresses[aLength + j] = B[j];
}
return newAddresses;
}
function validatePairsWithArray(address[] memory A, uint[] memory B) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function validatePairsWithArray(address[] memory A, bool[] memory B) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function validatePairsWithArray(address[] memory A, string[] memory B) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function validatePairsWithArray(
address[] memory A,
address[] memory B
) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function validatePairsWithArray(address[] memory A, bytes[] memory B) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function _validateLengthAndUniqueness(address[] memory A) internal pure {
require(A.length > 0, "Array length must be > 0");
require(!hasDuplicate(A), "Cannot duplicate addresses");
}
}
文件 4 的 19: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;
}
}
文件 5 的 19:IAFi.sol
pragma solidity ^0.8.0;
import {IERC20Extended as IERC20} from "./IERC20Extended.sol";
import "./IAFiStorage.sol";
import "./IPassiveRebal.sol";
interface PassiveRebal {
function applyRebalForProportions(
address _aFiContract,
address _aFiManager,
address _aFiStorage,
address[] memory _tokens,
uint256 strategy
) external returns (uint[] memory proportions, uint256);
function getPauseStatus() external returns (bool);
function getRebalStrategyNumber(address aFiContract) external returns (uint);
}
interface IAFiOracle {
function uniswapV3Oracle(
address afiContract,
address _tokenIn,
address _tokenOut,
uint _amountIn,
uint _maxTime,
address middleToken,
uint256 minimumReturnAmount
) external returns (bytes memory swapParams);
}
interface IAFiManager {
function updateUTokenProportion(
address aFiContract,
address aFiStorage
) external returns (uint256[] memory);
function inputTokenUSD(
IAFi aFiContract,
uint256 cSwapCounter,
IAFiStorage _aFiStorage
) external view returns (uint256 totalPreDepositInUSD);
function rebalanceController() external view returns(address);
function pauseQueueWithdrawUnstaking(address afiContract,bool status) external;
function isQueueWithdrawUnstakingPaused(address afiContract) external view returns(bool);
}
interface IAFi {
struct UnderlyingData {
address[] _underlyingTokens;
address[] _underlyingUniPoolToken;
}
struct PoolsData {
address[] _depositStableCoin;
address[] _depositCoinOracle;
bytes underlyingData;
address[] _compound;
address[] _aaveToken;
address[] _priceOracles;
uint[] _underlyingTokensProportion;
address[] compoundV3Comet;
uint _typeOfProduct;
}
struct SwapParameters {
address afiContract;
address oToken;
uint256 cSwapFee;
uint256 cSwapCounter;
address[] depositTokens;
uint256[] minimumReturnAmount;
uint256[] iMinimumReturnAmount;
address[] underlyingTokens;
uint256[] newProviders;
uint _deadline;
address[] cometToClaim;
address[] cometRewardTokens;
uint256[] rewardTokenMinReturnAmounts;
}
function initialize(
address newOwner,
string memory _name,
string memory _symbol,
bytes memory data,
bool _isActiveRebalanced,
IAFiStorage _aFiStorage,
address[] memory _commonInputTokens
) external;
function initializeToken(
address[] memory iToken,
address[] memory _teamWallets,
IPassiveRebal _rebalContract,
address _aFiManager
) external;
function getcSwapCounter() external view returns(uint256);
function getUTokens() external view returns (address[] memory uTokensArray);
function swapViaStorageOrManager(
address from,
address to,
uint amount,
uint deadline,
address midTok,
uint minimumReturnAmount
) external returns (uint256);
function isPaused() external view returns (bool, bool);
function getProportions()
external
view
returns (uint[] memory, uint[] memory);
function updatePoolData(bytes memory data) external;
function sendProfitOrFeeToManager(
address wallet,
uint profitShare,
address oToken
) external;
function _supplyCompV3(address tok, uint amount) external;
function _supplyAave(address tok, uint amount) external;
function _supplyCompound(address tok, uint amount) external;
function _withdrawAave(address tok, uint amount) external;
function _withdrawCompoundV3(address tok, uint amount) external;
function _withdrawCompound(address tok, uint amount) external;
function getTVLandRebalContractandType()
external
view
returns (uint256, address, uint256);
function getInputToken() external view returns (address[] memory, address[] memory);
function swap(
address inputToken,
address uTok,
uint256 amountAsPerProportion,
uint _deadline,
address middleToken,
uint256 minimumReturnAmount
) external returns (uint256);
function updateDp(
uint256[] memory _defaultProportion,
uint256[] memory _uTokensProportion
) external;
function updateuTokAndProp(
address[] memory _uTokens
) external;
function underlyingTokensStaking(address[] memory _depositTokens) external returns(uint256 _totalProp);
function depositUserNav(address user) external view returns (uint256);
function setUnstakeData(uint256 totalQueuedShares) external returns (address[] memory, address[] memory, uint256, uint256);
function isOTokenWhitelisted(address oToken) external view returns (bool);
function validateWithdraw(address user, address oToken, uint256 _shares) external;
function updateLockedTokens(
address user,
uint256 amount,
bool lock,
bool queue,
bool unqueue,
uint256 newNAV
) external;
function checkTVL(bool _updateTVL) external;
function updateInputTokens(address[] memory _inputTokens) external;
function reinitializeHappened(bool status) external;
function getPreSwapDepositLimit() external view returns(uint256);
function pauseUnpauseDeposit(bool status) external;
}
文件 6 的 19:IAFiStorage.sol
pragma solidity ^0.8.0;
interface IIEarnManager {
function recommend(
address _token,
address afiBase,
address afiStorage
) external view returns (string memory choice, uint capr, uint aapr, uint dapr);
}
interface IAFiStorage {
struct Investor {
bool isPresent;
uint depositNAV;
uint redemptionNAV;
}
struct RedemptionParams {
address baseContract;
uint r;
address oToken;
uint256 cSwapCounter;
address[] uTokens;
address[] iTokens;
uint256 deadline;
uint256[] minimumReturnAmount;
uint256 _pool;
uint256 tSupply;
uint256 depositNAV;
}
struct TeamWallet {
bool isPresent;
bool isActive;
address walletAddress;
}
struct RebalanceDetails {
uint8 scenario;
address rebalancedUToken;
address[] rebalancedToUTokens;
}
event TeamWalletActive(address indexed walletAddress, bool isActive);
event TeamWalletAdd(address indexed walletAddress, bool isActive);
function getTeamWalletDetails(
address aFiContract,
address _wallet
) external view returns (bool isPresent, bool isActive);
function handleRedemption(RedemptionParams memory params, uint _shares, uint swapMethod) external returns (uint256 redemptionFromContract);
function addTeamWallet(
address aFiContract,
address _wallet,
bool isActive,
bool isPresent
) external;
function getTeamWalletsOfAFi(
address aFiContract
) external view returns (address[] memory _teamWallets);
function setTeamWallets(address aFiContract, address[] memory _teamWallets) external;
function setAFiActive(address aFiContract, bool active) external;
function setActiveRebalancedStatus(address aFiContract, bool status) external;
function isAFiActiveRebalanced(
address aFiContract
) external view returns (bool _isActiveRebalanced);
function getTotalActiveWallets(address aFiContract) external view returns (uint);
function calcPoolValue(
address tok,
address afiContract
) external view returns (uint);
function calculateBalanceOfUnderlying(
address tok,
address afiContract
) external view returns (uint);
function calculatePoolInUsd(address afiContract) external view returns (uint);
function afiSync(
address afiContract,
address tok,
address aaveTok,
address compV3Comet,
address compTok
) external;
function getPriceInUSDC(
address tok
) external view returns (uint256, uint256);
function validateAndGetDecimals(address tok) external view returns (uint256);
function getStakedStatus(
address aFiContract,
address uToken
) external view returns (bool);
function rearrange(address aFiContract,address[] memory underlyingTokens, uint256[] memory newProviders) external;
function swapForOtherProduct(
address afiContract,
uint r,
address oToken,
uint deadline,
uint[] memory minimumReturnAmount,
address[] memory uToken
) external returns (uint256);
function _withdrawAll(address afiContract, address tok) external returns(bool);
function getAFiOracle() external view returns(address);
function calculateRedemptionFromContract(
address afiContract,
address tok,
uint256 r
) external view returns (uint256, bool, uint256, uint256, uint256);
function tvlRead(
address tok,
address afiContract
) external view returns (uint, uint256);
function getPreSwapDepositsTokens(
address aFiContract,
uint256 _cSwapCounter,
address stableToken
) external view returns (uint256);
function setPreDepositedInputToken(uint256 _cSwapCounter, uint256 _amount,address _oToken) external;
function setPreDepositedInputTokenInRebalance(
address aficontract,
uint256 _cSwapCounter,
uint256 _amount,
address _oToken
) external;
function convertInUSDAndTok(
address tok,
uint256 amt,
bool usd
) external view returns (uint256);
function calculateShares(
address afiContract,
uint256 amount,
uint256 prevPool,
uint256 _totalSupply,
address iToken,
uint256 currentDepositNAV,
uint256 prevBalance
) external view returns (uint256 shares, uint256 newDepositNAV);
function deletePreDepositedInputToken(
address aFiContract,
address oToken,
uint256 currentCounter
)external;
function doSwapForThewhiteListRemoval(
address tok,
uint256 _cSwapCounter,
address swapToken,
uint256 deadline,
uint256 minAmountOut
) external;
function isSwapMethodPaused(address afiContract,uint swapMethod) external view returns (bool);
}
文件 7 的 19: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);
}
文件 8 的 19:IERC20Extended.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
interface IERC20Extended is IERC20 {
function decimals() external view returns (uint8);
}
文件 9 的 19:IPassiveRebal.sol
pragma solidity ^0.8.0;
interface IPassiveRebal {
function applyRebalForProportions(
address _aFiContract,
address _aFiManager,
address _aFiStorage,
address[] memory _tokens,
uint256 strategy
) external returns (uint[] memory proportions, uint256 totalProp);
function getPauseStatus() external returns (bool);
function getRebalStrategyNumber(address aFiContract) external returns (uint);
function uniswapV3Oracle(
address afiContract,
address _tokenIn,
address _tokenOut,
uint _amountIn,
uint _maxTime,
address middleToken,
uint256 minimumReturnAmount
) external returns (bytes memory swapParams);
function getPool(address tok, address midTok) external view returns (address);
function upDateInputTokPool(address[] memory iToken, bytes memory uniData) external;
function getPriceOracle(address tok) external view returns (address);
function updateOracleData(
address _uToken,
address _oracleAddress
) external;
function removeToken(
address[] memory _nonOverlappingITokens,
address token
) external pure returns (address[] memory);
function initUniStructure(
address[] memory inputTokens,
bytes memory _poolData
) external;
}
文件 10 的 19:IUNISWAP.sol
pragma solidity ^0.8.0;
interface IUniswapV2Router {
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
文件 11 的 19:IUniswapV3.sol
pragma solidity ^0.8.0;
import "./IUniswapV3Factory.sol";
import "./IAFi.sol";
interface IUniswapOracleV3 {
function PERIOD() external returns (uint256);
function factory() external returns (address);
function getTotalProfit() external view returns (uint256);
function getDaoProfit() external view returns (uint256);
function update(address _tokenIn, address _tokenOut) external;
function quotePrice(IAFi aFiContract,address _tokenIn, address _depositToken, uint256 _amount) external view returns (uint256 price);
function consult(
address _tokenIn,
uint256 _amountIn,
address _tokenOut
) external view returns (uint256 _amountOut);
function estimateAmountOut(
address tokenIn,
uint128 amountIn,
address tokenOut
) external view returns (uint amountOut);
function estimateAmountOutMin(
address tokenIn,
uint128 amountIn,
address tokenOut,
address pool
) external view returns (uint amountOut);
function updateAndConsult(
address _tokenIn,
uint256 _amountIn,
address _tokenOut
) external returns (uint256 _amountOut);
function checkUnderlyingPool(address token) external view returns (bool hasPool);
function getStalePriceDelay(address aFiContract, address uToken) external view returns(uint256);
function getPriceAndDecimals(address aFiContract, address uToken, address feed) external view returns(int256 , uint8 );
function getPriceInUSDC(address tok) external view returns (uint256, uint256);
function getMidToken(address tok) external view returns (address);
function updateMidToken(address[] memory tok, address[] memory midTok) external;
function setRedeemData(address _oToken, uint256 _batchWithdrawCounter, uint256 _totalShares, uint256 _oTokenUnits) external;
function getControllers(address afiContract) external view returns(address, address);
function cumulativeSwap(
IAFi.SwapParameters memory params
) external;
}
文件 12 的 19:IUniswapV3Factory.sol
pragma solidity ^0.8.0;
interface IUniswapV3Factory {
event OwnerChanged(address indexed oldOwner, address indexed newOwner);
event PoolCreated(
address indexed token0,
address indexed token1,
uint24 indexed fee,
int24 tickSpacing,
address pool
);
event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);
function owner() external view returns (address);
function feeAmountTickSpacing(uint24 fee) external view returns (int24);
function getPool(
address tokenA,
address tokenB,
uint24 fee
) external view returns (address pool);
function createPool(
address tokenA,
address tokenB,
uint24 fee
) external returns (address pool);
function setOwner(address _owner) external;
function enableFeeAmount(uint24 fee, int24 tickSpacing) external;
}
interface IUniswapV3Pool {
function observe(
uint32[] calldata secondsAgos
) external
view
returns (
int56[] memory tickCumulatives,
uint160[] memory secondsPerLiquidityCumulativeX128s
);
function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
function fee() external returns(uint24);
}
文件 13 的 19:Ownable.sol
pragma solidity ^0.8.0;
import "./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);
}
}
文件 14 的 19:Ownable2Step.sol
pragma solidity ^0.8.0;
import "./Ownable.sol";
abstract contract Ownable2Step is Ownable {
address internal _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
function acceptOwnership() external {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}
文件 15 的 19:OwnableDelayModule.sol
pragma solidity ^0.8.0;
import {Ownable2Step} from "./Ownable2Step.sol";
contract OwnableDelayModule is Ownable2Step {
address internal delayModule;
constructor() {
delayModule = msg.sender;
}
function isDelayModule() internal view {
require(msg.sender == delayModule, "NA");
}
function setDelayModule(address _delayModule) external {
isDelayModule();
require(_delayModule != address(0), "ODZ");
delayModule = _delayModule;
}
function getDelayModule() external view returns (address) {
return delayModule;
}
function transferOwnership(address newOwner) public override {
isDelayModule();
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
}
文件 16 的 19: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;
}
}
文件 17 的 19:SafeERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./draft-IERC20Permit.sol";
import "./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 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
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");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
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");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 18 的 19:TransferHelper.sol
pragma solidity >=0.6.0;
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
文件 19 的 19:draft-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);
}
{
"compilationTarget": {
"AFiManager.sol": "AFiManager"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 180
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IAFi","name":"_aFiContract","type":"address"},{"indexed":false,"internalType":"address","name":"_fromToken","type":"address"},{"indexed":false,"internalType":"address","name":"_toToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"AFiManagerSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"aFiContract","type":"address"},{"indexed":false,"internalType":"address","name":"_wallet","type":"address"}],"name":"AddTeamWalletInAFi","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","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":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IAFi","name":"_aFiContract","type":"address"},{"indexed":false,"internalType":"uint8","name":"_scenario","type":"uint8"}],"name":"Rebalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"aFiContract","type":"address"},{"indexed":false,"internalType":"address","name":"_aFiStorage","type":"address"},{"indexed":false,"internalType":"address[]","name":"newUnderlyingTokens","type":"address[]"},{"indexed":false,"internalType":"address","name":"stableCoin","type":"address"},{"indexed":false,"internalType":"uint256","name":"managerFee","type":"uint256"}],"name":"RebalanceUnderlyingTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_aFiContract","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"SetActiveRebalStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"aFiContract","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"uTokenProportions","type":"uint256[]"}],"name":"UTokenProportionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_aFiContract","type":"address"},{"indexed":false,"internalType":"address","name":"uToken","type":"address"}],"name":"WithdrawFromPool","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAFiStorage","name":"_aFiStorage","type":"address"},{"internalType":"address","name":"aFiContract","type":"address"},{"internalType":"address","name":"_wallet","type":"address"}],"name":"addTeamWalletInAFi","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAFi","name":"aFiContract","type":"address"},{"internalType":"contract IAFiStorage","name":"_aFiStorage","type":"address"},{"internalType":"address","name":"uTokenToRemove","type":"address"},{"internalType":"uint256[]","name":"defProp","type":"uint256[]"},{"internalType":"address","name":"depositTok","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"stableamountOut","type":"uint256"}],"name":"algoRebalance2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAFi","name":"aFiContract","type":"address"},{"internalType":"contract IAFiStorage","name":"_aFiStorage","type":"address"},{"internalType":"address","name":"uTokenToRemove","type":"address"},{"internalType":"uint256[]","name":"defProp","type":"uint256[]"}],"name":"emergencyRebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getDelayModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPauseStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"aFiContract","type":"address"},{"internalType":"address","name":"_aFiStorage","type":"address"}],"name":"getUTokenProportion","outputs":[{"internalType":"uint256[]","name":"underlyingTokenProportions","type":"uint256[]"},{"internalType":"uint256","name":"totalProp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IAFi","name":"aFiContract","type":"address"},{"internalType":"uint256","name":"cSwapCounter","type":"uint256"},{"internalType":"contract IAFiStorage","name":"_aFiStorage","type":"address"}],"name":"inputTokenUSD","outputs":[{"internalType":"uint256","name":"totalPreDepositInUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isQueueWithdrawUnstakingPaused","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":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"afiContract","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"pauseQueueWithdrawUnstaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IAFi","name":"aFiContract","type":"address"},{"internalType":"contract IAFiStorage","name":"_aFiStorage","type":"address"},{"internalType":"bytes","name":"uniData","type":"bytes"},{"internalType":"address[]","name":"uTokens","type":"address[]"},{"internalType":"address[]","name":"oracles","type":"address[]"},{"internalType":"uint256[]","name":"defaultProp","type":"uint256[]"},{"internalType":"uint256[]","name":"currentProp","type":"uint256[]"},{"components":[{"internalType":"address","name":"afiContract","type":"address"},{"internalType":"address","name":"oToken","type":"address"},{"internalType":"uint256","name":"cSwapFee","type":"uint256"},{"internalType":"uint256","name":"cSwapCounter","type":"uint256"},{"internalType":"address[]","name":"depositTokens","type":"address[]"},{"internalType":"uint256[]","name":"minimumReturnAmount","type":"uint256[]"},{"internalType":"uint256[]","name":"iMinimumReturnAmount","type":"uint256[]"},{"internalType":"address[]","name":"underlyingTokens","type":"address[]"},{"internalType":"uint256[]","name":"newProviders","type":"uint256[]"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"address[]","name":"cometToClaim","type":"address[]"},{"internalType":"address[]","name":"cometRewardTokens","type":"address[]"},{"internalType":"uint256[]","name":"rewardTokenMinReturnAmounts","type":"uint256[]"}],"internalType":"struct IAFi.SwapParameters","name":"csParams","type":"tuple"}],"name":"reInitializeVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebalFeeUpperLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"contract IAFi","name":"aFiContract","type":"address"},{"internalType":"contract IAFiStorage","name":"_aFiStorage","type":"address"},{"internalType":"contract IERC20Extended","name":"depositToken","type":"address"},{"internalType":"address","name":"newUToken","type":"address"},{"internalType":"address","name":"uTokenToRemove","type":"address"},{"internalType":"uint256","name":"scenario","type":"uint256"},{"internalType":"address[]","name":"uTokensAfterS1","type":"address[]"},{"internalType":"uint256[]","name":"uTokenProportions","type":"uint256[]"},{"internalType":"uint256[]","name":"defaultProportion","type":"uint256[]"},{"internalType":"uint256","name":"uTokenToRemoveIndex","type":"uint256"}],"internalType":"struct AFiManager.RebalanceData","name":"rebalData","type":"tuple"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256[]","name":"minimumReturnAmount","type":"uint256[]"},{"internalType":"uint256","name":"stableAmountOut","type":"uint256"},{"internalType":"uint256","name":"_rebalFeeToDeduct","type":"uint256"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebalanceController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IAFi","name":"aFiContract","type":"address"},{"internalType":"contract IAFiStorage","name":"_aFiStorage","type":"address"},{"internalType":"bytes","name":"underlyingData","type":"bytes"},{"internalType":"address[]","name":"newUnderlyingOracle","type":"address[]"},{"internalType":"address[]","name":"prevUnderlying","type":"address[]"},{"internalType":"address","name":"stableCoin","type":"address"},{"internalType":"uint256","name":"managerFee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256[]","name":"minimumReturnAmount","type":"uint256[]"},{"internalType":"uint256[]","name":"minimumUnderlyingAmount","type":"uint256[]"}],"internalType":"struct AFiManager.AlgoRebalanceData","name":"rebalanceData","type":"tuple"},{"components":[{"internalType":"address","name":"afiContract","type":"address"},{"internalType":"address","name":"oToken","type":"address"},{"internalType":"uint256","name":"cSwapFee","type":"uint256"},{"internalType":"uint256","name":"cSwapCounter","type":"uint256"},{"internalType":"address[]","name":"depositTokens","type":"address[]"},{"internalType":"uint256[]","name":"minimumReturnAmount","type":"uint256[]"},{"internalType":"uint256[]","name":"iMinimumReturnAmount","type":"uint256[]"},{"internalType":"address[]","name":"underlyingTokens","type":"address[]"},{"internalType":"uint256[]","name":"newProviders","type":"uint256[]"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"address[]","name":"cometToClaim","type":"address[]"},{"internalType":"address[]","name":"cometRewardTokens","type":"address[]"},{"internalType":"uint256[]","name":"rewardTokenMinReturnAmounts","type":"uint256[]"}],"internalType":"struct IAFi.SwapParameters","name":"csParams","type":"tuple"}],"name":"rebalanceUnderlyingTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebalfee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAFiStorage","name":"_aFiStorage","type":"address"},{"internalType":"address","name":"aFiContract","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setActiveRebalStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delayModule","type":"address"}],"name":"setDelayModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rebalfee","type":"uint256"}],"name":"setRebalFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rebalFeeUpperLimit","type":"uint256"}],"name":"setRebalFeeUpperLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rebalanceController","type":"address"}],"name":"setRebalanceController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_afiOracle","type":"address"}],"name":"setafiOracleContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_preDepositsStablesInUSD","type":"uint256"}],"name":"updateStableUnitsInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAFiStorage","name":"_afiStorage","type":"address"},{"internalType":"contract IAFi","name":"aFiContract","type":"address"},{"internalType":"address","name":"underlyinToken","type":"address"}],"name":"withdrawFromPool","outputs":[],"stateMutability":"nonpayable","type":"function"}]