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

Multi VRGDA via Libraries & Structs #13

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
93e8a6c
multivariable VRGDA
saucepoint Sep 6, 2022
dfd923c
initial test
saucepoint Sep 6, 2022
1708c1d
add logic to original contracts
saucepoint Sep 6, 2022
fab64bb
tests for created VRGDAs
saucepoint Sep 6, 2022
fa32f60
basic tests for created VRGDA
saucepoint Sep 6, 2022
c88e16e
remove separate files
saucepoint Sep 6, 2022
39b4bf5
move VRGDA func to library; add example for multi VRGDA
saucepoint Sep 6, 2022
ed7e1a3
compiles
saucepoint Sep 7, 2022
4a89cef
minor organization changes
saucepoint Sep 7, 2022
aa60d74
bug squash, tests, and simplification of code
saucepoint Sep 7, 2022
946669f
documentation
saucepoint Sep 7, 2022
24b509a
revert state based multi vrgda
saucepoint Sep 7, 2022
852f095
Merge pull request #1 from saucepoint/libraried
saucepoint Sep 7, 2022
812e94e
remove state based multiVRGDA
saucepoint Sep 7, 2022
a23296f
gas snapshot
saucepoint Sep 7, 2022
6b50ad7
exploring struct and lib focused impl
saucepoint Sep 7, 2022
d7f4c72
simplification of code
saucepoint Sep 7, 2022
f7a1a10
temp test to measure gas
saucepoint Sep 7, 2022
c5dbac2
remove gas intense version
saucepoint Sep 7, 2022
d1f1291
reduce mem usage
saucepoint Sep 7, 2022
99346d1
add logisticVRGDAx; cleanup demo for clarity
saucepoint Sep 7, 2022
d89d20c
documentation and correct timeDelta logic
saucepoint Sep 7, 2022
bce4acb
reorganize
saucepoint Sep 8, 2022
2fc0d12
replace all VRGDA impl with lib struct impl
saucepoint Sep 8, 2022
a02cb3e
Merge pull request #2 from saucepoint/overwrite
saucepoint Sep 8, 2022
0bdab67
Sync with Master (#3)
saucepoint Sep 8, 2022
ae3fa30
choose our changes
saucepoint Sep 8, 2022
952cb97
remove log2lin in favor of lib
saucepoint Sep 8, 2022
363c688
merge in master
saucepoint Sep 8, 2022
04529bb
use solmate signedWadMath
saucepoint Sep 8, 2022
509ba39
dep updates
saucepoint Sep 8, 2022
f898035
reorder structs to shave 30 gas
saucepoint Sep 8, 2022
fed9831
reorder struct of log2in VRGDA; update gas snapshot
saucepoint Sep 8, 2022
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
58 changes: 33 additions & 25 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
LinearNFTTest:testCannotUnderpayForNFTMint() (gas: 37841)
LinearNFTTest:testMintManyNFT() (gas: 4177040)
LinearNFTTest:testMintNFT() (gas: 83907)
LinearVRGDATest:testAlwaysTargetPriceInRightConditions(uint256) (runs: 256, μ: 10109, ~: 10109)
LinearVRGDATest:testPricingBasic() (gas: 9972)
LinearVRGDATest:testTargetPrice() (gas: 10749)
LogisticNFTTest:testCannotMintMoreThanMax() (gas: 4409801)
LogisticNFTTest:testCannotUnderpayForNFTMint() (gas: 38508)
LogisticNFTTest:testMintAllNFT() (gas: 4399038)
LogisticNFTTest:testMintNFT() (gas: 84596)
LogisticToLinearNFTTest:testCannotUnderpayForNFTMint() (gas: 38595)
LogisticToLinearNFTTest:testMintManyNFT() (gas: 4252440)
LogisticToLinearNFTTest:testMintNFT() (gas: 84661)
LogisticToLinearVRGDATest:testAlwaysTargetPriceInRightConditions(uint256) (runs: 256, μ: 11029, ~: 10386)
LogisticToLinearVRGDATest:testPricingBasic() (gas: 10805)
LogisticToLinearVRGDATest:testSwitchSmoothness() (gas: 12669)
LogisticToLinearVRGDATest:testTargetPrice() (gas: 12376)
LogisticVRGDATest:testAlwaysTargetPriceInRightConditions(uint256) (runs: 256, μ: 11692, ~: 11692)
LogisticVRGDATest:testFailOverflowForBeyondLimitTokens(uint256,uint256) (runs: 256, μ: 10278, ~: 10278)
LogisticVRGDATest:testGetTargetSaleTimeDoesNotRevertEarly() (gas: 6147)
LogisticVRGDATest:testGetTargetSaleTimeRevertsWhenExpected() (gas: 8533)
LogisticVRGDATest:testNoOverflowForAllTokens(uint256,uint256) (runs: 256, μ: 11229, ~: 11229)
LogisticVRGDATest:testNoOverflowForMostTokens(uint256,uint256) (runs: 256, μ: 11385, ~: 11528)
LogisticVRGDATest:testPricingBasic() (gas: 10762)
LogisticVRGDATest:testTargetPrice() (gas: 12246)
ContractTest:testGasConsumption() (gas: 571342)
LinearNFTTest:testCannotUnderpayForNFTMint() (gas: 44315)
LinearNFTTest:testMintManyNFT() (gas: 4226039)
LinearNFTTest:testMintNFT() (gas: 90336)
LinearVRGDATest:testAlwaysTargetPriceInRightConditions(uint256) (runs: 256, μ: 17028, ~: 17028)
LinearVRGDATest:testPricingBasic() (gas: 16709)
LinearVRGDATest:testTargetPrice() (gas: 17668)
LogisticNFTTest:testCannotMintMoreThanMax() (gas: 4464882)
LogisticNFTTest:testCannotUnderpayForNFTMint() (gas: 47109)
LogisticNFTTest:testMintAllNFT() (gas: 4453602)
LogisticNFTTest:testMintNFT() (gas: 93152)
LogisticToLinearNFTTest:testCannotUnderpayForNFTMint() (gas: 53541)
LogisticToLinearNFTTest:testMintManyNFT() (gas: 4356639)
LogisticToLinearNFTTest:testMintNFT() (gas: 99562)
LogisticToLinearVRGDATest:testAlwaysTargetPriceInRightConditions(uint256) (runs: 256, μ: 27174, ~: 27794)
LogisticToLinearVRGDATest:testPricingBasic() (gas: 25913)
LogisticToLinearVRGDATest:testSwitchSmoothness() (gas: 32261)
LogisticToLinearVRGDATest:testTargetPrice() (gas: 28412)
LogisticVRGDATest:testAlwaysTargetPriceInRightConditions(uint256) (runs: 256, μ: 20645, ~: 20645)
LogisticVRGDATest:testFailOverflowForBeyondLimitTokens(uint256,uint256) (runs: 256, μ: 18849, ~: 18849)
LogisticVRGDATest:testGetTargetSaleTimeDoesNotRevertEarly() (gas: 10360)
LogisticVRGDATest:testGetTargetSaleTimeRevertsWhenExpected() (gas: 12740)
LogisticVRGDATest:testNoOverflowForAllTokens(uint256,uint256) (runs: 256, μ: 19894, ~: 19894)
LogisticVRGDATest:testNoOverflowForMostTokens(uint256,uint256) (runs: 256, μ: 20067, ~: 20193)
LogisticVRGDATest:testPricingBasic() (gas: 19502)
LogisticVRGDATest:testTargetPrice() (gas: 21199)
MultiNFTTest:testCannotPublicMintMoreThanMax() (gas: 4472784)
MultiNFTTest:testCannotUnderpayForPresaleNFTMint() (gas: 44404)
MultiNFTTest:testCannotUnderpayForPublicNFTMint() (gas: 48276)
MultiNFTTest:testMintAllPublicNFT() (gas: 4463971)
MultiNFTTest:testMintManyPresaleNFT() (gas: 4237217)
MultiNFTTest:testMintPresaleNFT() (gas: 90481)
MultiNFTTest:testMintPublicNFT() (gas: 96830)
44 changes: 0 additions & 44 deletions src/LinearVRGDA.sol

This file was deleted.

64 changes: 64 additions & 0 deletions src/LinearVRGDALib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {unsafeWadDiv, toWadUnsafe} from "solmate/utils/SignedWadMath.sol";

import {VRGDALib, VRGDAx} from "./VRGDALib.sol";

struct LinearVRGDAx {
VRGDAx vrgda;
int256 perTimeUnit;
}

/// @title Linear Variable Rate Gradual Dutch Auction
/// @author transmissions11 <t11s@paradigm.xyz>
/// @author FrankieIsLost <frankie@paradigm.xyz>
/// @author saucepoint
/// @notice VRGDA with a linear issuance curve.
library LinearVRGDALib {

/// @notice Create a Linear VRGDA using specified parameters.
/// @param _targetPrice The target price for a token if sold on pace, scaled by 1e18.
/// @param _priceDecayPercent The percent price decays per unit of time with no sales, scaled by 1e18.
/// @param _perTimeUnit The number of tokens to target sell in 1 full unit of time, scaled by 1e18.
/// @return linearVRGDA The created Linear VRGDA (of type struct LinearVRGDAx).
function createLinearVRGDA(
int256 _targetPrice,
int256 _priceDecayPercent,
int256 _perTimeUnit
) internal pure returns (LinearVRGDAx memory linearVRGDA) {
linearVRGDA = LinearVRGDAx(
VRGDALib.createVRGDA(_targetPrice, _priceDecayPercent),
_perTimeUnit
);
}

/*//////////////////////////////////////////////////////////////
PRICING LOGIC
//////////////////////////////////////////////////////////////*/

/// @notice Calculate the price of a token according to the VRGDA formula.
/// @param self a VRGDA represented as the LinearVRGDAx struct
/// @param timeSinceStart Units of time passed since the VRGDA began, scaled by 1e18.
/// @param sold The number of tokens sold so far, scaled by 1e18.
/// @return uint256 The price of a token according to VRGDA, scaled by 1e18.
function getVRGDAPrice(LinearVRGDAx memory self, int256 timeSinceStart, uint256 sold)
internal
pure
returns (uint256)
{
int256 timeDelta;
unchecked {
timeDelta = timeSinceStart - getTargetSaleTime(self.perTimeUnit, toWadUnsafe(sold + 1));
}
return VRGDALib.getVRGDAPrice(self.vrgda.targetPrice, self.vrgda.decayConstant, timeDelta);
}

/// @dev Given a number of tokens sold, return the target time that number of tokens should be sold by.
/// @param sold A number of tokens sold, scaled by 1e18, to get the corresponding target sale time for.
/// @return int256 The target time the tokens should be sold by, scaled by 1e18, where the time is
/// relative, such that 0 means the tokens should be sold immediately when the VRGDA begins.
function getTargetSaleTime(int256 perTimeUnit, int256 sold) internal pure returns (int256) {
return unsafeWadDiv(sold, perTimeUnit);
}
}
71 changes: 0 additions & 71 deletions src/LogisticToLinearVRGDA.sol

This file was deleted.

65 changes: 0 additions & 65 deletions src/LogisticVRGDA.sol

This file was deleted.

71 changes: 71 additions & 0 deletions src/LogisticVRGDALib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {wadMul, wadLn, unsafeDiv, unsafeWadDiv, toWadUnsafe} from "solmate/utils/SignedWadMath.sol";

import {VRGDALib, VRGDAx} from "./VRGDALib.sol";

struct LogisticVRGDAx {
VRGDAx vrgda;
int256 logisticLimit;
int256 timeScale;
}

/// @title Logistic Variable Rate Gradual Dutch Auction
/// @author transmissions11 <t11s@paradigm.xyz>
/// @author FrankieIsLost <frankie@paradigm.xyz>
/// @author saucepoint
/// @notice VRGDA with a logistic issuance curve.
library LogisticVRGDALib {

/// @notice Create a Logistic VRGDA using specified parameters.
/// @param _targetPrice The target price for a token if sold on pace, scaled by 1e18.
/// @param _priceDecayPercent The percent price decays per unit of time with no sales, scaled by 1e18.
/// @param _maxSellable The maximum number of tokens to sell, scaled by 1e18.
/// @param _timeScale The steepness of the logistic curve, scaled by 1e18.
function createLogisticVRGDA(
int256 _targetPrice,
int256 _priceDecayPercent,
int256 _maxSellable,
int256 _timeScale
) internal pure returns (LogisticVRGDAx memory logisticVRGDAx) {
logisticVRGDAx = LogisticVRGDAx(
VRGDALib.createVRGDA(_targetPrice, _priceDecayPercent),
_maxSellable + 1e18, // add 1 wad to make the limit inclusive of _maxSellable
_timeScale
);
}

/*//////////////////////////////////////////////////////////////
PRICING LOGIC
//////////////////////////////////////////////////////////////*/

/// @notice Calculate the price of a token according to the VRGDA formula.
/// @param self a VRGDA represented as the LinearVRGDAx struct
/// @param timeSinceStart Units of time passed since the VRGDA began, scaled by 1e18.
/// @param sold The number of tokens sold so far, scaled by 1e18.
/// @return uint256 The price of a token according to VRGDA, scaled by 1e18.
function getVRGDAPrice(LogisticVRGDAx memory self, int256 timeSinceStart, uint256 sold)
internal
pure
returns (uint256)
{
int256 timeDelta;
unchecked {
timeDelta = timeSinceStart - getTargetSaleTime(self.logisticLimit, self.timeScale, toWadUnsafe(sold + 1));
}
return VRGDALib.getVRGDAPrice(self.vrgda.targetPrice, self.vrgda.decayConstant, timeDelta);
}

/// @dev Given a number of tokens sold, return the target time that number of tokens should be sold by.
/// @param logisticLimit The logistic limit (maximum number of tokens to sell), scaled by 1e18.
/// @param timeScale The steepness of the logistic curve, scaled by 1e18.
/// @param sold A number of tokens sold, scaled by 1e18, to get the corresponding target sale time for.
/// @return int256 The target time the tokens should be sold by, scaled by 1e18, where the time is
/// relative, such that 0 means the tokens should be sold immediately when the VRGDA begins.
function getTargetSaleTime(int256 logisticLimit, int256 timeScale, int256 sold) internal pure returns (int256) {
unchecked {
return -unsafeWadDiv(wadLn(unsafeDiv(logisticLimit * 2e18, sold + logisticLimit) - 1e18), timeScale);
}
}
}
Loading