编译器
0.6.12+commit.27d51765
文件 1 的 21:Address.sol
pragma solidity >=0.6.2 <0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 21:CoreUtility.sol
pragma solidity >=0.6.10 <0.8.0;
import "@openzeppelin/contracts/math/SafeMath.sol";
abstract contract CoreUtility {
using SafeMath for uint256;
uint256 internal constant SETTLEMENT_TIME = 14 hours;
function _endOfWeek(uint256 timestamp) internal pure returns (uint256) {
return ((timestamp.add(1 weeks) - SETTLEMENT_TIME) / 1 weeks) * 1 weeks + SETTLEMENT_TIME;
}
}
文件 3 的 21:IChessController.sol
pragma solidity >=0.6.10 <0.8.0;
interface IChessController {
function getFundRelativeWeight(address account, uint256 timestamp) external returns (uint256);
}
文件 4 的 21:IChessSchedule.sol
pragma solidity >=0.6.10 <0.8.0;
interface IChessSchedule {
function getWeeklySupply(uint256 timestamp) external view returns (uint256);
function getRate(uint256 timestamp) external view returns (uint256);
function mint(address account, uint256 amount) external;
function addMinter(address account) external;
}
文件 5 的 21:IERC20.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, 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 sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 6 的 21:IFundV3.sol
pragma solidity >=0.6.10 <0.8.0;
pragma experimental ABIEncoderV2;
import "./ITwapOracleV2.sol";
interface IFundV3 {
struct Rebalance {
uint256 ratioB2Q;
uint256 ratioR2Q;
uint256 ratioBR;
uint256 timestamp;
}
function tokenUnderlying() external view returns (address);
function tokenQ() external view returns (address);
function tokenB() external view returns (address);
function tokenR() external view returns (address);
function tokenShare(uint256 tranche) external view returns (address);
function primaryMarket() external view returns (address);
function primaryMarketUpdateProposal() external view returns (address, uint256);
function strategy() external view returns (address);
function strategyUpdateProposal() external view returns (address, uint256);
function underlyingDecimalMultiplier() external view returns (uint256);
function twapOracle() external view returns (ITwapOracleV2);
function feeCollector() external view returns (address);
function endOfDay(uint256 timestamp) external pure returns (uint256);
function trancheTotalSupply(uint256 tranche) external view returns (uint256);
function trancheBalanceOf(uint256 tranche, address account) external view returns (uint256);
function trancheAllBalanceOf(address account)
external
view
returns (
uint256,
uint256,
uint256
);
function trancheBalanceVersion(address account) external view returns (uint256);
function trancheAllowance(
uint256 tranche,
address owner,
address spender
) external view returns (uint256);
function trancheAllowanceVersion(address owner, address spender)
external
view
returns (uint256);
function trancheTransfer(
uint256 tranche,
address recipient,
uint256 amount,
uint256 version
) external;
function trancheTransferFrom(
uint256 tranche,
address sender,
address recipient,
uint256 amount,
uint256 version
) external;
function trancheApprove(
uint256 tranche,
address spender,
uint256 amount,
uint256 version
) external;
function getRebalanceSize() external view returns (uint256);
function getRebalance(uint256 index) external view returns (Rebalance memory);
function getRebalanceTimestamp(uint256 index) external view returns (uint256);
function currentDay() external view returns (uint256);
function splitRatio() external view returns (uint256);
function historicalSplitRatio(uint256 version) external view returns (uint256);
function fundActivityStartTime() external view returns (uint256);
function isFundActive(uint256 timestamp) external view returns (bool);
function getEquivalentTotalB() external view returns (uint256);
function getEquivalentTotalQ() external view returns (uint256);
function historicalEquivalentTotalB(uint256 timestamp) external view returns (uint256);
function historicalNavs(uint256 timestamp) external view returns (uint256 navB, uint256 navR);
function extrapolateNav(uint256 price)
external
view
returns (
uint256,
uint256,
uint256
);
function doRebalance(
uint256 amountQ,
uint256 amountB,
uint256 amountR,
uint256 index
)
external
view
returns (
uint256 newAmountQ,
uint256 newAmountB,
uint256 newAmountR
);
function batchRebalance(
uint256 amountQ,
uint256 amountB,
uint256 amountR,
uint256 fromIndex,
uint256 toIndex
)
external
view
returns (
uint256 newAmountQ,
uint256 newAmountB,
uint256 newAmountR
);
function refreshBalance(address account, uint256 targetVersion) external;
function refreshAllowance(
address owner,
address spender,
uint256 targetVersion
) external;
function shareTransfer(
address sender,
address recipient,
uint256 amount
) external;
function shareTransferFrom(
address spender,
address sender,
address recipient,
uint256 amount
) external returns (uint256 newAllowance);
function shareIncreaseAllowance(
address sender,
address spender,
uint256 addedValue
) external returns (uint256 newAllowance);
function shareDecreaseAllowance(
address sender,
address spender,
uint256 subtractedValue
) external returns (uint256 newAllowance);
function shareApprove(
address owner,
address spender,
uint256 amount
) external;
function historicalUnderlying(uint256 timestamp) external view returns (uint256);
function getTotalUnderlying() external view returns (uint256);
function getStrategyUnderlying() external view returns (uint256);
function getTotalDebt() external view returns (uint256);
event RebalanceTriggered(
uint256 indexed index,
uint256 indexed day,
uint256 navSum,
uint256 navB,
uint256 navROrZero,
uint256 ratioB2Q,
uint256 ratioR2Q,
uint256 ratioBR
);
event Settled(uint256 indexed day, uint256 navB, uint256 navR, uint256 interestRate);
event InterestRateUpdated(uint256 baseInterestRate, uint256 floatingInterestRate);
event BalancesRebalanced(
address indexed account,
uint256 version,
uint256 balanceQ,
uint256 balanceB,
uint256 balanceR
);
event AllowancesRebalanced(
address indexed owner,
address indexed spender,
uint256 version,
uint256 allowanceQ,
uint256 allowanceB,
uint256 allowanceR
);
}
文件 7 的 21:IPrimaryMarketRouter.sol
pragma solidity >=0.6.10 <0.8.0;
pragma experimental ABIEncoderV2;
import "../interfaces/IFundV3.sol";
import "../interfaces/IStableSwap.sol";
interface IPrimaryMarketRouter is IStableSwapCore {
function create(
address recipient,
uint256 underlying,
uint256 minOutQ,
uint256 version
) external payable returns (uint256 outQ);
function createAndStake(
uint256 underlying,
uint256 minOutQ,
address staking,
uint256 version
) external payable;
function createSplitAndStake(
uint256 underlying,
uint256 minOutQ,
address router,
address quoteAddress,
uint256 minLpOut,
address staking,
uint256 version
) external payable;
function splitAndStake(
uint256 inQ,
address router,
address quoteAddress,
uint256 minLpOut,
address staking,
uint256 version
) external;
}
文件 8 的 21:IPrimaryMarketV3.sol
pragma solidity >=0.6.10 <0.8.0;
interface IPrimaryMarketV3 {
function fund() external view returns (address);
function getCreation(uint256 underlying) external view returns (uint256 outQ);
function getCreationForQ(uint256 minOutQ) external view returns (uint256 underlying);
function getRedemption(uint256 inQ) external view returns (uint256 underlying, uint256 fee);
function getRedemptionForUnderlying(uint256 minUnderlying) external view returns (uint256 inQ);
function getSplit(uint256 inQ) external view returns (uint256 outB);
function getSplitForB(uint256 minOutB) external view returns (uint256 inQ);
function getMerge(uint256 inB) external view returns (uint256 outQ, uint256 feeQ);
function getMergeForQ(uint256 minOutQ) external view returns (uint256 inB);
function canBeRemovedFromFund() external view returns (bool);
function create(
address recipient,
uint256 minOutQ,
uint256 version
) external returns (uint256 outQ);
function redeem(
address recipient,
uint256 inQ,
uint256 minUnderlying,
uint256 version
) external returns (uint256 underlying);
function redeemAndUnwrap(
address recipient,
uint256 inQ,
uint256 minUnderlying,
uint256 version
) external returns (uint256 underlying);
function queueRedemption(
address recipient,
uint256 inQ,
uint256 minUnderlying,
uint256 version
) external returns (uint256 underlying, uint256 index);
function claimRedemptions(address account, uint256[] calldata indices)
external
returns (uint256 underlying);
function claimRedemptionsAndUnwrap(address account, uint256[] calldata indices)
external
returns (uint256 underlying);
function split(
address recipient,
uint256 inQ,
uint256 version
) external returns (uint256 outB);
function merge(
address recipient,
uint256 inB,
uint256 version
) external returns (uint256 outQ);
function settle(uint256 day) external;
}
文件 9 的 21:IStableSwap.sol
pragma solidity >=0.6.10 <0.8.0;
import "../interfaces/IFundV3.sol";
interface IStableSwapCore {
function getQuoteOut(uint256 baseIn) external view returns (uint256 quoteOut);
function getQuoteIn(uint256 baseOut) external view returns (uint256 quoteIn);
function getBaseOut(uint256 quoteIn) external view returns (uint256 baseOut);
function getBaseIn(uint256 quoteOut) external view returns (uint256 baseIn);
function buy(
uint256 version,
uint256 baseOut,
address recipient,
bytes calldata data
) external returns (uint256 realBaseOut);
function sell(
uint256 version,
uint256 quoteOut,
address recipient,
bytes calldata data
) external returns (uint256 realQuoteOut);
}
interface IStableSwap is IStableSwapCore {
function fund() external view returns (IFundV3);
function baseTranche() external view returns (uint256);
function baseAddress() external view returns (address);
function quoteAddress() external view returns (address);
function allBalances() external view returns (uint256, uint256);
function getOraclePrice() external view returns (uint256);
function getCurrentD() external view returns (uint256);
function getCurrentPriceOverOracle() external view returns (uint256);
function getCurrentPrice() external view returns (uint256);
function getPriceOverOracleIntegral() external view returns (uint256);
function addLiquidity(uint256 version, address recipient) external returns (uint256);
function removeLiquidity(
uint256 version,
uint256 lpIn,
uint256 minBaseOut,
uint256 minQuoteOut
) external returns (uint256 baseOut, uint256 quoteOut);
function removeLiquidityUnwrap(
uint256 version,
uint256 lpIn,
uint256 minBaseOut,
uint256 minQuoteOut
) external returns (uint256 baseOut, uint256 quoteOut);
function removeBaseLiquidity(
uint256 version,
uint256 lpIn,
uint256 minBaseOut
) external returns (uint256 baseOut);
function removeQuoteLiquidity(
uint256 version,
uint256 lpIn,
uint256 minQuoteOut
) external returns (uint256 quoteOut);
function removeQuoteLiquidityUnwrap(
uint256 version,
uint256 lpIn,
uint256 minQuoteOut
) external returns (uint256 quoteOut);
}
interface IStableSwapCoreInternalRevertExpected {
function getQuoteOut(uint256 baseIn) external returns (uint256 quoteOut);
function getQuoteIn(uint256 baseOut) external returns (uint256 quoteIn);
function getBaseOut(uint256 quoteIn) external returns (uint256 baseOut);
function getBaseIn(uint256 quoteOut) external returns (uint256 baseIn);
function buy(
uint256 version,
uint256 baseOut,
address recipient,
bytes calldata data
) external returns (uint256 realBaseOut);
function sell(
uint256 version,
uint256 quoteOut,
address recipient,
bytes calldata data
) external returns (uint256 realQuoteOut);
}
文件 10 的 21:ISwapRouter.sol
pragma solidity >=0.6.10 <0.8.0;
import "./IStableSwap.sol";
interface ISwapRouter {
function getSwap(address baseToken, address quoteToken) external view returns (IStableSwap);
function getAmountsOut(uint256 amount, address[] memory path)
external
view
returns (
uint256[] memory amounts,
IStableSwap[] memory swaps,
bool[] memory isBuy
);
function getAmountsIn(uint256 amount, address[] memory path)
external
view
returns (
uint256[] memory amounts,
IStableSwap[] memory swaps,
bool[] memory isBuy
);
function addLiquidity(
address baseToken,
address quoteToken,
uint256 baseDelta,
uint256 quoteDelta,
uint256 minMintAmount,
uint256 version,
uint256 deadline
) external payable;
function swapExactTokensForTokens(
uint256 amountIn,
uint256 minAmountOut,
address[] calldata path,
address recipient,
address staking,
uint256[] calldata versions,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 maxAmountIn,
address[] calldata path,
address recipient,
address staking,
uint256[] calldata versions,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapExactTokensForTokensUnwrap(
uint256 amountIn,
uint256 minAmountOut,
address[] calldata path,
address recipient,
uint256[] calldata versions,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokensUnwrap(
uint256 amountOut,
uint256 maxAmountIn,
address[] calldata path,
address recipient,
uint256[] calldata versions,
uint256 deadline
) external returns (uint256[] memory amounts);
}
文件 11 的 21:ITrancheIndexV2.sol
pragma solidity >=0.6.10 <0.8.0;
abstract contract ITrancheIndexV2 {
uint256 internal constant TRANCHE_Q = 0;
uint256 internal constant TRANCHE_B = 1;
uint256 internal constant TRANCHE_R = 2;
uint256 internal constant TRANCHE_COUNT = 3;
}
文件 12 的 21:ITwapOracle.sol
pragma solidity >=0.6.10 <0.8.0;
interface ITwapOracle {
enum UpdateType {PRIMARY, SECONDARY, OWNER, CHAINLINK, UNISWAP_V2}
function getTwap(uint256 timestamp) external view returns (uint256);
}
文件 13 的 21:ITwapOracleV2.sol
pragma solidity >=0.6.10 <0.8.0;
import "./ITwapOracle.sol";
interface ITwapOracleV2 is ITwapOracle {
function getLatest() external view returns (uint256);
}
文件 14 的 21:IVotingEscrow.sol
pragma solidity >=0.6.10 <0.8.0;
pragma experimental ABIEncoderV2;
interface IAddressWhitelist {
function check(address account) external view returns (bool);
}
interface IVotingEscrowCallback {
function syncWithVotingEscrow(address account) external;
}
interface IVotingEscrow {
struct LockedBalance {
uint256 amount;
uint256 unlockTime;
}
function token() external view returns (address);
function maxTime() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function totalSupply() external view returns (uint256);
function balanceOfAtTimestamp(address account, uint256 timestamp)
external
view
returns (uint256);
function getTimestampDropBelow(address account, uint256 threshold)
external
view
returns (uint256);
function getLockedBalance(address account) external view returns (LockedBalance memory);
}
文件 15 的 21:IWrappedERC20.sol
pragma solidity >=0.6.10 <0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWrappedERC20 is IERC20 {
function deposit() external payable;
function withdraw(uint256 wad) external;
}
文件 16 的 21:Math.sol
pragma solidity >=0.6.0 <0.8.0;
library Math {
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 / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
文件 17 的 21:PrimaryMarketRouter.sol
pragma solidity >=0.6.10 <0.8.0;
pragma experimental ABIEncoderV2;
import "../fund/ShareStaking.sol";
import "../interfaces/IPrimaryMarketRouter.sol";
import "../interfaces/IPrimaryMarketV3.sol";
import "../interfaces/ISwapRouter.sol";
import "../interfaces/IStableSwap.sol";
import "../interfaces/IWrappedERC20.sol";
contract PrimaryMarketRouter is IPrimaryMarketRouter, ITrancheIndexV2 {
using SafeMath for uint256;
using SafeERC20 for IERC20;
IPrimaryMarketV3 public immutable primaryMarket;
IFundV3 public immutable fund;
IERC20 private immutable _tokenUnderlying;
address private immutable _tokenB;
constructor(address pm) public {
primaryMarket = IPrimaryMarketV3(pm);
IFundV3 fund_ = IFundV3(IPrimaryMarketV3(pm).fund());
fund = fund_;
_tokenUnderlying = IERC20(fund_.tokenUnderlying());
_tokenB = fund_.tokenB();
}
function getQuoteOut(uint256 baseIn) external view override returns (uint256 quoteOut) {
(quoteOut, ) = primaryMarket.getRedemption(baseIn);
}
function getQuoteIn(uint256 baseOut) external view override returns (uint256 quoteIn) {
quoteIn = primaryMarket.getCreationForQ(baseOut);
}
function getBaseOut(uint256 quoteIn) external view override returns (uint256 baseOut) {
baseOut = primaryMarket.getCreation(quoteIn);
}
function getBaseIn(uint256 quoteOut) external view override returns (uint256 baseIn) {
baseIn = primaryMarket.getRedemptionForUnderlying(quoteOut);
}
function buy(
uint256 version,
uint256 baseOut,
address recipient,
bytes calldata
) external override returns (uint256 realBaseOut) {
uint256 routerQuoteBalance = IERC20(_tokenUnderlying).balanceOf(address(this));
IERC20(_tokenUnderlying).safeTransfer(address(primaryMarket), routerQuoteBalance);
realBaseOut = primaryMarket.create(recipient, baseOut, version);
}
function sell(
uint256 version,
uint256 quoteOut,
address recipient,
bytes calldata
) external override returns (uint256 realQuoteOut) {
uint256 routerBaseBalance = fund.trancheBalanceOf(TRANCHE_Q, address(this));
realQuoteOut = primaryMarket.redeem(recipient, routerBaseBalance, quoteOut, version);
}
function create(
address recipient,
uint256 underlying,
uint256 minOutQ,
uint256 version
) public payable override returns (uint256 outQ) {
if (msg.value > 0) {
require(msg.value == underlying);
IWrappedERC20(address(_tokenUnderlying)).deposit{value: msg.value}();
_tokenUnderlying.safeTransfer(address(primaryMarket), msg.value);
} else {
IERC20(_tokenUnderlying).safeTransferFrom(
msg.sender,
address(primaryMarket),
underlying
);
}
outQ = primaryMarket.create(recipient, minOutQ, version);
}
function createAndStake(
uint256 underlying,
uint256 minOutQ,
address staking,
uint256 version
) external payable override {
uint256 outQ = create(staking, underlying, minOutQ, version);
ShareStaking(staking).deposit(TRANCHE_Q, outQ, msg.sender, version);
}
function createSplitAndStake(
uint256 underlying,
uint256 minOutQ,
address router,
address quoteAddress,
uint256 minLpOut,
address staking,
uint256 version
) external payable override {
uint256 outQ = create(address(this), underlying, minOutQ, version);
_splitAndStake(outQ, router, quoteAddress, minLpOut, staking, version);
}
function splitAndStake(
uint256 inQ,
address router,
address quoteAddress,
uint256 minLpOut,
address staking,
uint256 version
) external override {
fund.trancheTransferFrom(TRANCHE_Q, msg.sender, address(this), inQ, version);
_splitAndStake(inQ, router, quoteAddress, minLpOut, staking, version);
}
function _splitAndStake(
uint256 inQ,
address router,
address quoteAddress,
uint256 minLpOut,
address staking,
uint256 version
) private {
uint256 outB = primaryMarket.split(address(this), inQ, version);
{
IStableSwap swap = ISwapRouter(router).getSwap(_tokenB, quoteAddress);
fund.trancheTransfer(TRANCHE_B, address(swap), outB, version);
uint256 lpOut = swap.addLiquidity(version, msg.sender);
require(lpOut >= minLpOut, "Insufficient output");
}
if (staking == address(0)) {
fund.trancheTransfer(TRANCHE_R, msg.sender, outB, version);
} else {
fund.trancheTransfer(TRANCHE_R, staking, outB, version);
ShareStaking(staking).deposit(TRANCHE_R, outB, msg.sender, version);
}
}
}
文件 18 的 21:SafeDecimalMath.sol
pragma solidity >=0.6.10 <0.8.0;
import "@openzeppelin/contracts/math/SafeMath.sol";
library SafeDecimalMath {
using SafeMath for uint256;
uint256 private constant decimals = 18;
uint256 private constant highPrecisionDecimals = 27;
uint256 private constant UNIT = 10**uint256(decimals);
uint256 private constant PRECISE_UNIT = 10**uint256(highPrecisionDecimals);
uint256 private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR =
10**uint256(highPrecisionDecimals - decimals);
function multiplyDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mul(y).div(UNIT);
}
function multiplyDecimalPrecise(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mul(y).div(PRECISE_UNIT);
}
function divideDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mul(UNIT).div(y);
}
function divideDecimalPrecise(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mul(PRECISE_UNIT).div(y);
}
function decimalToPreciseDecimal(uint256 i) internal pure returns (uint256) {
return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);
}
function preciseDecimalToDecimal(uint256 i) internal pure returns (uint256) {
uint256 quotientTimesTen = i.mul(10).div(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);
if (quotientTimesTen % 10 >= 5) {
quotientTimesTen = quotientTimesTen.add(10);
}
return quotientTimesTen.div(10);
}
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
return c / a != b ? type(uint256).max : c;
}
function saturatingMultiplyDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
return saturatingMul(x, y).div(UNIT);
}
}
文件 19 的 21:SafeERC20.sol
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
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).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
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");
}
}
}
文件 20 的 21:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
文件 21 的 21:ShareStaking.sol
pragma solidity >=0.6.10 <0.8.0;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "../utils/SafeDecimalMath.sol";
import "../utils/CoreUtility.sol";
import "../interfaces/IFundV3.sol";
import "../interfaces/IChessController.sol";
import "../interfaces/IChessSchedule.sol";
import "../interfaces/ITrancheIndexV2.sol";
import "../interfaces/IVotingEscrow.sol";
contract ShareStaking is ITrancheIndexV2, CoreUtility {
using Math for uint256;
using SafeMath for uint256;
using SafeDecimalMath for uint256;
using SafeERC20 for IERC20;
event Deposited(uint256 tranche, address account, uint256 amount);
event Withdrawn(uint256 tranche, address account, uint256 amount);
uint256 private constant MAX_ITERATIONS = 500;
uint256 private constant REWARD_WEIGHT_B = 2;
uint256 private constant REWARD_WEIGHT_R = 1;
uint256 private constant REWARD_WEIGHT_Q = 3;
uint256 private constant MAX_BOOSTING_FACTOR = 3e18;
uint256 private constant MAX_BOOSTING_FACTOR_MINUS_ONE = MAX_BOOSTING_FACTOR - 1e18;
IFundV3 public immutable fund;
IChessSchedule public immutable chessSchedule;
IChessController public immutable chessController;
IVotingEscrow private immutable _votingEscrow;
uint256 public immutable rewardStartTimestamp;
uint256 private _rate;
uint256[TRANCHE_COUNT] private _totalSupplies;
uint256 private _totalSupplyVersion;
mapping(address => uint256[TRANCHE_COUNT]) private _balances;
mapping(address => uint256) private _balanceVersions;
mapping(uint256 => uint256) private _historicalSplitRatio;
uint256 private _invTotalWeightIntegral;
uint256[65535] private _historicalIntegrals;
uint256 private _historicalIntegralSize;
uint256 private _checkpointTimestamp;
mapping(address => uint256) private _userIntegrals;
mapping(address => uint256) private _claimableRewards;
uint256 private _workingSupply;
mapping(address => uint256) private _workingBalances;
constructor(
address fund_,
address chessSchedule_,
address chessController_,
address votingEscrow_,
uint256 rewardStartTimestamp_
) public {
fund = IFundV3(fund_);
chessSchedule = IChessSchedule(chessSchedule_);
chessController = IChessController(chessController_);
_votingEscrow = IVotingEscrow(votingEscrow_);
rewardStartTimestamp = rewardStartTimestamp_;
_checkpointTimestamp = block.timestamp;
}
function getRate() external view returns (uint256) {
return _rate / 1e18;
}
function weightedBalance(
uint256 amountQ,
uint256 amountB,
uint256 amountR,
uint256 splitRatio
) public pure returns (uint256) {
return
amountQ
.mul(REWARD_WEIGHT_Q)
.multiplyDecimal(splitRatio)
.add(amountB.mul(REWARD_WEIGHT_B))
.add(amountR.mul(REWARD_WEIGHT_R))
.div(REWARD_WEIGHT_Q);
}
function totalSupply(uint256 tranche) external view returns (uint256) {
uint256 totalSupplyQ = _totalSupplies[TRANCHE_Q];
uint256 totalSupplyB = _totalSupplies[TRANCHE_B];
uint256 totalSupplyR = _totalSupplies[TRANCHE_R];
uint256 version = _totalSupplyVersion;
uint256 rebalanceSize = _fundRebalanceSize();
if (version < rebalanceSize) {
(totalSupplyQ, totalSupplyB, totalSupplyR) = _fundBatchRebalance(
totalSupplyQ,
totalSupplyB,
totalSupplyR,
version,
rebalanceSize
);
}
if (tranche == TRANCHE_Q) {
return totalSupplyQ;
} else if (tranche == TRANCHE_B) {
return totalSupplyB;
} else {
return totalSupplyR;
}
}
function trancheBalanceOf(uint256 tranche, address account) external view returns (uint256) {
uint256 amountQ = _balances[account][TRANCHE_Q];
uint256 amountB = _balances[account][TRANCHE_B];
uint256 amountR = _balances[account][TRANCHE_R];
if (tranche == TRANCHE_Q) {
if (amountQ == 0 && amountB == 0 && amountR == 0) return 0;
} else if (tranche == TRANCHE_B) {
if (amountB == 0) return 0;
} else {
if (amountR == 0) return 0;
}
uint256 version = _balanceVersions[account];
uint256 rebalanceSize = _fundRebalanceSize();
if (version < rebalanceSize) {
(amountQ, amountB, amountR) = _fundBatchRebalance(
amountQ,
amountB,
amountR,
version,
rebalanceSize
);
}
if (tranche == TRANCHE_Q) {
return amountQ;
} else if (tranche == TRANCHE_B) {
return amountB;
} else {
return amountR;
}
}
function balanceVersion(address account) external view returns (uint256) {
return _balanceVersions[account];
}
function workingSupply() external view returns (uint256) {
uint256 version = _totalSupplyVersion;
uint256 rebalanceSize = _fundRebalanceSize();
if (version < rebalanceSize) {
(uint256 totalSupplyQ, uint256 totalSupplyB, uint256 totalSupplyR) =
_fundBatchRebalance(
_totalSupplies[TRANCHE_Q],
_totalSupplies[TRANCHE_B],
_totalSupplies[TRANCHE_R],
version,
rebalanceSize
);
return weightedBalance(totalSupplyQ, totalSupplyB, totalSupplyR, fund.splitRatio());
} else {
return _workingSupply;
}
}
function workingBalanceOf(address account) external view returns (uint256) {
uint256 version = _balanceVersions[account];
uint256 rebalanceSize = _fundRebalanceSize();
uint256 workingBalance = _workingBalances[account];
if (version < rebalanceSize || workingBalance == 0) {
uint256[TRANCHE_COUNT] storage balance = _balances[account];
uint256 amountQ = balance[TRANCHE_Q];
uint256 amountB = balance[TRANCHE_B];
uint256 amountR = balance[TRANCHE_R];
if (version < rebalanceSize) {
(amountQ, amountB, amountR) = _fundBatchRebalance(
amountQ,
amountB,
amountR,
version,
rebalanceSize
);
}
return weightedBalance(amountQ, amountB, amountR, fund.splitRatio());
} else {
return workingBalance;
}
}
function _fundRebalanceSize() internal view returns (uint256) {
return fund.getRebalanceSize();
}
function _fundDoRebalance(
uint256 amountQ,
uint256 amountB,
uint256 amountR,
uint256 index
)
internal
view
returns (
uint256,
uint256,
uint256
)
{
return fund.doRebalance(amountQ, amountB, amountR, index);
}
function _fundBatchRebalance(
uint256 amountQ,
uint256 amountB,
uint256 amountR,
uint256 fromIndex,
uint256 toIndex
)
internal
view
returns (
uint256,
uint256,
uint256
)
{
return fund.batchRebalance(amountQ, amountB, amountR, fromIndex, toIndex);
}
function deposit(
uint256 tranche,
uint256 amount,
address recipient,
uint256 version
) external {
_checkpoint(version);
_userCheckpoint(recipient, version);
_balances[recipient][tranche] = _balances[recipient][tranche].add(amount);
uint256 oldTotalSupply = _totalSupplies[tranche];
_totalSupplies[tranche] = oldTotalSupply.add(amount);
_updateWorkingBalance(recipient, version);
uint256 spareAmount = fund.trancheBalanceOf(tranche, address(this)).sub(oldTotalSupply);
if (spareAmount < amount) {
fund.trancheTransferFrom(
tranche,
msg.sender,
address(this),
amount - spareAmount,
version
);
} else {
require(version == _fundRebalanceSize(), "Invalid version");
}
emit Deposited(tranche, recipient, amount);
}
function withdraw(
uint256 tranche,
uint256 amount,
uint256 version
) external {
_checkpoint(version);
_userCheckpoint(msg.sender, version);
_balances[msg.sender][tranche] = _balances[msg.sender][tranche].sub(
amount,
"Insufficient balance to withdraw"
);
_totalSupplies[tranche] = _totalSupplies[tranche].sub(amount);
_updateWorkingBalance(msg.sender, version);
fund.trancheTransfer(tranche, msg.sender, amount, version);
emit Withdrawn(tranche, msg.sender, amount);
}
function refreshBalance(address account, uint256 targetVersion) external {
uint256 rebalanceSize = _fundRebalanceSize();
if (targetVersion == 0) {
targetVersion = rebalanceSize;
} else {
require(targetVersion <= rebalanceSize, "Target version out of bound");
}
_checkpoint(rebalanceSize);
_userCheckpoint(account, targetVersion);
}
function claimableRewards(address account) external returns (uint256) {
uint256 rebalanceSize = _fundRebalanceSize();
_checkpoint(rebalanceSize);
_userCheckpoint(account, rebalanceSize);
return _claimableRewards[account];
}
function claimRewards(address account) external {
uint256 rebalanceSize = _fundRebalanceSize();
_checkpoint(rebalanceSize);
_userCheckpoint(account, rebalanceSize);
uint256 amount = _claimableRewards[account];
_claimableRewards[account] = 0;
chessSchedule.mint(account, amount);
_updateWorkingBalance(account, rebalanceSize);
}
function syncWithVotingEscrow(address account) external {
uint256 rebalanceSize = _fundRebalanceSize();
_checkpoint(rebalanceSize);
_userCheckpoint(account, rebalanceSize);
_updateWorkingBalance(account, rebalanceSize);
}
function _checkpoint(uint256 rebalanceSize) private {
uint256 timestamp = _checkpointTimestamp;
if (timestamp >= block.timestamp) {
return;
}
uint256 integral = _invTotalWeightIntegral;
uint256 endWeek = _endOfWeek(timestamp);
uint256 version = _totalSupplyVersion;
uint256 rebalanceTimestamp;
if (version < rebalanceSize) {
rebalanceTimestamp = fund.getRebalanceTimestamp(version);
} else {
rebalanceTimestamp = type(uint256).max;
}
uint256 rate = _rate;
uint256 totalSupplyQ = _totalSupplies[TRANCHE_Q];
uint256 totalSupplyB = _totalSupplies[TRANCHE_B];
uint256 totalSupplyR = _totalSupplies[TRANCHE_R];
uint256 weight = _workingSupply;
uint256 timestamp_ = timestamp;
for (uint256 i = 0; i < MAX_ITERATIONS && timestamp_ < block.timestamp; i++) {
uint256 endTimestamp = rebalanceTimestamp.min(endWeek).min(block.timestamp);
if (weight > 0 && endTimestamp > rewardStartTimestamp) {
integral = integral.add(
rate
.mul(endTimestamp.sub(timestamp_.max(rewardStartTimestamp)))
.decimalToPreciseDecimal()
.div(weight)
);
}
if (endTimestamp == rebalanceTimestamp) {
uint256 oldSize = _historicalIntegralSize;
_historicalIntegrals[oldSize] = integral;
_historicalIntegralSize = oldSize + 1;
integral = 0;
(totalSupplyQ, totalSupplyB, totalSupplyR) = _fundDoRebalance(
totalSupplyQ,
totalSupplyB,
totalSupplyR,
version
);
version++;
{
uint256 splitRatio = fund.historicalSplitRatio(version);
weight = weightedBalance(totalSupplyQ, totalSupplyB, totalSupplyR, splitRatio);
_historicalSplitRatio[version] = splitRatio;
}
if (version < rebalanceSize) {
rebalanceTimestamp = fund.getRebalanceTimestamp(version);
} else {
rebalanceTimestamp = type(uint256).max;
}
}
if (endTimestamp == endWeek) {
rate = chessSchedule.getRate(endWeek).mul(
chessController.getFundRelativeWeight(address(this), endWeek)
);
if (endWeek < rewardStartTimestamp && endWeek + 1 weeks > rewardStartTimestamp) {
rate = rate.mul(1 weeks).div(endWeek + 1 weeks - rewardStartTimestamp);
}
endWeek += 1 weeks;
}
timestamp_ = endTimestamp;
}
_checkpointTimestamp = block.timestamp;
_invTotalWeightIntegral = integral;
_rate = rate;
if (_totalSupplyVersion != rebalanceSize) {
_totalSupplies[TRANCHE_Q] = totalSupplyQ;
_totalSupplies[TRANCHE_B] = totalSupplyB;
_totalSupplies[TRANCHE_R] = totalSupplyR;
_totalSupplyVersion = rebalanceSize;
_workingSupply = weight;
}
}
function _userCheckpoint(address account, uint256 targetVersion) private {
uint256 oldVersion = _balanceVersions[account];
if (oldVersion > targetVersion) {
return;
}
uint256 userIntegral = _userIntegrals[account];
uint256 integral;
{
uint256 rebalanceSize = _historicalIntegralSize;
integral = targetVersion == rebalanceSize
? _invTotalWeightIntegral
: _historicalIntegrals[targetVersion];
}
if (userIntegral == integral && oldVersion == targetVersion) {
return;
}
uint256 rewards = _claimableRewards[account];
uint256[TRANCHE_COUNT] storage balance = _balances[account];
uint256 weight = _workingBalances[account];
uint256 balanceQ = balance[TRANCHE_Q];
uint256 balanceB = balance[TRANCHE_B];
uint256 balanceR = balance[TRANCHE_R];
for (uint256 i = oldVersion; i < targetVersion; i++) {
rewards = rewards.add(
weight.multiplyDecimalPrecise(_historicalIntegrals[i].sub(userIntegral))
);
if (balanceQ != 0 || balanceB != 0 || balanceR != 0) {
(balanceQ, balanceB, balanceR) = _fundDoRebalance(balanceQ, balanceB, balanceR, i);
}
userIntegral = 0;
weight = weightedBalance(balanceQ, balanceB, balanceR, _historicalSplitRatio[i + 1]);
}
rewards = rewards.add(weight.multiplyDecimalPrecise(integral.sub(userIntegral)));
address account_ = account;
_claimableRewards[account_] = rewards;
_userIntegrals[account_] = integral;
if (oldVersion < targetVersion) {
balance[TRANCHE_Q] = balanceQ;
balance[TRANCHE_B] = balanceB;
balance[TRANCHE_R] = balanceR;
_balanceVersions[account_] = targetVersion;
_workingBalances[account_] = weight;
}
}
function _updateWorkingBalance(address account, uint256 rebalanceSize) private {
uint256 splitRatio = _historicalSplitRatio[rebalanceSize];
if (splitRatio == 0) {
splitRatio = fund.historicalSplitRatio(rebalanceSize);
_historicalSplitRatio[rebalanceSize] = splitRatio;
}
uint256 weightedSupply =
weightedBalance(
_totalSupplies[TRANCHE_Q],
_totalSupplies[TRANCHE_B],
_totalSupplies[TRANCHE_R],
splitRatio
);
uint256[TRANCHE_COUNT] storage balance = _balances[account];
uint256 newWorkingBalance =
weightedBalance(balance[TRANCHE_Q], balance[TRANCHE_B], balance[TRANCHE_R], splitRatio);
uint256 veBalance = _votingEscrow.balanceOf(account);
if (veBalance > 0) {
uint256 veTotalSupply = _votingEscrow.totalSupply();
uint256 maxWorkingBalance = newWorkingBalance.multiplyDecimal(MAX_BOOSTING_FACTOR);
uint256 boostedWorkingBalance =
newWorkingBalance.add(
weightedSupply
.mul(veBalance)
.multiplyDecimal(MAX_BOOSTING_FACTOR_MINUS_ONE)
.div(veTotalSupply)
);
newWorkingBalance = maxWorkingBalance.min(boostedWorkingBalance);
}
_workingSupply = _workingSupply.sub(_workingBalances[account]).add(newWorkingBalance);
_workingBalances[account] = newWorkingBalance;
}
}
{
"compilationTarget": {
"contracts/fund/PrimaryMarketRouter.sol": "PrimaryMarketRouter"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"pm","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"baseOut","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"buy","outputs":[{"internalType":"uint256","name":"realBaseOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"underlying","type":"uint256"},{"internalType":"uint256","name":"minOutQ","type":"uint256"},{"internalType":"uint256","name":"version","type":"uint256"}],"name":"create","outputs":[{"internalType":"uint256","name":"outQ","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlying","type":"uint256"},{"internalType":"uint256","name":"minOutQ","type":"uint256"},{"internalType":"address","name":"staking","type":"address"},{"internalType":"uint256","name":"version","type":"uint256"}],"name":"createAndStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlying","type":"uint256"},{"internalType":"uint256","name":"minOutQ","type":"uint256"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"quoteAddress","type":"address"},{"internalType":"uint256","name":"minLpOut","type":"uint256"},{"internalType":"address","name":"staking","type":"address"},{"internalType":"uint256","name":"version","type":"uint256"}],"name":"createSplitAndStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fund","outputs":[{"internalType":"contract IFundV3","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quoteOut","type":"uint256"}],"name":"getBaseIn","outputs":[{"internalType":"uint256","name":"baseIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quoteIn","type":"uint256"}],"name":"getBaseOut","outputs":[{"internalType":"uint256","name":"baseOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseOut","type":"uint256"}],"name":"getQuoteIn","outputs":[{"internalType":"uint256","name":"quoteIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseIn","type":"uint256"}],"name":"getQuoteOut","outputs":[{"internalType":"uint256","name":"quoteOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primaryMarket","outputs":[{"internalType":"contract IPrimaryMarketV3","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"quoteOut","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"sell","outputs":[{"internalType":"uint256","name":"realQuoteOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"inQ","type":"uint256"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"quoteAddress","type":"address"},{"internalType":"uint256","name":"minLpOut","type":"uint256"},{"internalType":"address","name":"staking","type":"address"},{"internalType":"uint256","name":"version","type":"uint256"}],"name":"splitAndStake","outputs":[],"stateMutability":"nonpayable","type":"function"}]