diff --git a/.gas-snapshot b/.gas-snapshot index 2b0b45a..7a82cca 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,35 +1,45 @@ ExponentialCurveTest:test_getBuyInfoExample() (gas: 9113) -ExponentialCurveTest:test_getBuyInfoWithoutFee(uint128,uint64,uint8) (runs: 256, μ: 996, ~: 523) +ExponentialCurveTest:test_getBuyInfoWithoutFee(uint128,uint64,uint8) (runs: 256, μ: 961, ~: 523) ExponentialCurveTest:test_getSellInfoExample() (gas: 9052) -ExponentialCurveTest:test_getSellInfoWithoutFee(uint128,uint128,uint8) (runs: 256, μ: 1860, ~: 604) +ExponentialCurveTest:test_getSellInfoWithoutFee(uint128,uint128,uint8) (runs: 256, μ: 1892, ~: 604) +GDACurveTest:test_getBuyInfoExample() (gas: 315467) +GDACurveTest:test_getBuyInfoFuzz(uint48) (runs: 256, μ: 29500, ~: 29276) +GDACurveTest:test_getBuyInfoOverflow() (gas: 23490) +GDACurveTest:test_getBuyInfoTimeDecayTooLarge() (gas: 67767) +GDACurveTest:test_getBuyInfoWithFees() (gas: 69564) +GDACurveTest:test_getSellInfoExample() (gas: 316310) +GDACurveTest:test_getSellInfoFuzz(uint48) (runs: 256, μ: 30807, ~: 30583) +GDACurveTest:test_getSellInfoOverflow() (gas: 19706) +GDACurveTest:test_getSellInfoTimeBoostTooLarge() (gas: 69191) +GDACurveTest:test_getSellInfoWithFees() (gas: 70871) LinearCurveTest:test_getBuyInfoExample() (gas: 8642) -LinearCurveTest:test_getBuyInfoWithoutFee(uint128,uint128,uint8) (runs: 256, μ: 7249, ~: 8819) +LinearCurveTest:test_getBuyInfoWithoutFee(uint128,uint128,uint8) (runs: 256, μ: 7432, ~: 8819) LinearCurveTest:test_getSellInfoExample() (gas: 8503) -LinearCurveTest:test_getSellInfoWithoutFee(uint128,uint128,uint8) (runs: 256, μ: 7488, ~: 8927) -NoArbExponentialCurveEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 832090, ~: 1257232) -NoArbExponentialCurveEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 832631, ~: 1246069) -NoArbExponentialCurveEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 306180, ~: 407907) -NoArbExponentialCurveEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 287935, ~: 408372) -NoArbExponentialCurveMissingEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 817319, ~: 1265233) -NoArbExponentialCurveMissingEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 771543, ~: 1215053) -NoArbExponentialCurveMissingEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 294752, ~: 415908) -NoArbExponentialCurveMissingEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 250843, ~: 377356) -NoArbLinearCurveEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 770471, ~: 1258953) -NoArbLinearCurveEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 843740, ~: 1247790) -NoArbLinearCurveEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 320801, ~: 409628) -NoArbLinearCurveEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 300051, ~: 410093) -NoArbLinearCurveMissingEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 865661, ~: 1266954) -NoArbLinearCurveMissingEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 761095, ~: 1216774) -NoArbLinearCurveMissingEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 291987, ~: 417629) -NoArbLinearCurveMissingEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 252752, ~: 379077) -NoArbXykCurveEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 805923, ~: 1259565) -NoArbXykCurveEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 801145, ~: 1248402) -NoArbXykCurveEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 324331, ~: 410240) -NoArbXykCurveEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 309238, ~: 417713) -NoArbXykCurveMissingEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 839653, ~: 1267566) -NoArbXykCurveMissingEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 797784, ~: 1217386) -NoArbXykCurveMissingEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 320663, ~: 418241) -NoArbXykCurveMissingEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 284274, ~: 386697) +LinearCurveTest:test_getSellInfoWithoutFee(uint128,uint128,uint8) (runs: 256, μ: 7677, ~: 8927) +NoArbExponentialCurveEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 787888, ~: 1257232) +NoArbExponentialCurveEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 844182, ~: 1246069) +NoArbExponentialCurveEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 303951, ~: 407907) +NoArbExponentialCurveEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 302441, ~: 408372) +NoArbExponentialCurveMissingEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 802110, ~: 1265233) +NoArbExponentialCurveMissingEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 792715, ~: 1215053) +NoArbExponentialCurveMissingEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 304756, ~: 415908) +NoArbExponentialCurveMissingEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 250412, ~: 377356) +NoArbLinearCurveEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 815398, ~: 1258953) +NoArbLinearCurveEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 804787, ~: 1247790) +NoArbLinearCurveEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 311204, ~: 409628) +NoArbLinearCurveEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 290001, ~: 407749) +NoArbLinearCurveMissingEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 809741, ~: 1266954) +NoArbLinearCurveMissingEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 804159, ~: 1216774) +NoArbLinearCurveMissingEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 310917, ~: 417629) +NoArbLinearCurveMissingEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 247470, ~: 376733) +NoArbXykCurveEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 839624, ~: 1259565) +NoArbXykCurveEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 879788, ~: 1248402) +NoArbXykCurveEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 322536, ~: 410240) +NoArbXykCurveEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 310867, ~: 417713) +NoArbXykCurveMissingEnumerableERC20Test:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 779669, ~: 1267566) +NoArbXykCurveMissingEnumerableERC20Test:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 744288, ~: 1217386) +NoArbXykCurveMissingEnumerableETHTest:test_bondingCurveBuySellNoProfit(uint56,uint64,uint8) (runs: 256, μ: 295663, ~: 418241) +NoArbXykCurveMissingEnumerableETHTest:test_bondingCurveSellBuyNoProfit(uint56,uint64,uint8) (runs: 256, μ: 260721, ~: 386697) PAFExponentialCurveEnumerableERC20Test:testFail_callMint721() (gas: 19248) PAFExponentialCurveEnumerableERC20Test:testFail_changeAssetRecipientForTrade() (gas: 10713) PAFExponentialCurveEnumerableERC20Test:testFail_changeDeltaNotOwner() (gas: 18581) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d72a4d4..24c76c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,18 @@ jobs: with: submodules: recursive + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Install eth_abi + run: pip install eth_abi + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + - name: Install Foundry uses: onbjerg/foundry-toolchain@v1 with: diff --git a/Makefile b/Makefile index 3b9fa64..adf1ad8 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ solc:; nix-env -f https://github.com/dapphub/dapptools/archive/master.tar.gz -iA # Build & test build :; forge build --optimize -test :; forge test --optimize +test :; forge test --optimize --ffi fuzz :; forge test -v --optimize clean :; forge clean lint :; yarn run lint diff --git a/src/bonding-curves/GDACurve.sol b/src/bonding-curves/GDACurve.sol index 528dde5..bdebc0f 100644 --- a/src/bonding-curves/GDACurve.sol +++ b/src/bonding-curves/GDACurve.sol @@ -91,18 +91,14 @@ contract GDACurve is ICurve, CurveErrorCodes { // This is equal to buySpotPrice * (alpha^n - 1) / (alpha - 1). // We then divide the value by scalar^(lambda * timeElapsed) to factor in the exponential decay. { - inputValue = spotPrice_.mul(alphaPowN - FixedPointMathLib.WAD); - inputValue = inputValue.div(alpha - FixedPointMathLib.WAD); - inputValue = inputValue.div(decayFactor); + inputValue = + spotPrice_.mul(alphaPowN - FixedPointMathLib.WAD).div(alpha - FixedPointMathLib.WAD).div(decayFactor); // Account for the protocol fee, a flat percentage of the buy amount protocolFee = inputValue.mul(protocolFeeMultiplier); - // Account for the trade fee, only for Trade pools - inputValue += inputValue.mul(feeMultiplier); - - // Add the protocol fee to the required input amount - inputValue += protocolFee; + // Account for the trade and protocol fees + inputValue += inputValue.mul(feeMultiplier) + protocolFee; } // Update delta with the current timestamp @@ -144,7 +140,6 @@ contract GDACurve is ICurve, CurveErrorCodes { } (uint256 alpha,,) = _parseDelta(delta); - // TODO: this value may overflow, should we cap the value? uint256 alphaPowN = uint256(alpha).powu(numItems); // The new spot price is multiplied by the time boost and divided by alpha^n so future @@ -166,18 +161,15 @@ contract GDACurve is ICurve, CurveErrorCodes { // and q is the number of items to sell. // Our spot price implicity embeds the number of items already purchased and the previous time boost, so we just need to // do some simple adjustments to get the current e^(lambda * t) and alpha^(m + q - 1) values. - outputValue = spotPrice_.mul(boostFactor).div(uint256(alpha).powu(numItems - 1)); - outputValue = outputValue.mul(alphaPowN - FixedPointMathLib.WAD); - outputValue = outputValue.div(alpha - FixedPointMathLib.WAD); + outputValue = spotPrice_.mul(boostFactor).div(alphaPowN.div(alpha)).mul(alphaPowN - FixedPointMathLib.WAD).div( + alpha - FixedPointMathLib.WAD + ); // Account for the protocol fee, a flat percentage of the sell amount protocolFee = outputValue.mul(protocolFeeMultiplier); - // Account for the trade fee, only for Trade pools - outputValue -= outputValue.mul(feeMultiplier); - - // Remove the protocol fee from the output amount - outputValue -= protocolFee; + // Account for the trade and protocol fees + outputValue -= (outputValue.mul(feeMultiplier) + protocolFee); // Update delta with the current timestamp newDelta = _getNewDelta(delta);