编译器
0.8.19+commit.7dd6d404
文件 1 的 38: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 的 38:BokkyPooBahsDateTimeLibrary.sol
pragma solidity ^0.8.19;
library BokkyPooBahsDateTimeLibrary {
uint constant SECONDS_PER_DAY = 24 * 60 * 60;
int constant OFFSET19700101 = 2440588;
function _daysToDate(
uint _days
) internal pure returns (uint year, uint month, uint day) {
int __days = int(_days);
int L = __days + 68569 + OFFSET19700101;
int N = (4 * L) / 146097;
L = L - (146097 * N + 3) / 4;
int _year = (4000 * (L + 1)) / 1461001;
L = L - (1461 * _year) / 4 + 31;
int _month = (80 * L) / 2447;
int _day = L - (2447 * _month) / 80;
L = _month / 11;
_month = _month + 2 - 12 * L;
_year = 100 * (N - 49) + _year + L;
year = uint(_year);
month = uint(_month);
day = uint(_day);
}
function timestampToDate(
uint timestamp
) internal pure returns (uint year, uint month, uint day) {
(year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
}
}
文件 3 的 38: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;
}
}
文件 4 的 38:Counters.sol
pragma solidity ^0.8.0;
library Counters {
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
文件 5 的 38:DecentralizedIndex.sol
pragma solidity ^0.8.19;
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@uniswap/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol';
import './interfaces/ICamelotRouter.sol';
import './interfaces/IDecentralizedIndex.sol';
import './interfaces/IDexAdapter.sol';
import './interfaces/IFlashLoanRecipient.sol';
import './interfaces/IProtocolFeeRouter.sol';
import './interfaces/IRewardsWhitelister.sol';
import './interfaces/ITokenRewards.sol';
import './interfaces/IUniswapV2Router02.sol';
import './StakingPoolToken.sol';
abstract contract DecentralizedIndex is
IDecentralizedIndex,
ERC20,
ERC20Permit
{
using SafeERC20 for IERC20;
uint16 constant DEN = 10000;
uint8 constant SWAP_DELAY = 20;
address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
IProtocolFeeRouter constant PROTOCOL_FEE_ROUTER =
IProtocolFeeRouter(0x7d544DD34ABbE24C8832db27820Ff53C151e949b);
IRewardsWhitelister constant REWARDS_WHITELIST =
IRewardsWhitelister(0xEc0Eb48d2D638f241c1a7F109e38ef2901E9450F);
IV3TwapUtilities constant V3_TWAP_UTILS =
IV3TwapUtilities(0x024ff47D552cB222b265D68C7aeB26E586D5229D);
uint256 public immutable override FLASH_FEE_AMOUNT_DAI;
address public immutable override PAIRED_LP_TOKEN;
IDexAdapter public immutable DEX_HANDLER;
address immutable V2_ROUTER;
address immutable V3_ROUTER;
address immutable WETH;
address V2_POOL;
IndexType public immutable override indexType;
uint256 public immutable override created;
address public immutable override lpRewardsToken;
address public override lpStakingPool;
Config public config;
Fees public fees;
IndexAssetInfo[] public indexTokens;
mapping(address => bool) _isTokenInIndex;
mapping(address => uint8) _fundTokenIdx;
mapping(address => bool) _blacklist;
uint64 _partnerFirstWrapped;
uint64 _lastSwap;
uint8 _swapping;
uint8 _swapAndFeeOn = 1;
uint8 _unlocked = 1;
bool _initialized;
event FlashLoan(
address indexed executor,
address indexed recipient,
address token,
uint256 amount
);
modifier lock() {
require(_unlocked == 1, 'L');
_unlocked = 0;
_;
_unlocked = 1;
}
modifier onlyPartner() {
require(_msgSender() == config.partner, 'P');
_;
}
modifier noSwapOrFee() {
_swapAndFeeOn = 0;
_;
_swapAndFeeOn = 1;
}
constructor(
string memory _name,
string memory _symbol,
IndexType _idxType,
Config memory _config,
Fees memory _fees,
address _pairedLpToken,
address _lpRewardsToken,
address _dexHandler,
bool _stakeRestriction
) ERC20(_name, _symbol) ERC20Permit(_name) {
require(_fees.buy <= (uint256(DEN) * 20) / 100);
require(_fees.sell <= (uint256(DEN) * 20) / 100);
require(_fees.burn <= (uint256(DEN) * 70) / 100);
require(_fees.bond <= (uint256(DEN) * 99) / 100);
require(_fees.debond <= (uint256(DEN) * 99) / 100);
require(_fees.partner <= (uint256(DEN) * 5) / 100);
indexType = _idxType;
created = block.timestamp;
fees = _fees;
config = _config;
lpRewardsToken = _lpRewardsToken;
DEX_HANDLER = IDexAdapter(_dexHandler);
address _v2Router = DEX_HANDLER.V2_ROUTER();
V2_ROUTER = _v2Router;
V3_ROUTER = DEX_HANDLER.V3_ROUTER();
address _finalPairedLpToken = _pairedLpToken == address(0)
? DAI
: _pairedLpToken;
PAIRED_LP_TOKEN = _finalPairedLpToken;
FLASH_FEE_AMOUNT_DAI = 10 * 10 ** IERC20Metadata(DAI).decimals();
lpStakingPool = address(
new StakingPoolToken(
string.concat('Staked ', _name),
string.concat('s', _symbol),
_finalPairedLpToken,
lpRewardsToken,
_stakeRestriction ? _msgSender() : address(0),
PROTOCOL_FEE_ROUTER,
REWARDS_WHITELIST,
DEX_HANDLER,
V3_TWAP_UTILS
)
);
if (!DEX_HANDLER.ASYNC_INITIALIZE()) {
_initialize();
}
WETH = IUniswapV2Router02(_v2Router).WETH();
emit Create(address(this), _msgSender());
}
function initialize() external {
_initialize();
}
function _initialize() internal {
require(!_initialized, 'O');
_initialized = true;
address _v2Pool = DEX_HANDLER.getV2Pool(address(this), PAIRED_LP_TOKEN);
if (_v2Pool == address(0)) {
_v2Pool = DEX_HANDLER.createV2Pool(address(this), PAIRED_LP_TOKEN);
}
StakingPoolToken(lpStakingPool).setStakingToken(_v2Pool);
StakingPoolToken(lpStakingPool).renounceOwnership();
V2_POOL = _v2Pool;
emit Initialize(_msgSender(), _v2Pool);
}
function _transfer(
address _from,
address _to,
uint256 _amount
) internal virtual override {
require(!_blacklist[_to], 'BK');
bool _buy = _from == V2_POOL && _to != V2_ROUTER;
bool _sell = _to == V2_POOL;
uint256 _fee;
if (_swapping == 0 && _swapAndFeeOn == 1) {
if (_from != V2_POOL) {
_processPreSwapFeesAndSwap();
}
if (_buy && fees.buy > 0) {
_fee = (_amount * fees.buy) / DEN;
super._transfer(_from, address(this), _fee);
}
if (_sell && fees.sell > 0) {
_fee = (_amount * fees.sell) / DEN;
super._transfer(_from, address(this), _fee);
}
if (!_buy && !_sell && config.hasTransferTax) {
_fee = _amount / 10000;
_fee = _fee == 0 && _amount > 0 ? 1 : _fee;
super._transfer(_from, address(this), _fee);
}
}
_processBurnFee(_fee);
super._transfer(_from, _to, _amount - _fee);
}
function _processPreSwapFeesAndSwap() internal {
bool _passesSwapDelay = block.timestamp > _lastSwap + SWAP_DELAY;
if (!_passesSwapDelay) {
return;
}
uint256 _bal = balanceOf(address(this));
if (_bal == 0) {
return;
}
uint256 _lpBal = balanceOf(V2_POOL);
uint256 _min = block.chainid == 1 ? _lpBal / 1000 : _lpBal / 4000;
uint256 _max = _lpBal / 100;
if (_bal >= _min && _lpBal > 0) {
_swapping = 1;
_lastSwap = uint64(block.timestamp);
uint256 _totalAmt = _bal > _max ? _max : _bal;
uint256 _partnerAmt;
if (
fees.partner > 0 &&
config.partner != address(0) &&
!_blacklist[config.partner]
) {
_partnerAmt = (_totalAmt * fees.partner) / DEN;
super._transfer(address(this), config.partner, _partnerAmt);
}
_feeSwap(_totalAmt - _partnerAmt);
_swapping = 0;
}
}
function _processBurnFee(uint256 _amtToProcess) internal {
if (_amtToProcess == 0 || fees.burn == 0) {
return;
}
_burn(address(this), (_amtToProcess * fees.burn) / DEN);
}
function _feeSwap(uint256 _amount) internal {
_approve(address(this), address(DEX_HANDLER), _amount);
address _rewards = StakingPoolToken(lpStakingPool).poolRewards();
uint256 _pairedLpBalBefore = IERC20(PAIRED_LP_TOKEN).balanceOf(_rewards);
DEX_HANDLER.swapV2Single(
address(this),
PAIRED_LP_TOKEN,
_amount,
0,
_rewards
);
if (PAIRED_LP_TOKEN == lpRewardsToken) {
uint256 _newPairedLpTkns = IERC20(PAIRED_LP_TOKEN).balanceOf(_rewards) -
_pairedLpBalBefore;
if (_newPairedLpTkns > 0) {
ITokenRewards(_rewards).depositRewardsNoTransfer(
PAIRED_LP_TOKEN,
_newPairedLpTkns
);
}
} else if (IERC20(PAIRED_LP_TOKEN).balanceOf(_rewards) > 0) {
ITokenRewards(_rewards).depositFromPairedLpToken(0, 0);
}
}
function _transferFromAndValidate(
IERC20 _token,
address _sender,
uint256 _amount
) internal {
uint256 _balanceBefore = _token.balanceOf(address(this));
_token.safeTransferFrom(_sender, address(this), _amount);
require(_token.balanceOf(address(this)) >= _balanceBefore + _amount, 'TV');
}
function _bond() internal {
require(_initialized, 'I');
if (_partnerFirstWrapped == 0 && _msgSender() == config.partner) {
_partnerFirstWrapped = uint64(block.timestamp);
}
}
function _canWrapFeeFree(address _wrapper) internal view returns (bool) {
return
_isFirstIn() ||
(_wrapper == config.partner &&
_partnerFirstWrapped == 0 &&
block.timestamp <= created + 7 days);
}
function _isFirstIn() internal view returns (bool) {
return totalSupply() == 0;
}
function _isLastOut(uint256 _debondAmount) internal view returns (bool) {
return _debondAmount >= (totalSupply() * 98) / 100;
}
function processPreSwapFeesAndSwap() external override {
require(_msgSender() == StakingPoolToken(lpStakingPool).poolRewards(), 'R');
_processPreSwapFeesAndSwap();
}
function partner() external view override returns (address) {
return config.partner;
}
function BOND_FEE() external view override returns (uint16) {
return fees.bond;
}
function DEBOND_FEE() external view override returns (uint16) {
return fees.debond;
}
function isAsset(address _token) public view override returns (bool) {
return _isTokenInIndex[_token];
}
function getAllAssets()
external
view
override
returns (IndexAssetInfo[] memory)
{
return indexTokens;
}
function burn(uint256 _amount) external lock {
_burn(_msgSender(), _amount);
}
function manualProcessFee(uint256 _slip) external {
_transfer(address(this), address(this), 0);
address _rewards = StakingPoolToken(lpStakingPool).poolRewards();
ITokenRewards(_rewards).depositFromPairedLpToken(
0,
_slip > 50 ? 50 : _slip
);
}
function addLiquidityV2(
uint256 _idxLPTokens,
uint256 _pairedLPTokens,
uint256 _slippage,
uint256 _deadline
) external override lock noSwapOrFee returns (uint256) {
uint256 _idxTokensBefore = balanceOf(address(this));
uint256 _pairedBefore = IERC20(PAIRED_LP_TOKEN).balanceOf(address(this));
super._transfer(_msgSender(), address(this), _idxLPTokens);
_approve(address(this), V2_ROUTER, _idxLPTokens);
IERC20(PAIRED_LP_TOKEN).safeTransferFrom(
_msgSender(),
address(this),
_pairedLPTokens
);
IERC20(PAIRED_LP_TOKEN).safeIncreaseAllowance(V2_ROUTER, _pairedLPTokens);
(, , uint256 _liquidity) = IUniswapV2Router02(V2_ROUTER).addLiquidity(
address(this),
PAIRED_LP_TOKEN,
_idxLPTokens,
_pairedLPTokens,
(_idxLPTokens * (1000 - _slippage)) / 1000,
(_pairedLPTokens * (1000 - _slippage)) / 1000,
_msgSender(),
_deadline
);
IERC20(PAIRED_LP_TOKEN).safeApprove(V2_ROUTER, 0);
if (balanceOf(address(this)) > _idxTokensBefore) {
super._transfer(
address(this),
_msgSender(),
balanceOf(address(this)) - _idxTokensBefore
);
}
if (IERC20(PAIRED_LP_TOKEN).balanceOf(address(this)) > _pairedBefore) {
IERC20(PAIRED_LP_TOKEN).safeTransfer(
_msgSender(),
IERC20(PAIRED_LP_TOKEN).balanceOf(address(this)) - _pairedBefore
);
}
emit AddLiquidity(_msgSender(), _idxLPTokens, _pairedLPTokens);
return _liquidity;
}
function removeLiquidityV2(
uint256 _lpTokens,
uint256 _minIdxTokens,
uint256 _minPairedLpToken,
uint256 _deadline
) external override lock noSwapOrFee {
_lpTokens = _lpTokens == 0
? IERC20(V2_POOL).balanceOf(_msgSender())
: _lpTokens;
require(_lpTokens > 0, 'LT');
IERC20(V2_POOL).safeTransferFrom(_msgSender(), address(this), _lpTokens);
IERC20(V2_POOL).safeIncreaseAllowance(V2_ROUTER, _lpTokens);
IUniswapV2Router02(V2_ROUTER).removeLiquidity(
address(this),
PAIRED_LP_TOKEN,
_lpTokens,
_minIdxTokens,
_minPairedLpToken,
_msgSender(),
_deadline
);
emit RemoveLiquidity(_msgSender(), _lpTokens);
}
function flash(
address _recipient,
address _token,
uint256 _amount,
bytes calldata _data
) external override lock {
require(_isTokenInIndex[_token], 'X');
address _rewards = StakingPoolToken(lpStakingPool).poolRewards();
address _feeRecipient = lpRewardsToken == DAI
? address(this)
: PAIRED_LP_TOKEN == DAI
? _rewards
: Ownable(address(V3_TWAP_UTILS)).owner();
IERC20(DAI).safeTransferFrom(
_msgSender(),
_feeRecipient,
FLASH_FEE_AMOUNT_DAI
);
if (lpRewardsToken == DAI) {
IERC20(DAI).safeIncreaseAllowance(_rewards, FLASH_FEE_AMOUNT_DAI);
ITokenRewards(_rewards).depositRewards(DAI, FLASH_FEE_AMOUNT_DAI);
}
uint256 _balance = IERC20(_token).balanceOf(address(this));
IERC20(_token).safeTransfer(_recipient, _amount);
IFlashLoanRecipient(_recipient).callback(_data);
require(IERC20(_token).balanceOf(address(this)) >= _balance, 'FA');
emit FlashLoan(_msgSender(), _recipient, _token, _amount);
}
function setPartner(address _partner) external onlyPartner {
config.partner = _partner;
emit SetPartner(_msgSender(), _partner);
}
function setPartnerFee(uint16 _fee) external onlyPartner {
require(_fee < fees.partner, 'L');
fees.partner = _fee;
emit SetPartnerFee(_msgSender(), _fee);
}
function rescueERC20(address _token) external lock {
require(!isAsset(_token) && _token != address(this), 'U');
IERC20(_token).safeTransfer(
Ownable(address(V3_TWAP_UTILS)).owner(),
IERC20(_token).balanceOf(address(this))
);
}
function rescueETH() external lock {
require(address(this).balance > 0, 'E');
(bool _sent, ) = Ownable(address(V3_TWAP_UTILS)).owner().call{
value: address(this).balance
}('');
require(_sent, 'S');
}
}
文件 6 的 38:ECDSA.sol
pragma solidity ^0.8.0;
import "../Strings.sol";
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}
文件 7 的 38:EIP712.sol
pragma solidity ^0.8.8;
import "./ECDSA.sol";
import "../ShortStrings.sol";
import "../../interfaces/IERC5267.sol";
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
function eip712Domain()
public
view
virtual
override
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f",
_name.toStringWithFallback(_nameFallback),
_version.toStringWithFallback(_versionFallback),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
}
文件 8 的 38:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
文件 9 的 38:ERC20Permit.sol
pragma solidity ^0.8.0;
import "./IERC20Permit.sol";
import "../ERC20.sol";
import "../../../utils/cryptography/ECDSA.sol";
import "../../../utils/cryptography/EIP712.sol";
import "../../../utils/Counters.sol";
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
using Counters for Counters.Counter;
mapping(address => Counters.Counter) private _nonces;
bytes32 private constant _PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;
constructor(string memory name) EIP712(name, "1") {}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
require(signer == owner, "ERC20Permit: invalid signature");
_approve(owner, spender, value);
}
function nonces(address owner) public view virtual override returns (uint256) {
return _nonces[owner].current();
}
function DOMAIN_SEPARATOR() external view override returns (bytes32) {
return _domainSeparatorV4();
}
function _useNonce(address owner) internal virtual returns (uint256 current) {
Counters.Counter storage nonce = _nonces[owner];
current = nonce.current();
nonce.increment();
}
}
文件 10 的 38:FixedPoint96.sol
pragma solidity >=0.4.0;
library FixedPoint96 {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant Q96 = 0x1000000000000000000000000;
}
文件 11 的 38:ICamelotRouter.sol
pragma solidity >=0.6.2;
interface ICamelotRouter {
function factory() external view returns (address);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
address referrer,
uint deadline
) external;
}
文件 12 的 38:IDecentralizedIndex.sol
pragma solidity ^0.8.19;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
interface IDecentralizedIndex is IERC20 {
enum IndexType {
WEIGHTED,
UNWEIGHTED
}
struct Config {
address partner;
bool hasTransferTax;
bool blacklistTKNpTKNPoolV2;
}
struct Fees {
uint16 burn;
uint16 bond;
uint16 debond;
uint16 buy;
uint16 sell;
uint16 partner;
}
struct IndexAssetInfo {
address token;
uint256 weighting;
uint256 basePriceUSDX96;
address c1;
uint256 q1;
}
event Create(address indexed newIdx, address indexed wallet);
event Initialize(address indexed wallet, address v2Pool);
event Bond(
address indexed wallet,
address indexed token,
uint256 amountTokensBonded,
uint256 amountTokensMinted
);
event Debond(address indexed wallet, uint256 amountDebonded);
event AddLiquidity(
address indexed wallet,
uint256 amountTokens,
uint256 amountDAI
);
event RemoveLiquidity(address indexed wallet, uint256 amountLiquidity);
event SetPartner(address indexed wallet, address newPartner);
event SetPartnerFee(address indexed wallet, uint16 newFee);
function BOND_FEE() external view returns (uint16);
function DEBOND_FEE() external view returns (uint16);
function FLASH_FEE_AMOUNT_DAI() external view returns (uint256);
function PAIRED_LP_TOKEN() external view returns (address);
function indexType() external view returns (IndexType);
function created() external view returns (uint256);
function lpStakingPool() external view returns (address);
function lpRewardsToken() external view returns (address);
function partner() external view returns (address);
function getIdxPriceUSDX96() external view returns (uint256, uint256);
function isAsset(address token) external view returns (bool);
function getAllAssets() external view returns (IndexAssetInfo[] memory);
function getInitialAmount(
address sToken,
uint256 sAmount,
address tToken
) external view returns (uint256);
function getTokenPriceUSDX96(address token) external view returns (uint256);
function processPreSwapFeesAndSwap() external;
function bond(address token, uint256 amount, uint256 amountMintMin) external;
function debond(
uint256 amount,
address[] memory token,
uint8[] memory percentage
) external;
function addLiquidityV2(
uint256 idxTokens,
uint256 daiTokens,
uint256 slippage,
uint256 deadline
) external returns (uint256);
function removeLiquidityV2(
uint256 lpTokens,
uint256 minTokens,
uint256 minDAI,
uint256 deadline
) external;
function flash(
address recipient,
address token,
uint256 amount,
bytes calldata data
) external;
}
文件 13 的 38:IDexAdapter.sol
pragma solidity ^0.8.19;
interface IDexAdapter {
function ASYNC_INITIALIZE() external view returns (bool);
function V2_ROUTER() external view returns (address);
function V3_ROUTER() external view returns (address);
function getV3Pool(
address _token0,
address _token1,
uint24 _poolFee
) external view returns (address _pool);
function getV2Pool(
address _token0,
address _token1
) external view returns (address _pool);
function createV2Pool(
address _token0,
address _token1
) external returns (address _pool);
function swapV2Single(
address _tokenIn,
address _tokenOut,
uint256 _amountIn,
uint256 _amountOutMin,
address _recipient
) external returns (uint256 _amountOut);
function swapV3Single(
address _tokenIn,
address _tokenOut,
uint24 _fee,
uint256 _amountIn,
uint256 _amountOutMin,
address _recipient
) external returns (uint256 _amountOut);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external;
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external;
}
文件 14 的 38: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);
}
文件 15 的 38:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 16 的 38: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);
}
文件 17 的 38:IERC5267.sol
pragma solidity ^0.8.0;
interface IERC5267 {
event EIP712DomainChanged();
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}
文件 18 的 38:IFlashLoanRecipient.sol
pragma solidity ^0.8.19;
interface IFlashLoanRecipient {
function callback(bytes calldata data) external;
}
文件 19 的 38:IPEAS.sol
pragma solidity ^0.8.19;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
interface IPEAS is IERC20 {
event Burn(address indexed user, uint256 amount);
function burn(uint256 amount) external;
}
文件 20 的 38:IPeripheryImmutableState.sol
pragma solidity >=0.5.0;
interface IPeripheryImmutableState {
function factory() external view returns (address);
function WETH9() external view returns (address);
}
文件 21 的 38:IProtocolFeeRouter.sol
pragma solidity ^0.8.19;
import './IProtocolFees.sol';
interface IProtocolFeeRouter {
function protocolFees() external view returns (IProtocolFees);
}
文件 22 的 38:IProtocolFees.sol
pragma solidity ^0.8.19;
interface IProtocolFees {
event SetYieldAdmin(uint256 newFee);
event SetYieldBurn(uint256 newFee);
function DEN() external view returns (uint256);
function yieldAdmin() external view returns (uint256);
function yieldBurn() external view returns (uint256);
}
文件 23 的 38:IRewardsWhitelister.sol
pragma solidity ^0.8.19;
interface IRewardsWhitelister {
function whitelist(address token) external view returns (bool);
function getFullWhitelist() external view returns (address[] memory);
}
文件 24 的 38:IStakingPoolToken.sol
pragma solidity ^0.8.19;
interface IStakingPoolToken {
event Stake(address indexed executor, address indexed user, uint256 amount);
event Unstake(address indexed user, uint256 amount);
function indexFund() external view returns (address);
function stakingToken() external view returns (address);
function poolRewards() external view returns (address);
function stakeUserRestriction() external view returns (address);
function stake(address user, uint256 amount) external;
function unstake(uint256 amount) external;
}
文件 25 的 38:ITokenRewards.sol
pragma solidity ^0.8.19;
interface ITokenRewards {
event AddShares(address indexed wallet, uint256 amount);
event RemoveShares(address indexed wallet, uint256 amount);
event ClaimReward(address indexed wallet);
event DistributeReward(
address indexed wallet,
address indexed token,
uint256 amount
);
event DepositRewards(
address indexed wallet,
address indexed token,
uint256 amount
);
function totalShares() external view returns (uint256);
function totalStakers() external view returns (uint256);
function rewardsToken() external view returns (address);
function trackingToken() external view returns (address);
function depositFromPairedLpToken(
uint256 amount,
uint256 slippageOverride
) external;
function depositRewards(address token, uint256 amount) external;
function depositRewardsNoTransfer(address token, uint256 amount) external;
function claimReward(address wallet) external;
function setShares(
address wallet,
uint256 amount,
bool sharesRemoving
) external;
}
文件 26 的 38:IUniswapV2Pair.sol
pragma solidity ^0.8.19;
interface IUniswapV2Pair {
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}
文件 27 的 38:IUniswapV2Router02.sol
pragma solidity ^0.8.19;
interface IUniswapV2Router02 {
function factory() external view returns (address);
function WETH() external view 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 removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
文件 28 的 38:IV3TwapUtilities.sol
pragma solidity ^0.8.19;
interface IV3TwapUtilities {
function getV3Pool(
address v3Factory,
address token0,
address token1
) external view returns (address);
function getV3Pool(
address v3Factory,
address token0,
address token1,
uint24 poolFee
) external view returns (address);
function getV3Pool(
address v3Factory,
address token0,
address token1,
int24 tickSpacing
) external view returns (address);
function getPoolPriceUSDX96(
address pricePool,
address nativeStablePool,
address WETH9
) external view returns (uint256);
function sqrtPriceX96FromPoolAndInterval(
address pool
) external view returns (uint160);
function priceX96FromSqrtPriceX96(
uint160 sqrtPriceX96
) external pure returns (uint256);
}
文件 29 的 38: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);
}
}
}
文件 30 的 38: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);
}
}
文件 31 的 38: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));
}
}
文件 32 的 38:ShortStrings.sol
pragma solidity ^0.8.8;
import "./StorageSlot.sol";
type ShortString is bytes32;
library ShortStrings {
bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
string memory str = new string(32);
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(_FALLBACK_SENTINEL);
}
}
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}
文件 33 的 38:SignedMath.sol
pragma solidity ^0.8.0;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
文件 34 的 38:StakingPoolToken.sol
pragma solidity ^0.8.19;
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import './interfaces/IDexAdapter.sol';
import './interfaces/IRewardsWhitelister.sol';
import './interfaces/IProtocolFeeRouter.sol';
import './interfaces/IStakingPoolToken.sol';
import './TokenRewards.sol';
contract StakingPoolToken is IStakingPoolToken, ERC20, Ownable {
using SafeERC20 for IERC20;
address public immutable override indexFund;
address public immutable override poolRewards;
address public override stakeUserRestriction;
address public override stakingToken;
modifier onlyRestricted() {
require(_msgSender() == stakeUserRestriction, 'R');
_;
}
constructor(
string memory _name,
string memory _symbol,
address _pairedLpToken,
address _rewardsToken,
address _stakeUserRestriction,
IProtocolFeeRouter _feeRouter,
IRewardsWhitelister _rewardsWhitelist,
IDexAdapter _dexHandler,
IV3TwapUtilities _v3TwapUtilities
) ERC20(_name, _symbol) {
indexFund = _msgSender();
stakeUserRestriction = _stakeUserRestriction;
poolRewards = address(
new TokenRewards(
_feeRouter,
_rewardsWhitelist,
_dexHandler,
_v3TwapUtilities,
indexFund,
_pairedLpToken,
address(this),
_rewardsToken
)
);
}
function stake(address _user, uint256 _amount) external override {
require(stakingToken != address(0), 'I');
if (stakeUserRestriction != address(0)) {
require(_user == stakeUserRestriction, 'U');
}
_mint(_user, _amount);
IERC20(stakingToken).safeTransferFrom(_msgSender(), address(this), _amount);
emit Stake(_msgSender(), _user, _amount);
}
function unstake(uint256 _amount) external override {
_burn(_msgSender(), _amount);
IERC20(stakingToken).safeTransfer(_msgSender(), _amount);
emit Unstake(_msgSender(), _amount);
}
function setStakingToken(address _stakingToken) external onlyOwner {
require(stakingToken == address(0), 'S');
stakingToken = _stakingToken;
}
function removeStakeUserRestriction() external onlyRestricted {
stakeUserRestriction = address(0);
}
function setStakeUserRestriction(address _user) external onlyRestricted {
stakeUserRestriction = _user;
}
function _afterTokenTransfer(
address _from,
address _to,
uint256 _amount
) internal override {
if (_from != address(0) && _from != address(0xdead)) {
TokenRewards(poolRewards).setShares(_from, _amount, true);
}
if (_to != address(0) && _to != address(0xdead)) {
TokenRewards(poolRewards).setShares(_to, _amount, false);
}
}
}
文件 35 的 38:StorageSlot.sol
pragma solidity ^0.8.0;
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly {
r.slot := slot
}
}
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly {
r.slot := store.slot
}
}
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly {
r.slot := slot
}
}
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly {
r.slot := store.slot
}
}
}
文件 36 的 38:Strings.sol
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
文件 37 的 38:TokenRewards.sol
pragma solidity ^0.8.19;
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/utils/Context.sol';
import '@uniswap/v3-core/contracts/libraries/FixedPoint96.sol';
import './interfaces/IDecentralizedIndex.sol';
import './interfaces/IDexAdapter.sol';
import './interfaces/IPEAS.sol';
import './interfaces/IRewardsWhitelister.sol';
import './interfaces/IProtocolFees.sol';
import './interfaces/IProtocolFeeRouter.sol';
import './interfaces/ITokenRewards.sol';
import './interfaces/IV3TwapUtilities.sol';
import './libraries/BokkyPooBahsDateTimeLibrary.sol';
contract TokenRewards is ITokenRewards, Context {
using SafeERC20 for IERC20;
uint256 constant PRECISION = 10 ** 36;
uint24 constant REWARDS_POOL_FEE = 10000;
address immutable INDEX_FUND;
address immutable PAIRED_LP_TOKEN;
IProtocolFeeRouter immutable PROTOCOL_FEE_ROUTER;
IRewardsWhitelister immutable REWARDS_WHITELISTER;
IDexAdapter immutable DEX_HANDLER;
IV3TwapUtilities immutable V3_TWAP_UTILS;
struct Reward {
uint256 excluded;
uint256 realized;
}
address public immutable override trackingToken;
address public immutable override rewardsToken;
uint256 public override totalShares;
uint256 public override totalStakers;
mapping(address => uint256) public shares;
mapping(address => mapping(address => Reward)) public rewards;
uint256 _rewardsSwapSlippage = 20;
mapping(address => uint256) _rewardsPerShare;
mapping(address => uint256) public rewardsDistributed;
mapping(address => uint256) public rewardsDeposited;
mapping(address => mapping(uint256 => uint256)) public rewardsDepMonthly;
address[] _allRewardsTokens;
mapping(address => bool) _depositedRewardsToken;
constructor(
IProtocolFeeRouter _feeRouter,
IRewardsWhitelister _rewardsWhitelist,
IDexAdapter _dexHandler,
IV3TwapUtilities _v3TwapUtilities,
address _indexFund,
address _pairedLpToken,
address _trackingToken,
address _rewardsToken
) {
PROTOCOL_FEE_ROUTER = _feeRouter;
REWARDS_WHITELISTER = _rewardsWhitelist;
DEX_HANDLER = _dexHandler;
V3_TWAP_UTILS = _v3TwapUtilities;
INDEX_FUND = _indexFund;
PAIRED_LP_TOKEN = _pairedLpToken;
trackingToken = _trackingToken;
rewardsToken = _rewardsToken;
}
function setShares(
address _wallet,
uint256 _amount,
bool _sharesRemoving
) external override {
require(_msgSender() == trackingToken, 'UNAUTHORIZED');
_setShares(_wallet, _amount, _sharesRemoving);
}
function _setShares(
address _wallet,
uint256 _amount,
bool _sharesRemoving
) internal {
_processFeesIfApplicable();
if (_sharesRemoving) {
_removeShares(_wallet, _amount);
emit RemoveShares(_wallet, _amount);
} else {
_addShares(_wallet, _amount);
emit AddShares(_wallet, _amount);
}
}
function _addShares(address _wallet, uint256 _amount) internal {
if (shares[_wallet] > 0) {
_distributeReward(_wallet);
}
uint256 sharesBefore = shares[_wallet];
totalShares += _amount;
shares[_wallet] += _amount;
if (sharesBefore == 0 && shares[_wallet] > 0) {
totalStakers++;
}
_resetExcluded(_wallet);
}
function _removeShares(address _wallet, uint256 _amount) internal {
require(shares[_wallet] > 0 && _amount <= shares[_wallet], 'RE');
_distributeReward(_wallet);
totalShares -= _amount;
shares[_wallet] -= _amount;
if (shares[_wallet] == 0) {
totalStakers--;
}
_resetExcluded(_wallet);
}
function _processFeesIfApplicable() internal {
IDecentralizedIndex(INDEX_FUND).processPreSwapFeesAndSwap();
}
function depositFromPairedLpToken(
uint256 _amountTknDepositing,
uint256 _slippageOverride
) public override {
require(PAIRED_LP_TOKEN != rewardsToken, 'R');
require(_slippageOverride <= 200, 'MS');
if (_amountTknDepositing > 0) {
IERC20(PAIRED_LP_TOKEN).safeTransferFrom(
_msgSender(),
address(this),
_amountTknDepositing
);
}
uint256 _amountTkn = IERC20(PAIRED_LP_TOKEN).balanceOf(address(this));
require(_amountTkn > 0, 'A');
uint256 _adminAmt = _getAdminFeeFromAmount(_amountTkn);
_amountTkn -= _adminAmt;
(address _token0, address _token1) = PAIRED_LP_TOKEN < rewardsToken
? (PAIRED_LP_TOKEN, rewardsToken)
: (rewardsToken, PAIRED_LP_TOKEN);
address _pool = DEX_HANDLER.getV3Pool(_token0, _token1, REWARDS_POOL_FEE);
uint160 _rewardsSqrtPriceX96 = V3_TWAP_UTILS
.sqrtPriceX96FromPoolAndInterval(_pool);
uint256 _rewardsPriceX96 = V3_TWAP_UTILS.priceX96FromSqrtPriceX96(
_rewardsSqrtPriceX96
);
uint256 _amountOut = _token0 == PAIRED_LP_TOKEN
? (_rewardsPriceX96 * _amountTkn) / FixedPoint96.Q96
: (_amountTkn * FixedPoint96.Q96) / _rewardsPriceX96;
uint256 _slippage = _slippageOverride > 0
? _slippageOverride
: _rewardsSwapSlippage;
_swapForRewards(
_amountTkn,
_amountOut,
_slippage,
_slippageOverride > 0,
_adminAmt
);
}
function depositRewards(address _token, uint256 _amount) external override {
_depositRewardsFromToken(_msgSender(), _token, _amount, true);
}
function depositRewardsNoTransfer(
address _token,
uint256 _amount
) external override {
require(_msgSender() == INDEX_FUND, 'AUTH');
_depositRewardsFromToken(_msgSender(), _token, _amount, false);
}
function _depositRewardsFromToken(
address _user,
address _token,
uint256 _amount,
bool _shouldTransfer
) internal {
require(_amount > 0, 'A');
require(_isValidRewardsToken(_token), 'V');
uint256 _finalAmt = _amount;
if (_shouldTransfer) {
uint256 _balBefore = IERC20(_token).balanceOf(address(this));
IERC20(_token).safeTransferFrom(_user, address(this), _finalAmt);
_finalAmt = IERC20(_token).balanceOf(address(this)) - _balBefore;
}
uint256 _adminAmt = _getAdminFeeFromAmount(_finalAmt);
if (_adminAmt > 0) {
IERC20(_token).safeTransfer(
Ownable(address(V3_TWAP_UTILS)).owner(),
_adminAmt
);
_finalAmt -= _adminAmt;
}
_depositRewards(_token, _finalAmt);
}
function _depositRewards(address _token, uint256 _amountTotal) internal {
if (!_depositedRewardsToken[_token]) {
_depositedRewardsToken[_token] = true;
_allRewardsTokens.push(_token);
}
if (_amountTotal == 0) {
return;
}
if (totalShares == 0) {
require(_token == rewardsToken, 'R');
_burnRewards(_amountTotal);
return;
}
uint256 _depositAmount = _amountTotal;
if (_token == rewardsToken) {
(, uint256 _yieldBurnFee) = _getYieldFees();
if (_yieldBurnFee > 0) {
uint256 _burnAmount = (_amountTotal * _yieldBurnFee) /
PROTOCOL_FEE_ROUTER.protocolFees().DEN();
if (_burnAmount > 0) {
_burnRewards(_burnAmount);
_depositAmount -= _burnAmount;
}
}
}
rewardsDeposited[_token] += _depositAmount;
rewardsDepMonthly[_token][
beginningOfMonth(block.timestamp)
] += _depositAmount;
_rewardsPerShare[_token] += (PRECISION * _depositAmount) / totalShares;
emit DepositRewards(_msgSender(), _token, _depositAmount);
}
function _distributeReward(address _wallet) internal {
if (shares[_wallet] == 0) {
return;
}
for (uint256 _i; _i < _allRewardsTokens.length; _i++) {
address _token = _allRewardsTokens[_i];
uint256 _amount = getUnpaid(_token, _wallet);
rewards[_token][_wallet].realized += _amount;
rewards[_token][_wallet].excluded = _cumulativeRewards(
_token,
shares[_wallet]
);
if (_amount > 0) {
rewardsDistributed[_token] += _amount;
IERC20(_token).safeTransfer(_wallet, _amount);
emit DistributeReward(_wallet, _token, _amount);
}
}
}
function _resetExcluded(address _wallet) internal {
for (uint256 _i; _i < _allRewardsTokens.length; _i++) {
address _token = _allRewardsTokens[_i];
rewards[_token][_wallet].excluded = _cumulativeRewards(
_token,
shares[_wallet]
);
}
}
function _burnRewards(uint256 _burnAmount) internal {
try IPEAS(rewardsToken).burn(_burnAmount) {} catch {
IERC20(rewardsToken).safeTransfer(address(0xdead), _burnAmount);
}
}
function _isValidRewardsToken(address _token) internal view returns (bool) {
return _token == rewardsToken || REWARDS_WHITELISTER.whitelist(_token);
}
function _getAdminFeeFromAmount(
uint256 _amount
) internal view returns (uint256) {
(uint256 _yieldAdminFee, ) = _getYieldFees();
if (_yieldAdminFee == 0) {
return 0;
}
return
(_amount * _yieldAdminFee) / PROTOCOL_FEE_ROUTER.protocolFees().DEN();
}
function _getYieldFees()
internal
view
returns (uint256 _admin, uint256 _burn)
{
IProtocolFees _fees = PROTOCOL_FEE_ROUTER.protocolFees();
if (address(_fees) != address(0)) {
_admin = _fees.yieldAdmin();
_burn = _fees.yieldBurn();
}
}
function _swapForRewards(
uint256 _amountIn,
uint256 _amountOut,
uint256 _slippage,
bool _isSlipOverride,
uint256 _adminAmt
) internal {
uint256 _balBefore = IERC20(rewardsToken).balanceOf(address(this));
IERC20(PAIRED_LP_TOKEN).safeIncreaseAllowance(
address(DEX_HANDLER),
_amountIn
);
try
DEX_HANDLER.swapV3Single(
PAIRED_LP_TOKEN,
rewardsToken,
REWARDS_POOL_FEE,
_amountIn,
(_amountOut * (1000 - _slippage)) / 1000,
address(this)
)
{
if (_adminAmt > 0) {
IERC20(PAIRED_LP_TOKEN).safeTransfer(
Ownable(address(V3_TWAP_UTILS)).owner(),
_adminAmt
);
}
_rewardsSwapSlippage = 20;
_depositRewards(
rewardsToken,
IERC20(rewardsToken).balanceOf(address(this)) - _balBefore
);
} catch {
if (!_isSlipOverride && _rewardsSwapSlippage < 200) {
_rewardsSwapSlippage += 10;
}
IERC20(PAIRED_LP_TOKEN).safeDecreaseAllowance(
address(DEX_HANDLER),
_amountIn
);
}
}
function beginningOfMonth(uint256 _timestamp) public pure returns (uint256) {
(, , uint256 _dayOfMonth) = BokkyPooBahsDateTimeLibrary.timestampToDate(
_timestamp
);
return _timestamp - ((_dayOfMonth - 1) * 1 days) - (_timestamp % 1 days);
}
function claimReward(address _wallet) external override {
_distributeReward(_wallet);
emit ClaimReward(_wallet);
}
function getUnpaid(
address _token,
address _wallet
) public view returns (uint256) {
if (shares[_wallet] == 0) {
return 0;
}
uint256 earnedRewards = _cumulativeRewards(_token, shares[_wallet]);
uint256 rewardsExcluded = rewards[_token][_wallet].excluded;
if (earnedRewards <= rewardsExcluded) {
return 0;
}
return earnedRewards - rewardsExcluded;
}
function _cumulativeRewards(
address _token,
uint256 _share
) internal view returns (uint256) {
return (_share * _rewardsPerShare[_token]) / PRECISION;
}
}
文件 38 的 38:WeightedIndex.sol
pragma solidity ^0.8.19;
import '@uniswap/v3-core/contracts/libraries/FixedPoint96.sol';
import './interfaces/IUniswapV2Pair.sol';
import './interfaces/IV3TwapUtilities.sol';
import './DecentralizedIndex.sol';
contract WeightedIndex is DecentralizedIndex {
using SafeERC20 for IERC20;
uint256 _totalWeights;
constructor(
string memory _name,
string memory _symbol,
Config memory _config,
Fees memory _fees,
address[] memory _tokens,
uint256[] memory _weights,
address _pairedLpToken,
address _lpRewardsToken,
address _dexHandler,
bool _stakeRestriction
)
DecentralizedIndex(
_name,
_symbol,
IndexType.WEIGHTED,
_config,
_fees,
_pairedLpToken,
_lpRewardsToken,
_dexHandler,
_stakeRestriction
)
{
require(_tokens.length == _weights.length, 'V');
uint256 _tl = _tokens.length;
for (uint8 _i; _i < _tl; _i++) {
require(!_isTokenInIndex[_tokens[_i]], 'D');
require(_weights[_i] > 0, 'W');
indexTokens.push(
IndexAssetInfo({
token: _tokens[_i],
basePriceUSDX96: 0,
weighting: _weights[_i],
c1: address(0),
q1: 0
})
);
_totalWeights += _weights[_i];
_fundTokenIdx[_tokens[_i]] = _i;
_isTokenInIndex[_tokens[_i]] = true;
if (_config.blacklistTKNpTKNPoolV2 && _tokens[_i] != _pairedLpToken) {
address _blkPool = IDexAdapter(_dexHandler).createV2Pool(
address(this),
_tokens[_i]
);
_blacklist[_blkPool] = true;
}
}
uint256 _xX96 = (FixedPoint96.Q96 * _totalWeights) / _weights[0];
for (uint256 _i; _i < _tl; _i++) {
indexTokens[_i].q1 =
(_weights[_i] * _xX96 * 10 ** IERC20Metadata(_tokens[_i]).decimals()) /
_totalWeights;
}
}
function _getNativePriceUSDX96() internal view returns (uint256) {
IUniswapV2Pair _nativeStablePool = IUniswapV2Pair(
DEX_HANDLER.getV2Pool(DAI, WETH)
);
address _token0 = _nativeStablePool.token0();
(uint8 _decimals0, uint8 _decimals1) = (
IERC20Metadata(_token0).decimals(),
IERC20Metadata(_nativeStablePool.token1()).decimals()
);
(uint112 _res0, uint112 _res1, ) = _nativeStablePool.getReserves();
return
_token0 == DAI
? (FixedPoint96.Q96 * _res0 * 10 ** _decimals1) /
_res1 /
10 ** _decimals0
: (FixedPoint96.Q96 * _res1 * 10 ** _decimals0) /
_res0 /
10 ** _decimals1;
}
function _getTokenPriceUSDX96(
address _token
) internal view returns (uint256) {
if (_token == WETH) {
return _getNativePriceUSDX96();
}
IUniswapV2Pair _pool = IUniswapV2Pair(DEX_HANDLER.getV2Pool(_token, WETH));
address _token0 = _pool.token0();
uint8 _decimals0 = IERC20Metadata(_token0).decimals();
uint8 _decimals1 = IERC20Metadata(_pool.token1()).decimals();
(uint112 _res0, uint112 _res1, ) = _pool.getReserves();
uint256 _nativePriceUSDX96 = _getNativePriceUSDX96();
return
_token0 == WETH
? (_nativePriceUSDX96 * _res0 * 10 ** _decimals1) /
_res1 /
10 ** _decimals0
: (_nativePriceUSDX96 * _res1 * 10 ** _decimals0) /
_res0 /
10 ** _decimals1;
}
function bond(
address _token,
uint256 _amount,
uint256 _amountMintMin
) external override lock noSwapOrFee {
require(_isTokenInIndex[_token], 'IT');
uint256 _tokenIdx = _fundTokenIdx[_token];
uint256 _tokenCurSupply = IERC20(_token).balanceOf(address(this));
bool _firstIn = _isFirstIn();
uint256 _tokenAmtSupplyRatioX96 = _firstIn
? FixedPoint96.Q96
: (_amount * FixedPoint96.Q96) / _tokenCurSupply;
uint256 _tokensMinted;
if (_firstIn) {
_tokensMinted =
(_amount * FixedPoint96.Q96 * 10 ** decimals()) /
indexTokens[_tokenIdx].q1;
} else {
_tokensMinted =
(totalSupply() * _tokenAmtSupplyRatioX96) /
FixedPoint96.Q96;
}
uint256 _feeTokens = _canWrapFeeFree(_msgSender())
? 0
: (_tokensMinted * fees.bond) / DEN;
require(_tokensMinted - _feeTokens >= _amountMintMin, 'M');
_mint(_msgSender(), _tokensMinted - _feeTokens);
if (_feeTokens > 0) {
_mint(address(this), _feeTokens);
_processBurnFee(_feeTokens);
}
uint256 _il = indexTokens.length;
for (uint256 _i; _i < _il; _i++) {
uint256 _transferAmt = _firstIn
? getInitialAmount(_token, _amount, indexTokens[_i].token)
: (IERC20(indexTokens[_i].token).balanceOf(address(this)) *
_tokenAmtSupplyRatioX96) / FixedPoint96.Q96;
_transferFromAndValidate(
IERC20(indexTokens[_i].token),
_msgSender(),
_transferAmt
);
}
_bond();
emit Bond(_msgSender(), _token, _amount, _tokensMinted);
}
function debond(
uint256 _amount,
address[] memory,
uint8[] memory
) external override lock noSwapOrFee {
uint256 _amountAfterFee = _isLastOut(_amount)
? _amount
: (_amount * (DEN - fees.debond)) / DEN;
uint256 _percAfterFeeX96 = (_amountAfterFee * FixedPoint96.Q96) /
totalSupply();
super._transfer(_msgSender(), address(this), _amount);
_burn(address(this), _amountAfterFee);
_processBurnFee(_amount - _amountAfterFee);
uint256 _il = indexTokens.length;
for (uint256 _i; _i < _il; _i++) {
uint256 _tokenSupply = IERC20(indexTokens[_i].token).balanceOf(
address(this)
);
uint256 _debondAmount = (_tokenSupply * _percAfterFeeX96) /
FixedPoint96.Q96;
if (_debondAmount > 0) {
IERC20(indexTokens[_i].token).safeTransfer(_msgSender(), _debondAmount);
}
}
_processPreSwapFeesAndSwap();
emit Debond(_msgSender(), _amount);
}
function getInitialAmount(
address _sourceToken,
uint256 _sourceAmount,
address _targetToken
) public view override returns (uint256) {
uint256 _sourceTokenIdx = _fundTokenIdx[_sourceToken];
uint256 _targetTokenIdx = _fundTokenIdx[_targetToken];
return
(_sourceAmount *
indexTokens[_targetTokenIdx].weighting *
10 ** IERC20Metadata(_targetToken).decimals()) /
indexTokens[_sourceTokenIdx].weighting /
10 ** IERC20Metadata(_sourceToken).decimals();
}
function getTokenPriceUSDX96(
address _token
) external view override returns (uint256) {
return _getTokenPriceUSDX96(_token);
}
function getIdxPriceUSDX96()
external
view
override
returns (uint256, uint256)
{
uint256 _priceX96;
uint256 _X96_2 = 2 ** (96 / 2);
uint256 _il = indexTokens.length;
for (uint256 _i; _i < _il; _i++) {
uint256 _tokenPriceUSDX96_2 = _getTokenPriceUSDX96(
indexTokens[_i].token
) / _X96_2;
_priceX96 +=
(_tokenPriceUSDX96_2 * indexTokens[_i].q1) /
10 ** IERC20Metadata(indexTokens[_i].token).decimals() /
_X96_2;
}
return (0, _priceX96);
}
}
{
"compilationTarget": {
"contracts/WeightedIndex.sol": "WeightedIndex"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"components":[{"internalType":"address","name":"partner","type":"address"},{"internalType":"bool","name":"hasTransferTax","type":"bool"},{"internalType":"bool","name":"blacklistTKNpTKNPoolV2","type":"bool"}],"internalType":"struct IDecentralizedIndex.Config","name":"_config","type":"tuple"},{"components":[{"internalType":"uint16","name":"burn","type":"uint16"},{"internalType":"uint16","name":"bond","type":"uint16"},{"internalType":"uint16","name":"debond","type":"uint16"},{"internalType":"uint16","name":"buy","type":"uint16"},{"internalType":"uint16","name":"sell","type":"uint16"},{"internalType":"uint16","name":"partner","type":"uint16"}],"internalType":"struct IDecentralizedIndex.Fees","name":"_fees","type":"tuple"},{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_weights","type":"uint256[]"},{"internalType":"address","name":"_pairedLpToken","type":"address"},{"internalType":"address","name":"_lpRewardsToken","type":"address"},{"internalType":"address","name":"_dexHandler","type":"address"},{"internalType":"bool","name":"_stakeRestriction","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountTokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountDAI","type":"uint256"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountTokensBonded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountTokensMinted","type":"uint256"}],"name":"Bond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newIdx","type":"address"},{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"Create","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountDebonded","type":"uint256"}],"name":"Debond","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FlashLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"v2Pool","type":"address"}],"name":"Initialize","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountLiquidity","type":"uint256"}],"name":"RemoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"newPartner","type":"address"}],"name":"SetPartner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"SetPartnerFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BOND_FEE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEBOND_FEE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEX_HANDLER","outputs":[{"internalType":"contract IDexAdapter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FLASH_FEE_AMOUNT_DAI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAIRED_LP_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_idxLPTokens","type":"uint256"},{"internalType":"uint256","name":"_pairedLPTokens","type":"uint256"},{"internalType":"uint256","name":"_slippage","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"addLiquidityV2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_amountMintMin","type":"uint256"}],"name":"bond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"address","name":"partner","type":"address"},{"internalType":"bool","name":"hasTransferTax","type":"bool"},{"internalType":"bool","name":"blacklistTKNpTKNPoolV2","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"created","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint8[]","name":"","type":"uint8[]"}],"name":"debond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fees","outputs":[{"internalType":"uint16","name":"burn","type":"uint16"},{"internalType":"uint16","name":"bond","type":"uint16"},{"internalType":"uint16","name":"debond","type":"uint16"},{"internalType":"uint16","name":"buy","type":"uint16"},{"internalType":"uint16","name":"sell","type":"uint16"},{"internalType":"uint16","name":"partner","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"flash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllAssets","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"weighting","type":"uint256"},{"internalType":"uint256","name":"basePriceUSDX96","type":"uint256"},{"internalType":"address","name":"c1","type":"address"},{"internalType":"uint256","name":"q1","type":"uint256"}],"internalType":"struct IDecentralizedIndex.IndexAssetInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getIdxPriceUSDX96","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sourceToken","type":"address"},{"internalType":"uint256","name":"_sourceAmount","type":"uint256"},{"internalType":"address","name":"_targetToken","type":"address"}],"name":"getInitialAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTokenPriceUSDX96","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"indexTokens","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"weighting","type":"uint256"},{"internalType":"uint256","name":"basePriceUSDX96","type":"uint256"},{"internalType":"address","name":"c1","type":"address"},{"internalType":"uint256","name":"q1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"indexType","outputs":[{"internalType":"enum IDecentralizedIndex.IndexType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"isAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpRewardsToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpStakingPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_slip","type":"uint256"}],"name":"manualProcessFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"partner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"processPreSwapFeesAndSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lpTokens","type":"uint256"},{"internalType":"uint256","name":"_minIdxTokens","type":"uint256"},{"internalType":"uint256","name":"_minPairedLpToken","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"removeLiquidityV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescueETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_partner","type":"address"}],"name":"setPartner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_fee","type":"uint16"}],"name":"setPartnerFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]