Skip to content

Commit

Permalink
Merge pull request #175 from gammaswap/fix/deltaswap-upd2
Browse files Browse the repository at this point in the history
publish package
  • Loading branch information
0xDanr committed Apr 21, 2024
2 parents d278510 + 1dc59f2 commit c5e1688
Show file tree
Hide file tree
Showing 17 changed files with 77 additions and 113 deletions.
2 changes: 1 addition & 1 deletion contracts/interfaces/external/IFeeSource.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
pragma solidity >=0.8.0;

/// @title Interface for contract that has fee information for transacting with AMM
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
pragma solidity ^0.8.0;
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

interface IDSPair {
import "../cpmm/ICPMM.sol";

/// @title Interface for DeltaSwapV2 CFMM implementations
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @notice Interface to get reserve tokens, deposit liquidity, withdraw liquidity, and swap tokens
/// @dev Interface assumes an UniswapV2 interface. Function mint() is used to deposit and burn() to withdraw
interface IDSV2Pair is ICPMM {

/// @notice Read reserve token quantities in the AMM, and timestamp of last update
/// @dev Reserve quantities come back as uint112 although we store them as uint128
/// @return reserve0 - quantity of token0 held in AMM
/// @return reserve1 - quantity of token1 held in AMM
/// @return blockTimestampLast - timestamp of the last update block
function getLPReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
/// @return rate - rate of growth of LP liquidity over the yield period
function getLPReserves() external view returns (uint112 reserve0, uint112 reserve1, uint256 rate);

/// @dev Get parameters used in fee calculation
/// @return _gammaPool - gammapool DeltaSwap pool is for
/// @return _stream0 - stream donations of token0 over the yield period
/// @return _stream1 - stream donations of token1 over the yield period
/// @return _gsFee - swap fee for gammaswap only
/// @return _dsFee - swap fee
/// @return _dsFeeThreshold - trehshold at which fees apply to swaps
/// @return _yieldPeriod - yield period in seconds
function getFeeParameters() external view returns(address _gammaPool, uint24 _gsFee, uint24 _dsFee, uint24 _dsFeeThreshold, uint24 _yieldPeriod);
function getFeeParameters() external view returns(address _gammaPool, bool _stream0, bool _stream1, uint16 _gsFee, uint16 _dsFee, uint24 _dsFeeThreshold, uint24 _yieldPeriod);

/// @dev Geometric mean of LP reserves
function rootK0() external view returns(uint112);
Expand Down
2 changes: 1 addition & 1 deletion contracts/libraries/FullMath.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity >=0.8.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
Expand Down
29 changes: 21 additions & 8 deletions contracts/strategies/cpmm/base/CPMMBaseLongStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ abstract contract CPMMBaseLongStrategy is BaseLongStrategy, CPMMBaseStrategy {
}

/// @dev See {BaseLongStrategy-calcTokensToRepay}.
function calcTokensToRepay(uint128[] memory reserves, uint256 liquidity, uint128[] memory maxAmounts) internal virtual override view
function calcTokensToRepay(uint128[] memory reserves, uint256 liquidity, uint128[] memory maxAmounts, bool isLiquidation) internal virtual override view
returns(uint256[] memory amounts) {

amounts = new uint256[](2);
Expand All @@ -57,15 +57,28 @@ abstract contract CPMMBaseLongStrategy is BaseLongStrategy, CPMMBaseStrategy {
amounts[0] = expectedLPTokens * reserves[0] / lastCFMMTotalSupply + 1;
amounts[1] = expectedLPTokens * reserves[1] / lastCFMMTotalSupply + 1;

if(!isLiquidation) {
uint256 actualLPTokens0 = amounts[0] * lastCFMMTotalSupply / reserves[0];
uint256 actualLPTokens1 = amounts[1] * lastCFMMTotalSupply / reserves[1];

if(actualLPTokens0 < actualLPTokens1) {
amounts[0] = amounts[1] * reserves[0] / reserves[1];
} else {
amounts[1] = amounts[0] * reserves[1] / reserves[0];
}
}

if(maxAmounts.length == 2) {
if(amounts[0] > maxAmounts[0]) {
unchecked {
if(amounts[0] - maxAmounts[0] > 1000) revert InsufficientTokenRepayment();
if(isLiquidation) {
if(amounts[0] > maxAmounts[0]) {
unchecked {
if(amounts[0] - maxAmounts[0] > 1000) revert InsufficientTokenRepayment();
}
}
}
if(amounts[1] > maxAmounts[1]) {
unchecked {
if(amounts[1] - maxAmounts[1] > 1000) revert InsufficientTokenRepayment();
if(amounts[1] > maxAmounts[1]) {
unchecked {
if(amounts[1] - maxAmounts[1] > 1000) revert InsufficientTokenRepayment();
}
}
}
amounts[0] = GSMath.min(amounts[0], maxAmounts[0]);
Expand Down
7 changes: 4 additions & 3 deletions contracts/strategies/deltaswap/DSV2ShortStrategy.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pragma solidity ^0.8.0;
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import "../../interfaces/external/deltaswap/IDSPair.sol";
import "../../interfaces/external/deltaswap/IDSV2Pair.sol";
import "../cpmm/CPMMShortStrategy.sol";

/// @title External Long Strategy concrete implementation contract for Streaming Yield Constant Product Market Maker
Expand All @@ -23,6 +24,6 @@ contract DSV2ShortStrategy is CPMMShortStrategy {
/// @dev See {BaseStrategy-getReserves}.
function getLPReserves(address cfmm, bool isLatest) internal virtual override(BaseStrategy, CPMMBaseStrategy) view returns(uint128[] memory reserves) {
reserves = new uint128[](2);
(reserves[0], reserves[1],) = IDSPair(cfmm).getLPReserves();
(reserves[0], reserves[1],) = IDSV2Pair(cfmm).getLPReserves();
}
}
9 changes: 5 additions & 4 deletions contracts/strategies/deltaswap/lending/DSV2BorrowStrategy.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pragma solidity ^0.8.0;
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import "../../../interfaces/external/deltaswap/IDSPair.sol";
import "../../../interfaces/external/deltaswap/IDSV2Pair.sol";
import "../../cpmm/lending/CPMMBorrowStrategy.sol";

/// @title External Long Strategy concrete implementation contract for Streaming Yield Constant Product Market Maker
Expand All @@ -18,12 +19,12 @@ contract DSV2BorrowStrategy is CPMMBorrowStrategy {
/// @dev See {BaseStrategy-getReserves}.
function getLPReserves(address cfmm, bool isLatest) internal virtual override(BaseStrategy, CPMMBaseStrategy) view returns(uint128[] memory reserves) {
reserves = new uint128[](2);
(reserves[0], reserves[1],) = IDSPair(cfmm).getLPReserves();
(reserves[0], reserves[1],) = IDSV2Pair(cfmm).getLPReserves();
}

/// @dev See {CPMMBaseLongStrategy-getTradingFee1}.
function getTradingFee1() internal virtual override view returns(uint24) {
(,uint24 gsFee,,,) = IDSPair(s.cfmm).getFeeParameters();
(,,,uint16 gsFee,,,) = IDSV2Pair(s.cfmm).getFeeParameters();
return tradingFee2 - gsFee;
}
}
40 changes: 5 additions & 35 deletions contracts/strategies/deltaswap/lending/DSV2RepayStrategy.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pragma solidity ^0.8.0;
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import "../../../interfaces/external/deltaswap/IDSPair.sol";
import "../../../interfaces/external/deltaswap/IDSV2Pair.sol";
import "../../cpmm/lending/CPMMRepayStrategy.sol";

/// @title External Long Strategy concrete implementation contract for Streaming Yield Constant Product Market Maker
Expand All @@ -18,43 +19,12 @@ contract DSV2RepayStrategy is CPMMRepayStrategy {
/// @dev See {BaseStrategy-getReserves}.
function getLPReserves(address cfmm, bool isLatest) internal virtual override(BaseStrategy, CPMMBaseStrategy) view returns(uint128[] memory reserves) {
reserves = new uint128[](2);
(reserves[0], reserves[1],) = IDSPair(cfmm).getLPReserves();
(reserves[0], reserves[1],) = IDSV2Pair(cfmm).getLPReserves();
}

/// @dev See {CPMMBaseLongStrategy-getTradingFee1}.
function getTradingFee1() internal virtual override view returns(uint24) {
(,uint24 gsFee,,,) = IDSPair(s.cfmm).getFeeParameters();
(,,,uint16 gsFee,,,) = IDSV2Pair(s.cfmm).getFeeParameters();
return tradingFee2 - gsFee;
}

/// @dev See {BaseLongStrategy-calcTokensToRepay}.
function calcTokensToRepay(uint128[] memory reserves, uint256 liquidity, uint128[] memory maxAmounts) internal virtual override(BaseLongStrategy, CPMMBaseLongStrategy) view
returns(uint256[] memory amounts) {
amounts = new uint256[](2);
uint256 lastCFMMInvariant = calcInvariant(address(0), s.CFMM_RESERVES);

uint256 lastCFMMTotalSupply = s.lastCFMMTotalSupply;
uint256 expectedLPTokens = liquidity * lastCFMMTotalSupply / lastCFMMInvariant;

uint256 rootK1 = calcInvariant(address(0), s.CFMM_RESERVES);
uint256 rootK0 = IDSPair(s.cfmm).rootK0();

amounts[0] = (expectedLPTokens * s.CFMM_RESERVES[0] / lastCFMMTotalSupply) * rootK0 / rootK1 + 10;
amounts[1] = (expectedLPTokens * s.CFMM_RESERVES[1] / lastCFMMTotalSupply) * rootK0 / rootK1 + 10;

if(maxAmounts.length == 2) {
if(amounts[0] > maxAmounts[0]) {
unchecked {
if(amounts[0] - maxAmounts[0] > 1000) revert InsufficientTokenRepayment();
}
}
if(amounts[1] > maxAmounts[1]) {
unchecked {
if(amounts[1] - maxAmounts[1] > 1000) revert InsufficientTokenRepayment();
}
}
amounts[0] = GSMath.min(amounts[0], maxAmounts[0]);
amounts[1] = GSMath.min(amounts[1], maxAmounts[1]);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pragma solidity ^0.8.0;
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import "../../../interfaces/external/deltaswap/IDSPair.sol";
import "../../../interfaces/external/deltaswap/IDSV2Pair.sol";
import "../../cpmm/liquidation/CPMMBatchLiquidationStrategy.sol";

/// @title External Long Strategy concrete implementation contract for Streaming Yield Constant Product Market Maker
Expand All @@ -19,12 +20,12 @@ contract DSV2BatchLiquidationStrategy is CPMMBatchLiquidationStrategy {
/// @dev See {BaseStrategy-getReserves}.
function getLPReserves(address cfmm, bool isLatest) internal virtual override(BaseStrategy, CPMMBaseStrategy) view returns(uint128[] memory reserves) {
reserves = new uint128[](2);
(reserves[0], reserves[1],) = IDSPair(cfmm).getLPReserves();
(reserves[0], reserves[1],) = IDSV2Pair(cfmm).getLPReserves();
}

/// @dev See {CPMMBaseLongStrategy-getTradingFee1}.
function getTradingFee1() internal virtual override view returns(uint24) {
(,uint24 gsFee,,,) = IDSPair(s.cfmm).getFeeParameters();
(,,,uint16 gsFee,,,) = IDSV2Pair(s.cfmm).getFeeParameters();
return tradingFee2 - gsFee;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import "../../../interfaces/external/deltaswap/IDSPair.sol";
import "../../../interfaces/external/deltaswap/IDSV2Pair.sol";
import "../../cpmm/liquidation/CPMMExternalLiquidationStrategy.sol";

/// @title External Liquidation Strategy concrete implementation contract for Streaming Yield Constant Product Market Maker
Expand All @@ -20,12 +20,12 @@ contract DSV2ExternalLiquidationStrategy is CPMMExternalLiquidationStrategy {
/// @dev See {BaseStrategy-getReserves}.
function getLPReserves(address cfmm, bool isLatest) internal virtual override(BaseStrategy, CPMMBaseStrategy) view returns(uint128[] memory reserves) {
reserves = new uint128[](2);
(reserves[0], reserves[1],) = IDSPair(cfmm).getLPReserves();
(reserves[0], reserves[1],) = IDSV2Pair(cfmm).getLPReserves();
}

/// @dev See {CPMMBaseLongStrategy-getTradingFee1}.
function getTradingFee1() internal virtual override view returns(uint24) {
(,uint24 gsFee,,,) = IDSPair(s.cfmm).getFeeParameters();
(,,,uint16 gsFee,,,) = IDSV2Pair(s.cfmm).getFeeParameters();
return tradingFee2 - gsFee;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import "../../../interfaces/external/deltaswap/IDSPair.sol";
import "../../../interfaces/external/deltaswap/IDSV2Pair.sol";
import "../../cpmm/liquidation/CPMMLiquidationStrategy.sol";

/// @title Liquidation Strategy concrete implementation contract for Streaming Yield Constant Product Market Maker
Expand All @@ -20,43 +20,12 @@ contract DSV2LiquidationStrategy is CPMMLiquidationStrategy {
/// @dev See {BaseStrategy-getReserves}.
function getLPReserves(address cfmm, bool isLatest) internal virtual override(BaseStrategy, CPMMBaseStrategy) view returns(uint128[] memory reserves) {
reserves = new uint128[](2);
(reserves[0], reserves[1],) = IDSPair(cfmm).getLPReserves();
(reserves[0], reserves[1],) = IDSV2Pair(cfmm).getLPReserves();
}

/// @dev See {CPMMBaseLongStrategy-getTradingFee1}.
function getTradingFee1() internal virtual override view returns(uint24) {
(,uint24 gsFee,,,) = IDSPair(s.cfmm).getFeeParameters();
(,,,uint16 gsFee,,,) = IDSV2Pair(s.cfmm).getFeeParameters();
return tradingFee2 - gsFee;
}

/// @dev See {BaseLongStrategy-calcTokensToRepay}.
function calcTokensToRepay(uint128[] memory reserves, uint256 liquidity, uint128[] memory maxAmounts) internal virtual override(BaseLongStrategy, CPMMBaseLongStrategy) view
returns(uint256[] memory amounts) {
amounts = new uint256[](2);
uint256 lastCFMMInvariant = calcInvariant(address(0), s.CFMM_RESERVES);

uint256 lastCFMMTotalSupply = s.lastCFMMTotalSupply;
uint256 expectedLPTokens = liquidity * lastCFMMTotalSupply / lastCFMMInvariant;

uint256 rootK1 = calcInvariant(address(0), s.CFMM_RESERVES);
uint256 rootK0 = IDSPair(s.cfmm).rootK0();

amounts[0] = (expectedLPTokens * s.CFMM_RESERVES[0] / lastCFMMTotalSupply) * rootK0 / rootK1 + 10;
amounts[1] = (expectedLPTokens * s.CFMM_RESERVES[1] / lastCFMMTotalSupply) * rootK0 / rootK1 + 10;

if(maxAmounts.length == 2) {
if(amounts[0] > maxAmounts[0]) {
unchecked {
if(amounts[0] - maxAmounts[0] > 1000) revert InsufficientTokenRepayment();
}
}
if(amounts[1] > maxAmounts[1]) {
unchecked {
if(amounts[1] - maxAmounts[1] > 1000) revert InsufficientTokenRepayment();
}
}
amounts[0] = GSMath.min(amounts[0], maxAmounts[0]);
amounts[1] = GSMath.min(amounts[1], maxAmounts[1]);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import "../../../interfaces/external/deltaswap/IDSPair.sol";
import "../../../interfaces/external/deltaswap/IDSV2Pair.sol";
import "../../cpmm/rebalance/CPMMExternalRebalanceStrategy.sol";

/// @title External Long Strategy concrete implementation contract for Streaming Yield Constant Product Market Maker
Expand All @@ -19,12 +19,12 @@ contract DSV2ExternalRebalanceStrategy is CPMMExternalRebalanceStrategy {
/// @dev See {BaseStrategy-getReserves}.
function getLPReserves(address cfmm, bool isLatest) internal virtual override(BaseStrategy, CPMMBaseStrategy) view returns(uint128[] memory reserves) {
reserves = new uint128[](2);
(reserves[0], reserves[1],) = IDSPair(cfmm).getLPReserves();
(reserves[0], reserves[1],) = IDSV2Pair(cfmm).getLPReserves();
}

/// @dev See {CPMMBaseLongStrategy-getTradingFee1}.
function getTradingFee1() internal virtual override view returns(uint24) {
(,uint24 gsFee,,,) = IDSPair(s.cfmm).getFeeParameters();
(,,,uint16 gsFee,,,) = IDSV2Pair(s.cfmm).getFeeParameters();
return tradingFee2 - gsFee;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ contract TestCPMMBatchLiquidationStrategy is CPMMBatchLiquidationStrategy, BaseB

function testCalcTokensToRepay(uint256 liquidity) external virtual view returns(uint256, uint256) {
uint256[] memory amounts;
amounts = calcTokensToRepay(s.CFMM_RESERVES, liquidity, new uint128[](0));
amounts = calcTokensToRepay(s.CFMM_RESERVES, liquidity, new uint128[](0), true);
return(amounts[0], amounts[1]);
}

Expand Down Expand Up @@ -177,7 +177,7 @@ contract TestCPMMBatchLiquidationStrategy is CPMMBatchLiquidationStrategy, BaseB
function checkExpectedUtilizationRate(uint256 lpTokens, bool isLoan) internal virtual override view {
}

function calcTokensToRepay(uint128[] memory reserves, uint256 liquidity, uint128[] memory maxAmounts) internal virtual override(BaseLongStrategy,CPMMBaseLongStrategy) view returns(uint256[] memory amounts) {
function calcTokensToRepay(uint128[] memory reserves, uint256 liquidity, uint128[] memory maxAmounts, bool isLiquidation) internal virtual override(BaseLongStrategy,CPMMBaseLongStrategy) view returns(uint256[] memory amounts) {
amounts = new uint256[](2);
uint256 lastCFMMInvariant = calcInvariant(address(0), reserves);

Expand Down
2 changes: 1 addition & 1 deletion contracts/test/strategies/cpmm/TestCPMMRepayStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ contract TestCPMMRepayStrategy is CPMMRepayStrategy, BorrowStrategy {
}

function testCalcTokensToRepay(uint256 liquidity) external virtual view returns(uint256, uint256) {
uint256[] memory amounts = calcTokensToRepay(s.CFMM_RESERVES, liquidity, new uint128[](0));
uint256[] memory amounts = calcTokensToRepay(s.CFMM_RESERVES, liquidity, new uint128[](0), false);
return(amounts[0], amounts[1]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ contract TestDSV2BatchLiquidationStrategy is DSV2BatchLiquidationStrategy, BaseB

function testCalcTokensToRepay(uint256 liquidity) external virtual view returns(uint256, uint256) {
uint256[] memory amounts;
amounts = calcTokensToRepay(s.CFMM_RESERVES, liquidity, new uint128[](0));
amounts = calcTokensToRepay(s.CFMM_RESERVES, liquidity, new uint128[](0), true);
return(amounts[0], amounts[1]);
}

Expand Down Expand Up @@ -177,7 +177,7 @@ contract TestDSV2BatchLiquidationStrategy is DSV2BatchLiquidationStrategy, BaseB
function checkExpectedUtilizationRate(uint256 lpTokens, bool isLoan) internal virtual override view {
}

function calcTokensToRepay(uint128[] memory reserves, uint256 liquidity, uint128[] memory maxAmounts) internal virtual override(BaseLongStrategy,CPMMBaseLongStrategy) view returns(uint256[] memory amounts) {
function calcTokensToRepay(uint128[] memory reserves, uint256 liquidity, uint128[] memory maxAmounts, bool isLiquidation) internal virtual override(BaseLongStrategy,CPMMBaseLongStrategy) view returns(uint256[] memory amounts) {
amounts = new uint256[](2);
uint256 lastCFMMInvariant = calcInvariant(address(0), reserves);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ contract TestDSV2RepayStrategy is DSV2RepayStrategy, BorrowStrategy {
}

function testCalcTokensToRepay(uint256 liquidity) external virtual view returns(uint256, uint256) {
uint256[] memory amounts = calcTokensToRepay(s.CFMM_RESERVES, liquidity, new uint128[](0));
uint256[] memory amounts = calcTokensToRepay(s.CFMM_RESERVES, liquidity, new uint128[](0), false);
return(amounts[0], amounts[1]);
}

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gammaswap/v1-implementations",
"version": "1.2.7",
"version": "1.2.8",
"description": "Pool and strategies implementation contracts for GammaSwap V1 protocol",
"homepage": "https://gammaswap.com",
"scripts": {
Expand Down Expand Up @@ -71,7 +71,7 @@
"typescript": "^4.7.4"
},
"dependencies": {
"@gammaswap/v1-core": "^1.2.6",
"@gammaswap/v1-core": "^1.2.7",
"@openzeppelin/contracts": "^4.7.0"
}
}

0 comments on commit c5e1688

Please sign in to comment.