Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] 17: User Defined Coupon Expiry w/ FPSBA #16

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
cbde5d8
first shot at premium decay of coupon with longer expiry
cinquemb Dec 30, 2020
6c19be4
updates for eulers number and missing import
cinquemb Dec 31, 2020
4b19843
fix multiplier
cinquemb Dec 31, 2020
42de4ef
fix uint256 assignment
cinquemb Dec 31, 2020
1a4b15f
first stab at coupon auction
cinquemb Jan 3, 2021
f41d958
sort bids by euclidan distance with equal weights on min bid and min …
cinquemb Jan 3, 2021
5f7ab94
fix: sort on distance not on struct
cinquemb Jan 3, 2021
482e236
add coupoun assignment/selected and rejected fix yeild calc
cinquemb Jan 3, 2021
7569fee
remove unused imports and constants
cinquemb Jan 3, 2021
ba31c11
dont subtract off constant epoch when assignment
cinquemb Jan 3, 2021
e53a3c8
fixing some compiler errors
cinquemb Jan 3, 2021
22a8e74
fixing more compiler errors
cinquemb Jan 3, 2021
24f30f8
first pass with implementing FPSBA
cinquemb Jan 4, 2021
5837ecc
changing contract inheritance of Auction
cinquemb Jan 4, 2021
3b58701
starting to add mocks and tests
cinquemb Jan 4, 2021
1343eab
adding test conditions scaffoled for auction
cinquemb Jan 4, 2021
ea81de4
adding tests for placeCouponAuctionBid
cinquemb Jan 5, 2021
827157b
updating state mocks, incorperating dollar amount in euclidian distan…
cinquemb Jan 5, 2021
7161284
adding some auction internals
cinquemb Jan 5, 2021
f42edee
tight packing auction structs
cinquemb Jan 5, 2021
c9c6bc4
adding modifier so that only dao can settle auction
cinquemb Jan 6, 2021
3afd5f4
adding new state tests
cinquemb Jan 6, 2021
f16f5d4
fixing market test
cinquemb Jan 6, 2021
ae3ce9b
fixing stuff with market tests, working on auction tests
cinquemb Jan 7, 2021
d7d6965
finsihed with auction test
cinquemb Jan 7, 2021
d48d484
need to finish/cancel prev auction in Regulator.step
cinquemb Jan 7, 2021
d4fd56b
use actual uint256 max for min initializations
cinquemb Jan 7, 2021
cd29d39
fixing coupon auction internals
cinquemb Jan 8, 2021
8b47444
used auction factory to avoid high gas for regulator contract
cinquemb Jan 8, 2021
9d667b4
merged auction settlement stuff into regulator to bypass gas issues, …
cinquemb Jan 8, 2021
ac9628e
removing unneed files, more work on regulator tests
cinquemb Jan 8, 2021
811fdae
update regulator tests
cinquemb Jan 9, 2021
5afc125
done adding tests
cinquemb Jan 9, 2021
abe2465
add back in commented out test
cinquemb Jan 9, 2021
45db6c8
more parity between auction updates between dsd-esd
cinquemb Jan 16, 2021
faac8a0
state parity
cinquemb Jan 16, 2021
b29314e
state parity
cinquemb Jan 16, 2021
3476961
state parity
cinquemb Jan 16, 2021
e3354f3
fixing regulator tests
cinquemb Jan 16, 2021
cb2bc50
adding back in autoredemption, prioritizing cross auction best bidder…
cinquemb Jan 16, 2021
9806393
some comment stuff
cinquemb Jan 16, 2021
0fb939e
dont limit auction bids based on debt, grow supply based on auction i…
cinquemb Jan 16, 2021
a2358b4
dont use totalNet() for growSupply using dollar().totalSupply()
cinquemb Jan 19, 2021
3427b39
bad conditional for not finished auction
cinquemb Jan 19, 2021
12f6f6b
remove debt requirement from placeCouponAuctionBid
cinquemb Jan 19, 2021
95473b1
use diff burnFromAccount function
cinquemb Jan 20, 2021
88262b9
fixing ratio calc
cinquemb Jan 20, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions protocol/contracts/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ library Constants {
/* Market */
uint256 private constant COUPON_EXPIRATION = 90;
uint256 private constant DEBT_RATIO_CAP = 20e16; // 20%
uint256 private constant MAX_COUPON_YIELD_MULT = 2000; //2000 coupouns per 1 dollar burn


/* Regulator */
uint256 private constant SUPPLY_CHANGE_LIMIT = 3e16; // 3%
Expand Down Expand Up @@ -165,6 +167,10 @@ library Constants {
return COUPON_EXPIRATION;
}

function getCouponMaxYieldToBurn() internal pure returns (uint256) {
return MAX_COUPON_YIELD_MULT;
}

function getDebtRatioCap() internal pure returns (Decimal.D256 memory) {
return Decimal.D256({value: DEBT_RATIO_CAP});
}
Expand Down
10 changes: 10 additions & 0 deletions protocol/contracts/dao/Comptroller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ contract Comptroller is Setters {
balanceCheck();
}

function burnFromAccountSansDebt(address account, uint256 amount) internal {
dollar().transferFrom(account, address(this), amount);
dollar().burn(amount);
balanceCheck();
}

function burnFromAccount(address account, uint256 amount) internal {
dollar().transferFrom(account, address(this), amount);
dollar().burn(amount);
Expand Down Expand Up @@ -122,6 +128,10 @@ contract Comptroller is Setters {
return 0;
}

function acceptableBidCheck(address account, uint256 dollarAmount) internal returns (bool) {
return (dollar().balanceOf(account) >= balanceOfBonded(account).add(dollarAmount));
}

function balanceCheck() private {
Require.that(
dollar().balanceOf(address(this)) >= totalBonded().add(totalStaged()).add(totalRedeemable()),
Expand Down
125 changes: 125 additions & 0 deletions protocol/contracts/dao/Getters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,131 @@ contract Getters is State {
return epoch <= Constants.getBootstrappingPeriod();
}

function getCouponAuctionAtEpoch(uint256 epoch) internal view returns (Epoch.AuctionState storage) {
return _state.epochs[epoch].auction;
}

function getCouponAuctionBids(uint256 epoch) internal view returns (uint256) {
return _state.epochs[epoch].auction._totalBids;
}

function getCouponBidderState(uint256 epoch, address bidder) internal view returns (Epoch.CouponBidderState storage) {
return _state.epochs[epoch].auction.couponBidderState[bidder];
}

function getCouponBidderStateSelected(uint256 epoch, address bidder) internal view returns (bool) {
return _state.epochs[epoch].auction.couponBidderState[bidder].selected;
}

function getCouponBidderStateAssginedAtIndex(uint256 epoch, uint256 index) internal view returns (address) {
return _state.epochs[epoch].auction.seletedCouponBidder[index];
}

function getCouponBidderStateRejected(uint256 epoch, address bidder) internal view returns (bool) {
return _state.epochs[epoch].auction.couponBidderState[bidder].rejected;
}

function getCouponBidderStateIndex(uint256 epoch, uint256 index) internal view returns (address) {
return _state.epochs[epoch].auction.couponBidder[index];
}

function isCouponAuctionFinished(uint256 epoch) internal view returns (bool){
return _state.epochs[epoch].auction.finished;
}

function isCouponAuctionCanceled(uint256 epoch) internal view returns (bool){
return _state.epochs[epoch].auction.canceled;
}

function getCouponAuctionMinExpiry(uint256 epoch) internal view returns (uint256) {
return _state.epochs[epoch].auction.minExpiry;
}

function getCouponAuctionMaxExpiry(uint256 epoch) internal view returns (uint256) {
return _state.epochs[epoch].auction.maxExpiry;
}

function getCouponAuctionMinYield(uint256 epoch) internal view returns (uint256) {
return _state.epochs[epoch].auction.minYield;
}

function getCouponAuctionMaxYield(uint256 epoch) internal view returns (uint256) {
return _state.epochs[epoch].auction.maxYield;
}

function getCouponAuctionMinDollarAmount(uint256 epoch) internal view returns (uint256) {
return _state.epochs[epoch].auction.minDollarAmount;
}

function getCouponAuctionMaxDollarAmount(uint256 epoch) internal view returns (uint256) {
return _state.epochs[epoch].auction.maxDollarAmount;
}

function getMinExpiryFilled(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.minExpiryFilled;
}

function getMaxExpiryFilled(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.maxExpiryFilled;
}

function getAvgExpiryFilled(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.avgExpiryFilled;
}

function getMinYieldFilled(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.minYieldFilled;
}

function getMaxYieldFilled(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.maxYieldFilled;
}

function getAvgYieldFilled(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.avgYieldFilled;
}

function getBidToCover(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.bidToCover;
}

function getTotalFilled(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.totalFilled;
}

function getTotalAuctioned(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.totalAuctioned;
}

function getTotalBurned(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.totalBurned;
}

function getEarliestDeadAuctionEpoch() public view returns (uint256) {
return _state.epoch.earliestDeadAuction;
}

function getLatestCouponAuctionRedeemedSelectedBidderIndex(uint256 epoch) public view returns (uint256) {
return _state.epochs[epoch].auction.latestRedeemedSelectedBidderIndex;
}

function getAvgAvgYieldAcrossCouponAuctions() public view returns (uint256) {
// loop over past epochs from the latest `dead` epoch to the current
uint256 sumYield = 0;
uint256 totalAvailableAuctions = 1;
for (uint256 d_idx = getEarliestDeadAuctionEpoch(); d_idx < uint256(epoch()); d_idx++) {
uint256 temp_coupon_auction_epoch = d_idx;
Epoch.AuctionState storage auction = getCouponAuctionAtEpoch(temp_coupon_auction_epoch);
// skip auctions that have been canceled, dead or not finished auction present?
if (!auction.canceled && !auction.dead && auction.isInit && auction.finished) {
sumYield += getAvgYieldFilled(temp_coupon_auction_epoch);
totalAvailableAuctions++;
}
}

return sumYield.div(totalAvailableAuctions);
}

/**
* Governance
*/
Expand Down
48 changes: 47 additions & 1 deletion protocol/contracts/dao/Market.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ contract Market is Comptroller, Curve {
event CouponRedemption(address indexed account, uint256 indexed epoch, uint256 couponAmount);
event CouponTransfer(address indexed from, address indexed to, uint256 indexed epoch, uint256 value);
event CouponApproval(address indexed owner, address indexed spender, uint256 value);

event CouponBidPlaced(address indexed account, uint256 indexed epoch, uint256 dollarAmount, uint256 maxCouponAmount);

function step() internal {
// Expire prior coupons
for (uint256 i = 0; i < expiringCoupons(epoch()); i++) {
Expand Down Expand Up @@ -117,4 +118,49 @@ contract Market is Comptroller, Curve {

emit CouponTransfer(sender, recipient, epoch, amount);
}

function placeCouponAuctionBid(uint256 couponEpochExpiry, uint256 dollarAmount, uint256 maxCouponAmount) external returns (bool) {
Require.that(
couponEpochExpiry > 0,
FILE,
"Must have non-zero expiry"
);

Require.that(
dollarAmount > 0,
FILE,
"Must bid non-zero amount"
);

Require.that(
maxCouponAmount > 0,
FILE,
"Must bid on non-zero amount"
);

Require.that(
acceptableBidCheck(msg.sender, dollarAmount),
FILE,
"Must have enough in account"
);

uint256 yield = maxCouponAmount.div(dollarAmount);
uint256 maxYield = Constants.getCouponMaxYieldToBurn();

Require.that(
maxYield >= yield,
FILE,
"Must be under maxYield"
);

uint256 epochExpiry = epoch().add(couponEpochExpiry);
setCouponAuctionRelYield(maxCouponAmount.div(dollarAmount));
setCouponAuctionRelDollarAmount(dollarAmount);
setCouponAuctionRelExpiry(epochExpiry);
setCouponBidderState(uint256(epoch()), msg.sender, couponEpochExpiry, dollarAmount, maxCouponAmount);
setCouponBidderStateIndex(uint256(epoch()), getCouponAuctionBids(uint256(epoch())), msg.sender);
incrementCouponAuctionBids();
emit CouponBidPlaced(msg.sender, epochExpiry, dollarAmount, maxCouponAmount);
return true;
}
}
Loading