Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 133 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Bidder Claim | 18984535 | 299 days ago | IN | 0 ETH | 0.00497495 | ||||
Bidder Claim | 18624968 | 350 days ago | IN | 0 ETH | 0.00249144 | ||||
Bidder Claim | 18519034 | 365 days ago | IN | 0 ETH | 0.00182073 | ||||
Bidder Claim | 17468470 | 512 days ago | IN | 0 ETH | 0.00095236 | ||||
Bidder Claim | 17459496 | 513 days ago | IN | 0 ETH | 0.00133001 | ||||
Bidder Claim | 17172844 | 553 days ago | IN | 0 ETH | 0.00544809 | ||||
Bidder Claim | 16989039 | 580 days ago | IN | 0 ETH | 0.00206255 | ||||
Bidder Claim | 16946275 | 586 days ago | IN | 0 ETH | 0.0017015 | ||||
Bidder Claim | 16931604 | 588 days ago | IN | 0 ETH | 0.00200988 | ||||
Bidder Claim | 16925031 | 589 days ago | IN | 0 ETH | 0.00159482 | ||||
Bidder Claim | 16922458 | 589 days ago | IN | 0 ETH | 0.00153635 | ||||
Bidder Claim | 16879979 | 595 days ago | IN | 0 ETH | 0.00098911 | ||||
Bidder Claim | 16574246 | 638 days ago | IN | 0 ETH | 0.00212722 | ||||
Bidder Claim | 16558568 | 640 days ago | IN | 0 ETH | 0.00146741 | ||||
Bidder Claim | 16494767 | 649 days ago | IN | 0 ETH | 0.0011692 | ||||
Bidder Claim | 16322928 | 673 days ago | IN | 0 ETH | 0.00122957 | ||||
Bidder Claim | 16222248 | 687 days ago | IN | 0 ETH | 0.00126778 | ||||
Bidder Claim | 16222245 | 687 days ago | IN | 0 ETH | 0.00129341 | ||||
Bidder Claim | 16222242 | 687 days ago | IN | 0 ETH | 0.00128989 | ||||
Bidder Claim | 16222239 | 687 days ago | IN | 0 ETH | 0.00130858 | ||||
Bidder Claim | 16222236 | 687 days ago | IN | 0 ETH | 0.0012822 | ||||
Bidder Claim | 16222233 | 687 days ago | IN | 0 ETH | 0.00127821 | ||||
Bidder Claim | 16222230 | 687 days ago | IN | 0 ETH | 0.00131787 | ||||
Bidder Claim | 16222218 | 687 days ago | IN | 0 ETH | 0.00138162 | ||||
Bidder Claim | 16222215 | 687 days ago | IN | 0 ETH | 0.00141545 |
Loading...
Loading
Minimal Proxy Contract for 0xa5543cb8d946515947205f22a8ebd351fc801985
Contract Name:
CP
Compiler Version
v0.6.9+commit.3e3065ac
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-12-30 */ // File: contracts/lib/SafeMath.sol /* Copyright 2021 DODO ZOO. SPDX-License-Identifier: Apache-2.0 */ pragma solidity 0.6.9; pragma experimental ABIEncoderV2; /** * @title SafeMath * @author DODO Breeder * * @notice Math operations with safety checks that revert on error */ library SafeMath { function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "MUL_ERROR"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "DIVIDING_ERROR"); return a / b; } function divCeil(uint256 a, uint256 b) internal pure returns (uint256) { uint256 quotient = div(a, b); uint256 remainder = a - quotient * b; if (remainder > 0) { return quotient + 1; } else { return quotient; } } function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SUB_ERROR"); return a - b; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "ADD_ERROR"); return c; } function sqrt(uint256 x) internal pure returns (uint256 y) { uint256 z = x / 2 + 1; y = x; while (z < y) { y = z; z = (x / z + z) / 2; } } } // File: contracts/lib/DecimalMath.sol /** * @title DecimalMath * @author DODO Breeder * * @notice Functions for fixed point number with 18 decimals */ library DecimalMath { using SafeMath for uint256; uint256 internal constant ONE = 10**18; uint256 internal constant ONE2 = 10**36; function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) { return target.mul(d) / (10**18); } function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) { return target.mul(d).divCeil(10**18); } function divFloor(uint256 target, uint256 d) internal pure returns (uint256) { return target.mul(10**18).div(d); } function divCeil(uint256 target, uint256 d) internal pure returns (uint256) { return target.mul(10**18).divCeil(d); } function reciprocalFloor(uint256 target) internal pure returns (uint256) { return uint256(10**36).div(target); } function reciprocalCeil(uint256 target) internal pure returns (uint256) { return uint256(10**36).divCeil(target); } function powFloor(uint256 target, uint256 e) internal pure returns (uint256) { if (e == 0) { return 10 ** 18; } else if (e == 1) { return target; } else { uint p = powFloor(target, e.div(2)); p = p.mul(p) / (10**18); if (e % 2 == 1) { p = p.mul(target) / (10**18); } return p; } } } // File: contracts/lib/Ownable.sol /** * @title Ownable * @author DODO Breeder * * @notice Ownership related functions */ contract Ownable { address public _OWNER_; address public _NEW_OWNER_; // ============ Events ============ event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // ============ Modifiers ============ modifier onlyOwner() { require(msg.sender == _OWNER_, "NOT_OWNER"); _; } // ============ Functions ============ constructor() internal { _OWNER_ = msg.sender; emit OwnershipTransferred(address(0), _OWNER_); } function transferOwnership(address newOwner) external virtual onlyOwner { emit OwnershipTransferPrepared(_OWNER_, newOwner); _NEW_OWNER_ = newOwner; } function claimOwnership() external { require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM"); emit OwnershipTransferred(_OWNER_, _NEW_OWNER_); _OWNER_ = _NEW_OWNER_; _NEW_OWNER_ = address(0); } } // File: contracts/intf/IERC20.sol /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); function decimals() external view returns (uint8); function name() external view returns (string memory); function symbol() external view returns (string memory); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); } // File: contracts/lib/SafeERC20.sol /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; 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 { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length 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)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: contracts/DODOVendingMachine/intf/IDVM.sol interface IDVM { function init( address maintainer, address baseTokenAddress, address quoteTokenAddress, uint256 lpFeeRate, address mtFeeRateModel, uint256 i, uint256 k, bool isOpenTWAP ) external; function _BASE_TOKEN_() external returns (address); function _QUOTE_TOKEN_() external returns (address); function _MT_FEE_RATE_MODEL_() external returns (address); function getVaultReserve() external returns (uint256 baseReserve, uint256 quoteReserve); function sellBase(address to) external returns (uint256); function sellQuote(address to) external returns (uint256); function buyShares(address to) external returns (uint256,uint256,uint256); function addressToShortString(address _addr) external pure returns (string memory); function getMidPrice() external view returns (uint256 midPrice); function sellShares( uint256 shareAmount, address to, uint256 baseMinAmount, uint256 quoteMinAmount, bytes calldata data, uint256 deadline ) external returns (uint256 baseAmount, uint256 quoteAmount); } // File: contracts/lib/InitializableOwnable.sol /** * @title Ownable * @author DODO Breeder * * @notice Ownership related functions */ contract InitializableOwnable { address public _OWNER_; address public _NEW_OWNER_; bool internal _INITIALIZED_; // ============ Events ============ event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // ============ Modifiers ============ modifier notInitialized() { require(!_INITIALIZED_, "DODO_INITIALIZED"); _; } modifier onlyOwner() { require(msg.sender == _OWNER_, "NOT_OWNER"); _; } // ============ Functions ============ function initOwner(address newOwner) public notInitialized { _INITIALIZED_ = true; _OWNER_ = newOwner; } function transferOwnership(address newOwner) public onlyOwner { emit OwnershipTransferPrepared(_OWNER_, newOwner); _NEW_OWNER_ = newOwner; } function claimOwnership() public { require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM"); emit OwnershipTransferred(_OWNER_, _NEW_OWNER_); _OWNER_ = _NEW_OWNER_; _NEW_OWNER_ = address(0); } } // File: contracts/lib/CloneFactory.sol interface ICloneFactory { function clone(address prototype) external returns (address proxy); } // introduction of proxy mode design: https://docs.openzeppelin.com/upgrades/2.8/ // minimum implementation of transparent proxy: https://eips.ethereum.org/EIPS/eip-1167 contract CloneFactory is ICloneFactory { function clone(address prototype) external override returns (address proxy) { bytes20 targetBytes = bytes20(prototype); assembly { let clone := mload(0x40) mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(clone, 0x14), targetBytes) mstore( add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 ) proxy := create(0, clone, 0x37) } return proxy; } } // File: contracts/Factory/DVMFactory.sol interface IDVMFactory { function createDODOVendingMachine( address baseToken, address quoteToken, uint256 lpFeeRate, uint256 i, uint256 k, bool isOpenTWAP ) external returns (address newVendingMachine); } /** * @title DODO VendingMachine Factory * @author DODO Breeder * * @notice Create And Register DVM Pools */ contract DVMFactory is InitializableOwnable { // ============ Templates ============ address public immutable _CLONE_FACTORY_; address public immutable _DEFAULT_MT_FEE_RATE_MODEL_; address public _DEFAULT_MAINTAINER_; address public _DVM_TEMPLATE_; // ============ Registry ============ // base -> quote -> DVM address list mapping(address => mapping(address => address[])) public _REGISTRY_; // creator -> DVM address list mapping(address => address[]) public _USER_REGISTRY_; // ============ Events ============ event NewDVM( address baseToken, address quoteToken, address creator, address dvm ); event RemoveDVM(address dvm); // ============ Functions ============ constructor( address cloneFactory, address dvmTemplate, address defaultMaintainer, address defaultMtFeeRateModel ) public { _CLONE_FACTORY_ = cloneFactory; _DVM_TEMPLATE_ = dvmTemplate; _DEFAULT_MAINTAINER_ = defaultMaintainer; _DEFAULT_MT_FEE_RATE_MODEL_ = defaultMtFeeRateModel; } function createDODOVendingMachine( address baseToken, address quoteToken, uint256 lpFeeRate, uint256 i, uint256 k, bool isOpenTWAP ) external returns (address newVendingMachine) { newVendingMachine = ICloneFactory(_CLONE_FACTORY_).clone(_DVM_TEMPLATE_); { IDVM(newVendingMachine).init( _DEFAULT_MAINTAINER_, baseToken, quoteToken, lpFeeRate, _DEFAULT_MT_FEE_RATE_MODEL_, i, k, isOpenTWAP ); } _REGISTRY_[baseToken][quoteToken].push(newVendingMachine); _USER_REGISTRY_[tx.origin].push(newVendingMachine); emit NewDVM(baseToken, quoteToken, tx.origin, newVendingMachine); } // ============ Admin Operation Functions ============ function updateDvmTemplate(address _newDVMTemplate) external onlyOwner { _DVM_TEMPLATE_ = _newDVMTemplate; } function updateDefaultMaintainer(address _newMaintainer) external onlyOwner { _DEFAULT_MAINTAINER_ = _newMaintainer; } function addPoolByAdmin( address creator, address baseToken, address quoteToken, address pool ) external onlyOwner { _REGISTRY_[baseToken][quoteToken].push(pool); _USER_REGISTRY_[creator].push(pool); emit NewDVM(baseToken, quoteToken, creator, pool); } function removePoolByAdmin( address creator, address baseToken, address quoteToken, address pool ) external onlyOwner { address[] memory registryList = _REGISTRY_[baseToken][quoteToken]; for (uint256 i = 0; i < registryList.length; i++) { if (registryList[i] == pool) { registryList[i] = registryList[registryList.length - 1]; break; } } _REGISTRY_[baseToken][quoteToken] = registryList; _REGISTRY_[baseToken][quoteToken].pop(); address[] memory userRegistryList = _USER_REGISTRY_[creator]; for (uint256 i = 0; i < userRegistryList.length; i++) { if (userRegistryList[i] == pool) { userRegistryList[i] = userRegistryList[userRegistryList.length - 1]; break; } } _USER_REGISTRY_[creator] = userRegistryList; _USER_REGISTRY_[creator].pop(); emit RemoveDVM(pool); } // ============ View Functions ============ function getDODOPool(address baseToken, address quoteToken) external view returns (address[] memory machines) { return _REGISTRY_[baseToken][quoteToken]; } function getDODOPoolBidirection(address token0, address token1) external view returns (address[] memory baseToken0Machines, address[] memory baseToken1Machines) { return (_REGISTRY_[token0][token1], _REGISTRY_[token1][token0]); } function getDODOPoolByUser(address user) external view returns (address[] memory machines) { return _USER_REGISTRY_[user]; } } // File: contracts/lib/ReentrancyGuard.sol /** * @title ReentrancyGuard * @author DODO Breeder * * @notice Protect functions from Reentrancy Attack */ contract ReentrancyGuard { // https://solidity.readthedocs.io/en/latest/control-structures.html?highlight=zero-state#scoping-and-declarations // zero-state of _ENTERED_ is false bool private _ENTERED_; modifier preventReentrant() { require(!_ENTERED_, "REENTRANT"); _ENTERED_ = true; _; _ENTERED_ = false; } } // File: contracts/lib/PermissionManager.sol interface IPermissionManager { function initOwner(address) external; function isAllowed(address) external view returns (bool); } contract PermissionManager is InitializableOwnable { bool public _WHITELIST_MODE_ON_; mapping(address => bool) internal _whitelist_; mapping(address => bool) internal _blacklist_; function isAllowed(address account) external view returns (bool) { if (_WHITELIST_MODE_ON_) { return _whitelist_[account]; } else { return !_blacklist_[account]; } } function openBlacklistMode() external onlyOwner { _WHITELIST_MODE_ON_ = false; } function openWhitelistMode() external onlyOwner { _WHITELIST_MODE_ON_ = true; } function addToWhitelist(address account) external onlyOwner { _whitelist_[account] = true; } function removeFromWhitelist(address account) external onlyOwner { _whitelist_[account] = false; } function addToBlacklist(address account) external onlyOwner { _blacklist_[account] = true; } function removeFromBlacklist(address account) external onlyOwner { _blacklist_[account] = false; } } // File: contracts/lib/FeeRateModel.sol interface IFeeRateImpl { function getFeeRate(address pool, address trader) external view returns (uint256); } interface IFeeRateModel { function getFeeRate(address trader) external view returns (uint256); } contract FeeRateModel is InitializableOwnable { address public feeRateImpl; function setFeeProxy(address _feeRateImpl) public onlyOwner { feeRateImpl = _feeRateImpl; } function getFeeRate(address trader) external view returns (uint256) { if(feeRateImpl == address(0)) return 0; return IFeeRateImpl(feeRateImpl).getFeeRate(msg.sender,trader); } } // File: contracts/CrowdPooling/impl/CPStorage.sol contract CPStorage is InitializableOwnable, ReentrancyGuard { using SafeMath for uint256; // ============ Constant ============ uint256 internal constant _SETTLEMENT_EXPIRE_ = 86400 * 7; uint256 internal constant _SETTEL_FUND_ = 200 finney; bool public _IS_OPEN_TWAP_ = false; bool public _IS_OVERCAP_STOP = false; bool public _FORCE_STOP_ = false; // ============ Timeline ============ uint256 public _PHASE_BID_STARTTIME_; uint256 public _PHASE_BID_ENDTIME_; uint256 public _PHASE_CALM_ENDTIME_; uint256 public _SETTLED_TIME_; bool public _SETTLED_; // ============ Core Address ============ IERC20 public _BASE_TOKEN_; IERC20 public _QUOTE_TOKEN_; // ============ Distribution Parameters ============ uint256 public _TOTAL_BASE_; uint256 public _POOL_QUOTE_CAP_; // ============ Settlement ============ uint256 public _QUOTE_RESERVE_; uint256 public _UNUSED_BASE_; uint256 public _UNUSED_QUOTE_; uint256 public _TOTAL_SHARES_; mapping(address => uint256) internal _SHARES_; mapping(address => bool) public _CLAIMED_QUOTE_; address public _POOL_FACTORY_; address public _POOL_; uint256 public _POOL_FEE_RATE_; uint256 public _AVG_SETTLED_PRICE_; // ============ Advanced Control ============ address public _MAINTAINER_; IFeeRateModel public _MT_FEE_RATE_MODEL_; IPermissionManager public _BIDDER_PERMISSION_; // ============ PMM Parameters ============ uint256 public _K_; uint256 public _I_; // ============ LP Token Vesting && Claim Params ============ uint256 public _TOTAL_LP_AMOUNT_; uint256 public _FREEZE_DURATION_; uint256 public _VESTING_DURATION_; uint256 public _CLIFF_RATE_; uint256 public _TOKEN_CLAIM_DURATION_; uint256 public _TOKEN_VESTING_DURATION_; uint256 public _TOKEN_CLIFF_RATE_; mapping(address => uint256) public _CLAIMED_BASE_TOKEN_; // ============ Modifiers ============ modifier isNotForceStop() { require(!_FORCE_STOP_, "FORCE_STOP"); _; } modifier phaseBid() { require( block.timestamp >= _PHASE_BID_STARTTIME_ && block.timestamp < _PHASE_BID_ENDTIME_, "NOT_PHASE_BID" ); _; } modifier phaseCalm() { require( block.timestamp >= _PHASE_BID_ENDTIME_ && block.timestamp < _PHASE_CALM_ENDTIME_, "NOT_PHASE_CALM" ); _; } modifier phaseBidOrCalm() { require( block.timestamp >= _PHASE_BID_STARTTIME_ && block.timestamp < _PHASE_CALM_ENDTIME_, "NOT_PHASE_BID_OR_CALM" ); _; } modifier phaseSettlement() { require(block.timestamp >= _PHASE_CALM_ENDTIME_, "NOT_PHASE_EXE"); _; } modifier phaseVesting() { require(_SETTLED_, "NOT_VESTING"); _; } function forceStop() external onlyOwner { require(block.timestamp < _PHASE_BID_STARTTIME_, "CP_ALREADY_STARTED"); _FORCE_STOP_ = true; _TOTAL_BASE_ = 0; uint256 baseAmount = _BASE_TOKEN_.balanceOf(address(this)); _BASE_TOKEN_.transfer(_OWNER_, baseAmount); } } // File: contracts/lib/DODOMath.sol /** * @title DODOMath * @author DODO Breeder * * @notice Functions for complex calculating. Including ONE Integration and TWO Quadratic solutions */ library DODOMath { using SafeMath for uint256; /* Integrate dodo curve from V1 to V2 require V0>=V1>=V2>0 res = (1-k)i(V1-V2)+ikV0*V0(1/V2-1/V1) let V1-V2=delta res = i*delta*(1-k+k(V0^2/V1/V2)) i is the price of V-res trading pair support k=1 & k=0 case [round down] */ function _GeneralIntegrate( uint256 V0, uint256 V1, uint256 V2, uint256 i, uint256 k ) internal pure returns (uint256) { require(V0 > 0, "TARGET_IS_ZERO"); uint256 fairAmount = i.mul(V1.sub(V2)); // i*delta if (k == 0) { return fairAmount.div(DecimalMath.ONE); } uint256 V0V0V1V2 = DecimalMath.divFloor(V0.mul(V0).div(V1), V2); uint256 penalty = DecimalMath.mulFloor(k, V0V0V1V2); // k(V0^2/V1/V2) return DecimalMath.ONE.sub(k).add(penalty).mul(fairAmount).div(DecimalMath.ONE2); } /* Follow the integration function above i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2) Assume Q2=Q0, Given Q1 and deltaB, solve Q0 i is the price of delta-V trading pair give out target of V support k=1 & k=0 case [round down] */ function _SolveQuadraticFunctionForTarget( uint256 V1, uint256 delta, uint256 i, uint256 k ) internal pure returns (uint256) { if (V1 == 0) { return 0; } if (k == 0) { return V1.add(DecimalMath.mulFloor(i, delta)); } // V0 = V1*(1+(sqrt-1)/2k) // sqrt = √(1+4kidelta/V1) // premium = 1+(sqrt-1)/2k // uint256 sqrt = (4 * k).mul(i).mul(delta).div(V1).add(DecimalMath.ONE2).sqrt(); uint256 sqrt; uint256 ki = (4 * k).mul(i); if (ki == 0) { sqrt = DecimalMath.ONE; } else if ((ki * delta) / ki == delta) { sqrt = (ki * delta).div(V1).add(DecimalMath.ONE2).sqrt(); } else { sqrt = ki.div(V1).mul(delta).add(DecimalMath.ONE2).sqrt(); } uint256 premium = DecimalMath.divFloor(sqrt.sub(DecimalMath.ONE), k * 2).add(DecimalMath.ONE); // V0 is greater than or equal to V1 according to the solution return DecimalMath.mulFloor(V1, premium); } /* Follow the integration expression above, we have: i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2) Given Q1 and deltaB, solve Q2 This is a quadratic function and the standard version is aQ2^2 + bQ2 + c = 0, where a=1-k -b=(1-k)Q1-kQ0^2/Q1+i*deltaB c=-kQ0^2 and Q2=(-b+sqrt(b^2+4(1-k)kQ0^2))/2(1-k) note: another root is negative, abondan if deltaBSig=true, then Q2>Q1, user sell Q and receive B if deltaBSig=false, then Q2<Q1, user sell B and receive Q return |Q1-Q2| as we only support sell amount as delta, the deltaB is always negative the input ideltaB is actually -ideltaB in the equation i is the price of delta-V trading pair support k=1 & k=0 case [round down] */ function _SolveQuadraticFunctionForTrade( uint256 V0, uint256 V1, uint256 delta, uint256 i, uint256 k ) internal pure returns (uint256) { require(V0 > 0, "TARGET_IS_ZERO"); if (delta == 0) { return 0; } if (k == 0) { return DecimalMath.mulFloor(i, delta) > V1 ? V1 : DecimalMath.mulFloor(i, delta); } if (k == DecimalMath.ONE) { // if k==1 // Q2=Q1/(1+ideltaBQ1/Q0/Q0) // temp = ideltaBQ1/Q0/Q0 // Q2 = Q1/(1+temp) // Q1-Q2 = Q1*(1-1/(1+temp)) = Q1*(temp/(1+temp)) // uint256 temp = i.mul(delta).mul(V1).div(V0.mul(V0)); uint256 temp; uint256 idelta = i.mul(delta); if (idelta == 0) { temp = 0; } else if ((idelta * V1) / idelta == V1) { temp = (idelta * V1).div(V0.mul(V0)); } else { temp = delta.mul(V1).div(V0).mul(i).div(V0); } return V1.mul(temp).div(temp.add(DecimalMath.ONE)); } // calculate -b value and sig // b = kQ0^2/Q1-i*deltaB-(1-k)Q1 // part1 = (1-k)Q1 >=0 // part2 = kQ0^2/Q1-i*deltaB >=0 // bAbs = abs(part1-part2) // if part1>part2 => b is negative => bSig is false // if part2>part1 => b is positive => bSig is true uint256 part2 = k.mul(V0).div(V1).mul(V0).add(i.mul(delta)); // kQ0^2/Q1-i*deltaB uint256 bAbs = DecimalMath.ONE.sub(k).mul(V1); // (1-k)Q1 bool bSig; if (bAbs >= part2) { bAbs = bAbs - part2; bSig = false; } else { bAbs = part2 - bAbs; bSig = true; } bAbs = bAbs.div(DecimalMath.ONE); // calculate sqrt uint256 squareRoot = DecimalMath.mulFloor( DecimalMath.ONE.sub(k).mul(4), DecimalMath.mulFloor(k, V0).mul(V0) ); // 4(1-k)kQ0^2 squareRoot = bAbs.mul(bAbs).add(squareRoot).sqrt(); // sqrt(b*b+4(1-k)kQ0*Q0) // final res uint256 denominator = DecimalMath.ONE.sub(k).mul(2); // 2(1-k) uint256 numerator; if (bSig) { numerator = squareRoot.sub(bAbs); } else { numerator = bAbs.add(squareRoot); } uint256 V2 = DecimalMath.divCeil(numerator, denominator); if (V2 > V1) { return 0; } else { return V1 - V2; } } } // File: contracts/lib/PMMPricing.sol /** * @title Pricing * @author DODO Breeder * * @notice DODO Pricing model */ library PMMPricing { using SafeMath for uint256; enum RState {ONE, ABOVE_ONE, BELOW_ONE} struct PMMState { uint256 i; uint256 K; uint256 B; uint256 Q; uint256 B0; uint256 Q0; RState R; } // ============ buy & sell ============ function sellBaseToken(PMMState memory state, uint256 payBaseAmount) internal pure returns (uint256 receiveQuoteAmount, RState newR) { if (state.R == RState.ONE) { // case 1: R=1 // R falls below one receiveQuoteAmount = _ROneSellBaseToken(state, payBaseAmount); newR = RState.BELOW_ONE; } else if (state.R == RState.ABOVE_ONE) { uint256 backToOnePayBase = state.B0.sub(state.B); uint256 backToOneReceiveQuote = state.Q.sub(state.Q0); // case 2: R>1 // complex case, R status depends on trading amount if (payBaseAmount < backToOnePayBase) { // case 2.1: R status do not change receiveQuoteAmount = _RAboveSellBaseToken(state, payBaseAmount); newR = RState.ABOVE_ONE; if (receiveQuoteAmount > backToOneReceiveQuote) { // [Important corner case!] may enter this branch when some precision problem happens. And consequently contribute to negative spare quote amount // to make sure spare quote>=0, mannually set receiveQuote=backToOneReceiveQuote receiveQuoteAmount = backToOneReceiveQuote; } } else if (payBaseAmount == backToOnePayBase) { // case 2.2: R status changes to ONE receiveQuoteAmount = backToOneReceiveQuote; newR = RState.ONE; } else { // case 2.3: R status changes to BELOW_ONE receiveQuoteAmount = backToOneReceiveQuote.add( _ROneSellBaseToken(state, payBaseAmount.sub(backToOnePayBase)) ); newR = RState.BELOW_ONE; } } else { // state.R == RState.BELOW_ONE // case 3: R<1 receiveQuoteAmount = _RBelowSellBaseToken(state, payBaseAmount); newR = RState.BELOW_ONE; } } function sellQuoteToken(PMMState memory state, uint256 payQuoteAmount) internal pure returns (uint256 receiveBaseAmount, RState newR) { if (state.R == RState.ONE) { receiveBaseAmount = _ROneSellQuoteToken(state, payQuoteAmount); newR = RState.ABOVE_ONE; } else if (state.R == RState.ABOVE_ONE) { receiveBaseAmount = _RAboveSellQuoteToken(state, payQuoteAmount); newR = RState.ABOVE_ONE; } else { uint256 backToOnePayQuote = state.Q0.sub(state.Q); uint256 backToOneReceiveBase = state.B.sub(state.B0); if (payQuoteAmount < backToOnePayQuote) { receiveBaseAmount = _RBelowSellQuoteToken(state, payQuoteAmount); newR = RState.BELOW_ONE; if (receiveBaseAmount > backToOneReceiveBase) { receiveBaseAmount = backToOneReceiveBase; } } else if (payQuoteAmount == backToOnePayQuote) { receiveBaseAmount = backToOneReceiveBase; newR = RState.ONE; } else { receiveBaseAmount = backToOneReceiveBase.add( _ROneSellQuoteToken(state, payQuoteAmount.sub(backToOnePayQuote)) ); newR = RState.ABOVE_ONE; } } } // ============ R = 1 cases ============ function _ROneSellBaseToken(PMMState memory state, uint256 payBaseAmount) internal pure returns ( uint256 // receiveQuoteToken ) { // in theory Q2 <= targetQuoteTokenAmount // however when amount is close to 0, precision problems may cause Q2 > targetQuoteTokenAmount return DODOMath._SolveQuadraticFunctionForTrade( state.Q0, state.Q0, payBaseAmount, state.i, state.K ); } function _ROneSellQuoteToken(PMMState memory state, uint256 payQuoteAmount) internal pure returns ( uint256 // receiveBaseToken ) { return DODOMath._SolveQuadraticFunctionForTrade( state.B0, state.B0, payQuoteAmount, DecimalMath.reciprocalFloor(state.i), state.K ); } // ============ R < 1 cases ============ function _RBelowSellQuoteToken(PMMState memory state, uint256 payQuoteAmount) internal pure returns ( uint256 // receiveBaseToken ) { return DODOMath._GeneralIntegrate( state.Q0, state.Q.add(payQuoteAmount), state.Q, DecimalMath.reciprocalFloor(state.i), state.K ); } function _RBelowSellBaseToken(PMMState memory state, uint256 payBaseAmount) internal pure returns ( uint256 // receiveQuoteToken ) { return DODOMath._SolveQuadraticFunctionForTrade( state.Q0, state.Q, payBaseAmount, state.i, state.K ); } // ============ R > 1 cases ============ function _RAboveSellBaseToken(PMMState memory state, uint256 payBaseAmount) internal pure returns ( uint256 // receiveQuoteToken ) { return DODOMath._GeneralIntegrate( state.B0, state.B.add(payBaseAmount), state.B, state.i, state.K ); } function _RAboveSellQuoteToken(PMMState memory state, uint256 payQuoteAmount) internal pure returns ( uint256 // receiveBaseToken ) { return DODOMath._SolveQuadraticFunctionForTrade( state.B0, state.B, payQuoteAmount, DecimalMath.reciprocalFloor(state.i), state.K ); } // ============ Helper functions ============ function adjustedTarget(PMMState memory state) internal pure { if (state.R == RState.BELOW_ONE) { state.Q0 = DODOMath._SolveQuadraticFunctionForTarget( state.Q, state.B.sub(state.B0), state.i, state.K ); } else if (state.R == RState.ABOVE_ONE) { state.B0 = DODOMath._SolveQuadraticFunctionForTarget( state.B, state.Q.sub(state.Q0), DecimalMath.reciprocalFloor(state.i), state.K ); } } function getMidPrice(PMMState memory state) internal pure returns (uint256) { if (state.R == RState.BELOW_ONE) { uint256 R = DecimalMath.divFloor(state.Q0.mul(state.Q0).div(state.Q), state.Q); R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mulFloor(state.K, R)); return DecimalMath.divFloor(state.i, R); } else { uint256 R = DecimalMath.divFloor(state.B0.mul(state.B0).div(state.B), state.B); R = DecimalMath.ONE.sub(state.K).add(DecimalMath.mulFloor(state.K, R)); return DecimalMath.mulFloor(state.i, R); } } } // File: contracts/intf/IDODOCallee.sol interface IDODOCallee { function DVMSellShareCall( address sender, uint256 burnShareAmount, uint256 baseAmount, uint256 quoteAmount, bytes calldata data ) external; function DVMFlashLoanCall( address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data ) external; function DPPFlashLoanCall( address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data ) external; function DSPFlashLoanCall( address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data ) external; function CPCancelCall( address sender, uint256 amount, bytes calldata data ) external; function CPClaimBidCall( address sender, uint256 baseAmount, uint256 quoteAmount, bytes calldata data ) external; function NFTRedeemCall( address payable assetTo, uint256 quoteAmount, bytes calldata ) external; } // File: contracts/CrowdPooling/impl/CPFunding.sol contract CPFunding is CPStorage { using SafeERC20 for IERC20; // ============ Events ============ event Bid(address to, uint256 amount, uint256 fee); event Cancel(address to,uint256 amount); event Settle(); // ============ BID & CALM PHASE ============ modifier isBidderAllow(address bidder) { require(_BIDDER_PERMISSION_.isAllowed(bidder), "BIDDER_NOT_ALLOWED"); if(_IS_OVERCAP_STOP) { require(_QUOTE_TOKEN_.balanceOf(address(this)) <= _POOL_QUOTE_CAP_, "ALREADY_OVER_CAP"); } _; } function bid(address to) external isNotForceStop phaseBid preventReentrant isBidderAllow(to) { uint256 input = _getQuoteInput(); uint256 mtFee = DecimalMath.mulFloor(input, _MT_FEE_RATE_MODEL_.getFeeRate(to)); _transferQuoteOut(_MAINTAINER_, mtFee); _mintShares(to, input.sub(mtFee)); _sync(); emit Bid(to, input, mtFee); } function cancel(address to, uint256 amount, bytes calldata data) external phaseBidOrCalm preventReentrant { require(_SHARES_[msg.sender] >= amount, "SHARES_NOT_ENOUGH"); _burnShares(msg.sender, amount); _transferQuoteOut(to, amount); _sync(); if(data.length > 0){ IDODOCallee(to).CPCancelCall(msg.sender,amount,data); } emit Cancel(msg.sender,amount); } function _mintShares(address to, uint256 amount) internal { _SHARES_[to] = _SHARES_[to].add(amount); _TOTAL_SHARES_ = _TOTAL_SHARES_.add(amount); } function _burnShares(address from, uint256 amount) internal { _SHARES_[from] = _SHARES_[from].sub(amount); _TOTAL_SHARES_ = _TOTAL_SHARES_.sub(amount); } // ============ SETTLEMENT ============ function settle() external isNotForceStop phaseSettlement preventReentrant { _settle(); (uint256 poolBase, uint256 poolQuote, uint256 poolI, uint256 unUsedBase, uint256 unUsedQuote) = getSettleResult(); _UNUSED_BASE_ = unUsedBase; _UNUSED_QUOTE_ = unUsedQuote; address _poolBaseToken; address _poolQuoteToken; if (_UNUSED_BASE_ > poolBase) { _poolBaseToken = address(_QUOTE_TOKEN_); _poolQuoteToken = address(_BASE_TOKEN_); } else { _poolBaseToken = address(_BASE_TOKEN_); _poolQuoteToken = address(_QUOTE_TOKEN_); } _POOL_ = IDVMFactory(_POOL_FACTORY_).createDODOVendingMachine( _poolBaseToken, _poolQuoteToken, _POOL_FEE_RATE_, poolI, DecimalMath.ONE, _IS_OPEN_TWAP_ ); uint256 avgPrice = unUsedBase == 0 ? _I_ : DecimalMath.divCeil(poolQuote, unUsedBase); _AVG_SETTLED_PRICE_ = avgPrice; _transferBaseOut(_POOL_, poolBase); _transferQuoteOut(_POOL_, poolQuote); (_TOTAL_LP_AMOUNT_, ,) = IDVM(_POOL_).buyShares(address(this)); msg.sender.transfer(_SETTEL_FUND_); emit Settle(); } // in case something wrong with base token contract function emergencySettle() external isNotForceStop phaseSettlement preventReentrant { require(block.timestamp >= _PHASE_CALM_ENDTIME_.add(_SETTLEMENT_EXPIRE_), "NOT_EMERGENCY"); _settle(); _UNUSED_QUOTE_ = _QUOTE_TOKEN_.balanceOf(address(this)); } function _settle() internal { require(!_SETTLED_, "ALREADY_SETTLED"); _SETTLED_ = true; _SETTLED_TIME_ = block.timestamp; } // ============ Pricing ============ function getSettleResult() public view returns (uint256 poolBase, uint256 poolQuote, uint256 poolI, uint256 unUsedBase, uint256 unUsedQuote) { poolQuote = _QUOTE_TOKEN_.balanceOf(address(this)); if (poolQuote > _POOL_QUOTE_CAP_) { poolQuote = _POOL_QUOTE_CAP_; } (uint256 soldBase,) = PMMPricing.sellQuoteToken(_getPMMState(), poolQuote); poolBase = _TOTAL_BASE_.sub(soldBase); unUsedQuote = _QUOTE_TOKEN_.balanceOf(address(this)).sub(poolQuote); unUsedBase = _BASE_TOKEN_.balanceOf(address(this)).sub(poolBase); // Try to make midPrice equal to avgPrice // k=1, If quote and base are not balanced, one side must be cut off // DVM truncated quote, but if more quote than base entering the pool, we need set the quote to the base // m = avgPrice // i = m (1-quote/(m*base)) // if quote = m*base i = 1 // if quote > m*base reverse uint256 avgPrice = unUsedBase == 0 ? _I_ : DecimalMath.divCeil(poolQuote, unUsedBase); uint256 baseDepth = DecimalMath.mulFloor(avgPrice, poolBase); if (poolQuote == 0) { // ask side only DVM poolI = _I_; } else if (unUsedBase== poolBase) { // standard bonding curve poolI = 1; } else if (unUsedBase < poolBase) { // poolI up round uint256 ratio = DecimalMath.ONE.sub(DecimalMath.divFloor(poolQuote, baseDepth)); poolI = avgPrice.mul(ratio).mul(ratio).divCeil(DecimalMath.ONE2); } else if (unUsedBase > poolBase) { // poolI down round uint256 ratio = DecimalMath.ONE.sub(DecimalMath.divCeil(baseDepth, poolQuote)); poolI = ratio.mul(ratio).div(avgPrice); } } function _getPMMState() internal view returns (PMMPricing.PMMState memory state) { state.i = _I_; state.K = _K_; state.B = _TOTAL_BASE_; state.Q = 0; state.B0 = state.B; state.Q0 = 0; state.R = PMMPricing.RState.ONE; } function getExpectedAvgPrice() external view returns (uint256) { require(!_SETTLED_, "ALREADY_SETTLED"); (uint256 poolBase, uint256 poolQuote, , , ) = getSettleResult(); return DecimalMath.divCeil(poolQuote, _BASE_TOKEN_.balanceOf(address(this)).sub(poolBase)); } // ============ Asset In ============ function _getQuoteInput() internal view returns (uint256 input) { return _QUOTE_TOKEN_.balanceOf(address(this)).sub(_QUOTE_RESERVE_); } // ============ Set States ============ function _sync() internal { uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); if (quoteBalance != _QUOTE_RESERVE_) { _QUOTE_RESERVE_ = quoteBalance; } } // ============ Asset Out ============ function _transferBaseOut(address to, uint256 amount) internal { if (amount > 0) { _BASE_TOKEN_.safeTransfer(to, amount); } } function _transferQuoteOut(address to, uint256 amount) internal { if (amount > 0) { _QUOTE_TOKEN_.safeTransfer(to, amount); } } function getShares(address user) external view returns (uint256) { return _SHARES_[user]; } } // File: contracts/CrowdPooling/impl/CPVesting.sol /** * @title CPVesting * @author DODO Breeder * * @notice Lock Token and release it linearly */ contract CPVesting is CPFunding { using SafeMath for uint256; using SafeERC20 for IERC20; // ============ Events ============ event ClaimBaseToken(address user, uint256 baseAmount); event ClaimQuoteToken(address user, uint256 quoteAmount); event ClaimLP(uint256 amount); // ================ Modifiers ================ modifier afterSettlement() { require(_SETTLED_, "NOT_SETTLED"); _; } modifier afterFreeze() { require(_SETTLED_ && block.timestamp >= _SETTLED_TIME_.add(_FREEZE_DURATION_), "FREEZED"); _; } modifier afterClaimFreeze() { require(_SETTLED_ && block.timestamp >= _SETTLED_TIME_.add(_TOKEN_CLAIM_DURATION_), "CLAIM_FREEZED"); _; } // ============ Bidder Functions ============ function bidderClaim(address to, bytes calldata data) external { if(_SETTLED_) { _claimQuoteToken(to, data); } if(_SETTLED_ && block.timestamp >= _SETTLED_TIME_.add(_TOKEN_CLAIM_DURATION_)) { _claimBaseToken(to); } } function _claimQuoteToken(address to,bytes calldata data) internal { // require(!_CLAIMED_QUOTE_[msg.sender], "ALREADY_CLAIMED_FUND"); if(_CLAIMED_QUOTE_[msg.sender]) return; _CLAIMED_QUOTE_[msg.sender] = true; uint256 quoteAmount = _UNUSED_QUOTE_.mul(_SHARES_[msg.sender]).div(_TOTAL_SHARES_); _transferQuoteOut(to, quoteAmount); if(data.length>0){ IDODOCallee(to).CPClaimBidCall(msg.sender,0,quoteAmount,data); } emit ClaimQuoteToken(msg.sender, quoteAmount); } function _claimBaseToken(address to) internal { uint256 claimableBaseAmount = getClaimableBaseToken(msg.sender); _CLAIMED_BASE_TOKEN_[msg.sender] = _CLAIMED_BASE_TOKEN_[msg.sender].add(claimableBaseAmount); _transferBaseOut(to, claimableBaseAmount); emit ClaimBaseToken(msg.sender, claimableBaseAmount); } function getClaimableBaseToken(address user) public view afterClaimFreeze returns (uint256) { uint256 baseTotalAmount = _UNUSED_BASE_.mul(_SHARES_[user]).div(_TOTAL_SHARES_); uint256 remainingBaseToken = DecimalMath.mulFloor( getRemainingBaseTokenRatio(block.timestamp), baseTotalAmount ); return baseTotalAmount.sub(remainingBaseToken).sub(_CLAIMED_BASE_TOKEN_[user]); } function getRemainingBaseTokenRatio(uint256 timestamp) public view afterClaimFreeze returns (uint256) { uint256 timePast = timestamp.sub(_SETTLED_TIME_.add(_TOKEN_CLAIM_DURATION_)); if (timePast < _TOKEN_VESTING_DURATION_) { uint256 remainingTime = _TOKEN_VESTING_DURATION_.sub(timePast); return DecimalMath.ONE.sub(_TOKEN_CLIFF_RATE_).mul(remainingTime).div(_TOKEN_VESTING_DURATION_); } else { return 0; } } // ============ Owner Functions ============ function claimLPToken() external onlyOwner afterFreeze { uint256 lpAmount = getClaimableLPToken(); IERC20(_POOL_).safeTransfer(_OWNER_, lpAmount); emit ClaimLP(lpAmount); } function getClaimableLPToken() public view afterFreeze returns (uint256) { uint256 remainingLPToken = DecimalMath.mulFloor( getRemainingLPRatio(block.timestamp), _TOTAL_LP_AMOUNT_ ); return IERC20(_POOL_).balanceOf(address(this)).sub(remainingLPToken); } function getRemainingLPRatio(uint256 timestamp) public view afterFreeze returns (uint256) { uint256 timePast = timestamp.sub(_SETTLED_TIME_.add(_FREEZE_DURATION_)); if (timePast < _VESTING_DURATION_) { uint256 remainingTime = _VESTING_DURATION_.sub(timePast); return DecimalMath.ONE.sub(_CLIFF_RATE_).mul(remainingTime).div(_VESTING_DURATION_); } else { return 0; } } } // File: contracts/CrowdPooling/impl/CP.sol /** * @title DODO CrowdPooling * @author DODO Breeder * * @notice CrowdPooling initialization */ contract CP is CPVesting { using SafeMath for uint256; receive() external payable { require(_INITIALIZED_ == false, "WE_NOT_SAVE_ETH_AFTER_INIT"); } function init( address[] calldata addressList, uint256[] calldata timeLine, uint256[] calldata valueList, bool[] calldata switches //0 isOverCapStop 1 isOpenTWAP ) external { /* Address List 0. owner 1. maintainer 2. baseToken 3. quoteToken 4. permissionManager 5. feeRateModel 6. poolFactory */ require(addressList.length == 7, "LIST_LENGTH_WRONG"); initOwner(addressList[0]); _MAINTAINER_ = addressList[1]; _BASE_TOKEN_ = IERC20(addressList[2]); _QUOTE_TOKEN_ = IERC20(addressList[3]); _BIDDER_PERMISSION_ = IPermissionManager(addressList[4]); _MT_FEE_RATE_MODEL_ = IFeeRateModel(addressList[5]); _POOL_FACTORY_ = addressList[6]; /* Time Line 0. phase bid starttime 1. phase bid duration 2. phase calm duration 3. freeze duration 4. vesting duration 5. claim freeze duration 6. claim vesting duration */ require(timeLine.length == 7, "LIST_LENGTH_WRONG"); _PHASE_BID_STARTTIME_ = timeLine[0]; _PHASE_BID_ENDTIME_ = _PHASE_BID_STARTTIME_.add(timeLine[1]); _PHASE_CALM_ENDTIME_ = _PHASE_BID_ENDTIME_.add(timeLine[2]); _FREEZE_DURATION_ = timeLine[3]; _VESTING_DURATION_ = timeLine[4]; _TOKEN_CLAIM_DURATION_ = timeLine[5]; _TOKEN_VESTING_DURATION_ = timeLine[6]; require(block.timestamp <= _PHASE_BID_STARTTIME_, "TIMELINE_WRONG"); /* Value List 0. pool quote cap 1. k 2. i 3. lp cliff rate 4. base token cliff rate 5. lp fee rate */ require(valueList.length == 6, "LIST_LENGTH_WRONG"); _POOL_QUOTE_CAP_ = valueList[0]; _K_ = valueList[1]; _I_ = valueList[2]; _CLIFF_RATE_ = valueList[3]; _TOKEN_CLIFF_RATE_ = valueList[4]; _POOL_FEE_RATE_ = valueList[5]; require(_I_ > 0 && _I_ <= 1e36, "I_VALUE_WRONG"); require(_K_ <= 1e18, "K_VALUE_WRONG"); require(_CLIFF_RATE_ <= 1e18, "CLIFF_RATE_WRONG"); require(_TOKEN_CLIFF_RATE_ <= 1e18, "TOKEN_CLIFF_RATE_WRONG"); _TOTAL_BASE_ = _BASE_TOKEN_.balanceOf(address(this)); require(switches.length == 2, "SWITCHES_LENGTH_WRONG"); _IS_OVERCAP_STOP = switches[0]; _IS_OPEN_TWAP_ = switches[1]; require(address(this).balance == _SETTEL_FUND_, "SETTLE_FUND_NOT_MATCH"); } // ============ Version Control ============ function version() virtual external pure returns (string memory) { return "CP 2.0.0"; } // ============= View ================= function getCpInfoHelper(address user) external view returns ( bool isSettled, uint256 settledTime, uint256 claimableBaseToken, uint256 claimedBaseToken, bool isClaimedQuoteToken, uint256 claimableQuoteToken, address pool, uint256 claimableLpToken, uint256 myShares, bool isOverCapStop ) { isSettled = _SETTLED_; settledTime = _SETTLED_TIME_; if(_SETTLED_ && block.timestamp >= _SETTLED_TIME_.add(_TOKEN_CLAIM_DURATION_)) { claimableBaseToken = getClaimableBaseToken(user); claimedBaseToken = _CLAIMED_BASE_TOKEN_[user]; }else { claimableBaseToken = 0; claimedBaseToken = 0; } if(_SETTLED_) { if(_CLAIMED_QUOTE_[msg.sender]) { isClaimedQuoteToken = true; claimableQuoteToken = 0; } else { isClaimedQuoteToken = false; claimableQuoteToken = _UNUSED_QUOTE_.mul(_SHARES_[user]).div(_TOTAL_SHARES_); } } else { isClaimedQuoteToken = false; claimableQuoteToken = 0; } pool = _POOL_; if(_SETTLED_ && block.timestamp >= _SETTLED_TIME_.add(_FREEZE_DURATION_)) { if(user == _OWNER_) { claimableLpToken = getClaimableLPToken(); }else { claimableLpToken = 0; } }else { claimableLpToken = 0; } myShares = _SHARES_[user]; isOverCapStop = _IS_OVERCAP_STOP; } }
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Bid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"baseAmount","type":"uint256"}],"name":"ClaimBaseToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimLP","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"quoteAmount","type":"uint256"}],"name":"ClaimQuoteToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferPrepared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Settle","type":"event"},{"inputs":[],"name":"_AVG_SETTLED_PRICE_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_BASE_TOKEN_","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_BIDDER_PERMISSION_","outputs":[{"internalType":"contract IPermissionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_CLAIMED_BASE_TOKEN_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_CLAIMED_QUOTE_","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_CLIFF_RATE_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_FORCE_STOP_","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_FREEZE_DURATION_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_IS_OPEN_TWAP_","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_IS_OVERCAP_STOP","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_I_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_K_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_MAINTAINER_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_MT_FEE_RATE_MODEL_","outputs":[{"internalType":"contract IFeeRateModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_NEW_OWNER_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_OWNER_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_PHASE_BID_ENDTIME_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_PHASE_BID_STARTTIME_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_PHASE_CALM_ENDTIME_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_POOL_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_POOL_FACTORY_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_POOL_FEE_RATE_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_POOL_QUOTE_CAP_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_QUOTE_RESERVE_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_QUOTE_TOKEN_","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_SETTLED_","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_SETTLED_TIME_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_TOKEN_CLAIM_DURATION_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_TOKEN_CLIFF_RATE_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_TOKEN_VESTING_DURATION_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_TOTAL_BASE_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_TOTAL_LP_AMOUNT_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_TOTAL_SHARES_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_UNUSED_BASE_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_UNUSED_QUOTE_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_VESTING_DURATION_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"bid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"bidderClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimLPToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencySettle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"forceStop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getClaimableBaseToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClaimableLPToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getCpInfoHelper","outputs":[{"internalType":"bool","name":"isSettled","type":"bool"},{"internalType":"uint256","name":"settledTime","type":"uint256"},{"internalType":"uint256","name":"claimableBaseToken","type":"uint256"},{"internalType":"uint256","name":"claimedBaseToken","type":"uint256"},{"internalType":"bool","name":"isClaimedQuoteToken","type":"bool"},{"internalType":"uint256","name":"claimableQuoteToken","type":"uint256"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"claimableLpToken","type":"uint256"},{"internalType":"uint256","name":"myShares","type":"uint256"},{"internalType":"bool","name":"isOverCapStop","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExpectedAvgPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getRemainingBaseTokenRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getRemainingLPRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSettleResult","outputs":[{"internalType":"uint256","name":"poolBase","type":"uint256"},{"internalType":"uint256","name":"poolQuote","type":"uint256"},{"internalType":"uint256","name":"poolI","type":"uint256"},{"internalType":"uint256","name":"unUsedBase","type":"uint256"},{"internalType":"uint256","name":"unUsedQuote","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addressList","type":"address[]"},{"internalType":"uint256[]","name":"timeLine","type":"uint256[]"},{"internalType":"uint256[]","name":"valueList","type":"uint256[]"},{"internalType":"bool[]","name":"switches","type":"bool[]"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"initOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"stateMutability":"payable","type":"receive"}]
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.00667 | 282,335.7691 | $1,883.06 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.