From 09ff15e85b5412a9328c04508f578410537bd2b4 Mon Sep 17 00:00:00 2001 From: mingda Date: Tue, 8 Dec 2020 18:13:45 +0800 Subject: [PATCH] Call Auction --- contracts/CallAuction/impl/CAFunding.sol | 46 +++++++++++++----------- contracts/CallAuction/impl/CAStorage.sol | 13 ++++--- contracts/CallAuction/impl/CAVesting.sol | 34 ++++++++++++------ 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/contracts/CallAuction/impl/CAFunding.sol b/contracts/CallAuction/impl/CAFunding.sol index 511748c..380586c 100644 --- a/contracts/CallAuction/impl/CAFunding.sol +++ b/contracts/CallAuction/impl/CAFunding.sol @@ -21,7 +21,12 @@ contract CAFunding is CAStorage { // ============ BID ============ - function bid(address to) external phaseBid preventReentrant { + modifier isBidderAllow(address bidder) { + require(_BIDDER_PERMISSION_.isAllowed(bidder), "BIDDER_NOT_ALLOWED"); + _; + } + + function bid(address to) external phaseBid preventReentrant isBidderAllow(to) { uint256 input = _getQuoteInput(); _QUOTE_SHARES_[to] = _QUOTE_SHARES_[to].add(input); _TOTAL_QUOTE_SHARES_ = _TOTAL_QUOTE_SHARES_.add(input); @@ -30,18 +35,11 @@ contract CAFunding is CAStorage { // ============ CALM ============ - function cancel( - address to, - uint256 amount, - bytes memory data - ) external phaseBidOrCalm preventReentrant { + function cancel(address to, uint256 amount) external phaseBidOrCalm preventReentrant { require(_QUOTE_SHARES_[msg.sender] >= amount, "SHARES_NOT_ENOUGH"); _QUOTE_SHARES_[msg.sender] = _QUOTE_SHARES_[msg.sender].sub(amount); _transferQuoteOut(to, amount); _sync(); - if (data.length > 0) { - IDODOCallee(to).CACancelCall(msg.sender, amount, data); - } } // ============ SETTLEMENT ============ @@ -52,16 +50,20 @@ contract CAFunding is CAStorage { uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); uint256 baseBalance = _BASE_TOKEN_.balanceOf(address(this)); - uint256 mtFee; - (_TOTAL_SOLD_BASE_, mtFee) = getBaseSold(); - // 1. maintainer quote - _transferQuoteOut(_MAINTAINER_, mtFee); - // 2. remaining quote - _transferQuoteOut(_QUOTE_PAY_BACK_, quoteBalance.sub(mtFee)); - // 3. base token pay back + // 1. sold base remaining in the contract + _TOTAL_SOLD_BASE_ = getBaseSold(); + + // 2. left base send out _transferBaseOut(_BASE_PAY_BACK_, baseBalance.sub(_TOTAL_SOLD_BASE_)); - // 4. left base in contract + + // 3. used quote token + uint256 usedQuote = _QUOTE_CAP_ <= quoteBalance ? _QUOTE_CAP_ : quoteBalance; + _transferQuoteOut(_QUOTE_PAY_BACK_, usedQuote); + + // 4. unused quote token + _TOTAL_UNUSED_QUOTE_ = quoteBalance.sub(usedQuote); + // 5. external call if (_BASE_PAY_BACK_CALL_DATA_.length > 0) { (bool success, ) = _BASE_PAY_BACK_.call(_BASE_PAY_BACK_CALL_DATA_); @@ -76,18 +78,20 @@ contract CAFunding is CAStorage { // ============ Pricing ============ function getAvgPrice() public view returns (uint256 avgPrice) { - (uint256 baseSold, ) = getBaseSold(); + uint256 baseSold = getBaseSold(); avgPrice = DecimalMath.divFloor(_QUOTE_TOKEN_.balanceOf(address(this)), baseSold); } function getBaseByUser(address user) public view returns (uint256 baseAmount) { - (uint256 baseSold, ) = getBaseSold(); + uint256 baseSold = getBaseSold(); baseAmount = baseSold.mul(_QUOTE_SHARES_[user]).div(_TOTAL_QUOTE_SHARES_); } - function getBaseSold() public view returns (uint256 baseSold, uint256 mtFee) { + function getBaseSold() public view returns (uint256 baseSold) { uint256 quoteBalance = _QUOTE_TOKEN_.balanceOf(address(this)); - mtFee = DecimalMath.mulFloor(quoteBalance, _QUOTE_MAINTAINER_FEE_RATE_); + if (quoteBalance > _QUOTE_CAP_) { + quoteBalance = _QUOTE_CAP_; + } (baseSold, ) = PMMPricing.sellQuoteToken(_getPMMState(), quoteBalance); } diff --git a/contracts/CallAuction/impl/CAStorage.sol b/contracts/CallAuction/impl/CAStorage.sol index 8d6e844..d7b064e 100644 --- a/contracts/CallAuction/impl/CAStorage.sol +++ b/contracts/CallAuction/impl/CAStorage.sol @@ -10,6 +10,7 @@ pragma experimental ABIEncoderV2; import {InitializableOwnable} from "../../lib/InitializableOwnable.sol"; import {ReentrancyGuard} from "../../lib/ReentrancyGuard.sol"; +import {IPermissionManager} from "../../lib/PermissionManager.sol"; import {SafeMath} from "../../lib/SafeMath.sol"; import {IERC20} from "../../intf/IERC20.sol"; @@ -27,13 +28,12 @@ contract CAStorage is InitializableOwnable, ReentrancyGuard { IERC20 public _BASE_TOKEN_; IERC20 public _QUOTE_TOKEN_; - address public _MAINTAINER_; - address public _BASE_PAY_BACK_; - address public _QUOTE_PAY_BACK_; // ============ Distribution Parameters ============ - uint256 _QUOTE_MAINTAINER_FEE_RATE_; + uint256 _QUOTE_CAP_; + address public _BASE_PAY_BACK_; + address public _QUOTE_PAY_BACK_; bytes _BASE_PAY_BACK_CALL_DATA_; bytes _QUOTE_PAY_BACK_CALL_DATA_; @@ -42,9 +42,12 @@ contract CAStorage is InitializableOwnable, ReentrancyGuard { uint256 public _QUOTE_RESERVE_; uint256 public _BASE_RESERVE_; uint256 public _TOTAL_SOLD_BASE_; + uint256 public _TOTAL_UNUSED_QUOTE_; uint256 public _TOTAL_QUOTE_SHARES_; mapping(address => uint256) internal _QUOTE_SHARES_; - mapping(address => uint256) internal _CLAIMED_BALANCES_; + mapping(address => bool) internal _QUOTE_CLAIMED_; + mapping(address => uint256) internal _CLAIMED_BASE_; + IPermissionManager public _BIDDER_PERMISSION_; // ============ Time Lock ============ diff --git a/contracts/CallAuction/impl/CAVesting.sol b/contracts/CallAuction/impl/CAVesting.sol index 1fb7546..5c01111 100644 --- a/contracts/CallAuction/impl/CAVesting.sol +++ b/contracts/CallAuction/impl/CAVesting.sol @@ -28,10 +28,16 @@ contract LockedTokenVault is CAFunding { // ============ Functions ============ - function claim() external { - uint256 claimableToken = getClaimableBalance(msg.sender); + function claimBase() external { + uint256 claimableToken = getClaimableBaseBalance(msg.sender); _transferBaseOut(msg.sender, claimableToken); - _CLAIMED_BALANCES_[msg.sender] = _CLAIMED_BALANCES_[msg.sender].add(claimableToken); + _CLAIMED_BASE_[msg.sender] = _CLAIMED_BASE_[msg.sender].add(claimableToken); + } + + function claimQuote() external { + require(!_QUOTE_CLAIMED_[msg.sender], "QUOTE_CLAIMED"); + _QUOTE_CLAIMED_[msg.sender] = true; + _transferQuoteOut(msg.sender, getClaimableQuoteBalance(msg.sender)); } // ============ View ============ @@ -41,20 +47,20 @@ contract LockedTokenVault is CAFunding { } function getClaimedBaseBalance(address holder) public view returns (uint256) { - return _CLAIMED_BALANCES_[holder]; + return _CLAIMED_BASE_[holder]; } - function getClaimableBalance(address holder) public view returns (uint256) { - uint256 remainingToken = getRemainingBalance(holder); - return getOriginBaseBalance(holder).sub(remainingToken).sub(_CLAIMED_BALANCES_[holder]); + function getClaimableBaseBalance(address holder) public view returns (uint256) { + uint256 remainingToken = getRemainingBaseBalance(holder); + return getOriginBaseBalance(holder).sub(remainingToken).sub(_CLAIMED_BASE_[holder]); } - function getRemainingBalance(address holder) public view returns (uint256) { - uint256 remainingRatio = getRemainingRatio(block.timestamp); + function getRemainingBaseBalance(address holder) public view returns (uint256) { + uint256 remainingRatio = getRemainingBaseRatio(block.timestamp); return DecimalMath.mulFloor(getOriginBaseBalance(holder), remainingRatio); } - function getRemainingRatio(uint256 timestamp) public view returns (uint256) { + function getRemainingBaseRatio(uint256 timestamp) public view returns (uint256) { if (timestamp < _START_VESTING_TIME_) { return DecimalMath.ONE; } @@ -66,4 +72,12 @@ contract LockedTokenVault is CAFunding { return 0; } } + + function getClaimableQuoteBalance(address holder) public view returns (uint256) { + if (!_QUOTE_CLAIMED_[msg.sender]) { + return 0; + } else { + return _TOTAL_UNUSED_QUOTE_.mul(_QUOTE_SHARES_[holder]).div(_TOTAL_QUOTE_SHARES_); + } + } }