Skip to content

Commit

Permalink
Merge pull request #159 from SweeprFi/baseswap
Browse files Browse the repository at this point in the history
Baseswap
  • Loading branch information
CelaPablo authored Feb 7, 2024
2 parents 6ff2716 + e6dcc90 commit f084fc4
Show file tree
Hide file tree
Showing 35 changed files with 816 additions and 736 deletions.
30 changes: 30 additions & 0 deletions contracts/AMM/BaseswapAMM.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

// ==========================================================
// ====================== BaseswapAMM.sol ===================
// ==========================================================

/**
* @title Baseswap AMM
* @dev Interactions with BaseSwap
*/

import "./UniswapAMM.sol";

contract BaseswapAMM is UniswapAMM {

constructor(
address _sweep,
address _base,
address _sequencer,
address _pool,
address _oracleBase,
uint256 _oracleBaseUpdateFrequency,
address _liquidityHelper,
address _router
) UniswapAMM(
_sweep, _base, _sequencer, _pool, _oracleBase,
_oracleBaseUpdateFrequency, _liquidityHelper, _router
) {}
}
228 changes: 9 additions & 219 deletions contracts/AMM/PancakeAMM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,12 @@ pragma solidity 0.8.19;

/**
* @title Pancake AMM
* @dev Interactions with UniswapV3
* @dev Interactions with PancakeSwap
*/

import "../Libraries/Chainlink.sol";
import { PancakeLiquidityHelper, IPancakePool } from "../Utils/PancakeLiquidityHelper.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@uniswap/v3-periphery/contracts/libraries/OracleLibrary.sol";
import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "../Balancer/IMarketMaker.sol";
import "../Sweep/ISweep.sol";
import { UniswapAMM } from "./UniswapAMM.sol";

contract PancakeAMM {
using Math for uint256;

ISwapRouter private constant ROUTER = ISwapRouter(0x1b81D678ffb9C0263b24A97847620C99d213eB14);

IERC20Metadata public immutable base;
ISweep public immutable sweep;
IPriceFeed public immutable oracleBase;
IPriceFeed public immutable sequencer;
address public immutable pool;
uint256 public immutable oracleBaseUpdateFrequency;
bool private immutable flag; // The sort status of tokens
PancakeLiquidityHelper private immutable liquidityHelper;
IMarketMaker public marketMaker;

uint32 private constant LOOKBACK = 1 days;
uint16 private constant DEADLINE_GAP = 15 minutes;
uint256 private constant PRECISION = 1e6;
contract PancakeAMM is UniswapAMM {

constructor(
address _sweep,
Expand All @@ -47,195 +21,11 @@ contract PancakeAMM {
address _pool,
address _oracleBase,
uint256 _oracleBaseUpdateFrequency,
address _liquidityHelper
) {
sweep = ISweep(_sweep);
base = IERC20Metadata(_base);
oracleBase = IPriceFeed(_oracleBase);
sequencer = IPriceFeed(_sequencer);
pool = _pool;
oracleBaseUpdateFrequency = _oracleBaseUpdateFrequency;
liquidityHelper = PancakeLiquidityHelper(_liquidityHelper);
flag = _base < _sweep;
}

// Events
event Bought(uint256 usdxAmount);
event Sold(uint256 sweepAmount);

// Errors
error ZeroAmount();
error BadRate();
error NotOwnerOrGov();

modifier onlyOwner () {
if (msg.sender != sweep.fastMultisig() && msg.sender != sweep.owner())
revert NotOwnerOrGov();
_;
}

/**
* @notice Get Price
* @dev Get the quote for selling 1 unit of a token.
*/
function getPrice() public view returns (uint256 amountOut) {
int24 tick = liquidityHelper.getCurrentTick(pool);

uint256 quote = OracleLibrary.getQuoteAtTick(
tick,
uint128(10 ** sweep.decimals()),
address(sweep),
address(base)
);
uint256 price = ChainlinkLibrary.getPrice(
oracleBase,
sequencer,
oracleBaseUpdateFrequency
);

uint8 quoteDecimals = base.decimals();
uint8 priceDecimals = ChainlinkLibrary.getDecimals(oracleBase);

amountOut = PRECISION.mulDiv(quote * price, 10 ** (quoteDecimals + priceDecimals));
}

function getPriceAtCurrentTick() public view returns (uint256) {
int24 tick = liquidityHelper.getCurrentTick(pool);
return getPriceAtTick(tick);
}

function getPriceAtTick(int24 tick) public view returns (uint256 price) {
uint256 quote = OracleLibrary.getQuoteAtTick(
tick,
uint128(10 ** sweep.decimals()),
address(sweep),
address(base)
);
uint8 quoteDecimals = base.decimals();
price = PRECISION.mulDiv(quote, 10 ** quoteDecimals);
}

function getTickFromPrice(uint256 price, uint8 decimals, int24 tickSpacing) public view returns (int24) {
return liquidityHelper.getTickFromPrice(price, decimals, tickSpacing, flag);
}

/**
* @notice Get TWA Price
* @dev Get the quote for selling 1 unit of a token.
*/
function getTWAPrice() external view returns (uint256 amountOut) {
uint256 price = ChainlinkLibrary.getPrice(
oracleBase,
sequencer,
oracleBaseUpdateFrequency
);

// Get the average price tick first
(int24 arithmeticMeanTick, ) = OracleLibrary.consult(pool, LOOKBACK);

// Get the quote for selling 1 unit of a token.
uint256 quote = OracleLibrary.getQuoteAtTick(
arithmeticMeanTick,
uint128(10 ** sweep.decimals()),
address(sweep),
address(base)
);

uint8 quoteDecimals = base.decimals();
uint8 priceDecimals = ChainlinkLibrary.getDecimals(oracleBase);

amountOut = PRECISION.mulDiv(quote * price, 10 ** (quoteDecimals + priceDecimals));
}

function getPositions(uint256 tokenId)
public view
returns (uint256 usdxAmount, uint256 sweepAmount, uint256 lp)
{
lp = 0;
(uint256 amount0, uint256 amount1) = liquidityHelper.getTokenAmountsFromLP(tokenId, pool);
(usdxAmount, sweepAmount) = flag ? (amount0, amount1) : (amount1, amount0);
}

/* ========== Actions ========== */

/**
* @notice Buy Sweep
* @param usdxAddress Token Address to use for buying sweep.
* @param usdxAmount Token Amount.
* @param amountOutMin Minimum amount out.
* @dev Increases the sweep balance and decrease collateral balance.
*/
function buySweep(address usdxAddress, uint256 usdxAmount, uint256 amountOutMin)
external returns (uint256 sweepAmount)
{
if (address(marketMaker) != address(0) && marketMaker.getBuyPrice() < getPrice() ) {
TransferHelper.safeTransferFrom(address(base), msg.sender, address(this), usdxAmount);
TransferHelper.safeApprove(address(base), address(marketMaker), usdxAmount);
sweepAmount = marketMaker.buySweep(usdxAmount);
TransferHelper.safeTransfer(address(sweep), msg.sender, sweepAmount);
} else {
checkRate(usdxAddress, usdxAmount, amountOutMin);
sweepAmount = swap(usdxAddress, address(sweep), usdxAmount, amountOutMin, pool);
}

emit Bought(usdxAmount);
}

/**
* @notice Sell Sweep
* @param usdxAddress Token Address to return after selling sweep.
* @param sweepAmount Sweep Amount.
* @param amountOutMin Minimum amount out.
* @dev Decreases the sweep balance and increase collateral balance
*/
function sellSweep(address usdxAddress, uint256 sweepAmount, uint256 amountOutMin)
external returns (uint256 tokenAmount)
{
emit Sold(sweepAmount);
checkRate(usdxAddress, amountOutMin, sweepAmount);
tokenAmount = swap(address(sweep), usdxAddress, sweepAmount, amountOutMin, pool);
}

function setMarketMaker(address _marketMaker) external onlyOwner {
marketMaker = IMarketMaker(_marketMaker);
}

/**
* @notice Swap tokenA into tokenB using uniV3Router.ExactInputSingle()
* @param tokenA Address to in
* @param tokenB Address to out
* @param amountIn Amount of _tokenA
* @param amountOutMin Minimum amount out.
* @param poolAddress Pool to use in the swap
*/
function swap(address tokenA, address tokenB, uint256 amountIn, uint256 amountOutMin, address poolAddress)
private returns (uint256 amountOut)
{
// Approval
TransferHelper.safeTransferFrom(tokenA, msg.sender, address(this), amountIn);
TransferHelper.safeApprove(tokenA, address(ROUTER), amountIn);

ISwapRouter.ExactInputSingleParams memory swapParams = ISwapRouter
.ExactInputSingleParams({
tokenIn: tokenA,
tokenOut: tokenB,
fee: IPancakePool(poolAddress).fee(),
recipient: msg.sender,
deadline: block.timestamp + DEADLINE_GAP,
amountIn: amountIn,
amountOutMinimum: amountOutMin,
sqrtPriceLimitX96: 0
});

amountOut = ROUTER.exactInputSingle(swapParams);
}

function checkRate(address usdxAddress, uint256 usdxAmount, uint256 sweepAmount) internal view {
if(usdxAmount == 0 || sweepAmount == 0) revert ZeroAmount();
uint256 tokenFactor = 10 ** IERC20Metadata(usdxAddress).decimals();
uint256 sweepFactor = 10 ** sweep.decimals();
uint256 rate = usdxAmount * sweepFactor * PRECISION / (tokenFactor * sweepAmount);
address _pancakeLiquidityHelper,
address _router
) UniswapAMM(
_sweep, _base, _sequencer, _pool, _oracleBase,
_oracleBaseUpdateFrequency, _pancakeLiquidityHelper, _router
) {}

if(rate > 16e5 || rate < 6e5) revert BadRate();
}
}
35 changes: 18 additions & 17 deletions contracts/AMM/UniswapAMM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,29 @@ pragma solidity 0.8.19;
* @dev Interactions with UniswapV3
*/

import "../Libraries/Chainlink.sol";
import "../Utils/LiquidityHelper.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@uniswap/v3-periphery/contracts/libraries/OracleLibrary.sol";
import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "../Balancer/IMarketMaker.sol";
import "../Sweep/ISweep.sol";
import { IPriceFeed, ChainlinkLibrary } from "../Libraries/Chainlink.sol";
import { ILiquidityHelper } from "../Utils/ILiquidityHelper.sol";
import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import { OracleLibrary } from "@uniswap/v3-periphery/contracts/libraries/OracleLibrary.sol";
import { TransferHelper } from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { IMarketMaker } from "../Balancer/IMarketMaker.sol";
import { ISweep } from "../Sweep/ISweep.sol";

contract UniswapAMM {
using Math for uint256;

ISwapRouter private constant ROUTER = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);

ISwapRouter private immutable router;
IERC20Metadata public immutable base;
ISweep public immutable sweep;
IPriceFeed public immutable oracleBase;
IPriceFeed public immutable sequencer;
address public immutable pool;
uint256 public immutable oracleBaseUpdateFrequency;
bool private immutable flag; // The sort status of tokens
LiquidityHelper private immutable liquidityHelper;
ILiquidityHelper private immutable liquidityHelper;
IMarketMaker public marketMaker;

// Uniswap V3
Expand All @@ -48,16 +47,18 @@ contract UniswapAMM {
address _pool,
address _oracleBase,
uint256 _oracleBaseUpdateFrequency,
address _liquidityHelper
address _liquidityHelper,
address _router
) {
sweep = ISweep(_sweep);
base = IERC20Metadata(_base);
oracleBase = IPriceFeed(_oracleBase);
sequencer = IPriceFeed(_sequencer);
pool = _pool;
oracleBaseUpdateFrequency = _oracleBaseUpdateFrequency;
liquidityHelper = LiquidityHelper(_liquidityHelper);
liquidityHelper = ILiquidityHelper(_liquidityHelper);
flag = _base < _sweep;
router = ISwapRouter(_router);
}

// Events
Expand Down Expand Up @@ -213,7 +214,7 @@ contract UniswapAMM {
{
// Approval
TransferHelper.safeTransferFrom(tokenA, msg.sender, address(this), amountIn);
TransferHelper.safeApprove(tokenA, address(ROUTER), amountIn);
TransferHelper.safeApprove(tokenA, address(router), amountIn);

ISwapRouter.ExactInputSingleParams memory swapParams = ISwapRouter
.ExactInputSingleParams({
Expand All @@ -227,7 +228,7 @@ contract UniswapAMM {
sqrtPriceLimitX96: 0
});

amountOut = ROUTER.exactInputSingle(swapParams);
amountOut = router.exactInputSingle(swapParams);
}

function checkRate(address usdxAddress, uint256 usdxAmount, uint256 sweepAmount) internal view {
Expand Down
3 changes: 2 additions & 1 deletion contracts/Balancer/BalancerMarketMaker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ pragma solidity 0.8.19;
* Increases and decreases the liquidity
*/

import { Stabilizer, TransferHelper, ISweep } from "../Stabilizer/Stabilizer.sol";
import { Stabilizer } from "../Stabilizer/Stabilizer.sol";
import { TransferHelper } from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import { IBalancerPool, IBalancerVault, IAsset, JoinKind, ExitKind } from "../Assets/Interfaces/Balancer/IBalancer.sol";

contract BalancerMarketMaker is Stabilizer {
Expand Down
28 changes: 28 additions & 0 deletions contracts/Balancer/BaseswapMarketMaker.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

// ====================================================================
// ===================== BaseswapMarketMaker.sol ======================
// ====================================================================

/**
* @title Baseswap Market Maker
* @dev Implementation:
* Mints a new LP.
* Increases and decreases the liquidity for the LP created.
* Collects fees from the LP.
*/

import { UniswapMarketMaker } from "./UniswapMarketMaker.sol";

contract BaseswapMarketMaker is UniswapMarketMaker {

constructor(
string memory _name,
address _sweep,
address _usdx,
address _oracleUsdx,
address _positionManager,
address _borrower
) UniswapMarketMaker(_name, _sweep, _usdx, _oracleUsdx, _positionManager, _borrower) {}
}
Loading

0 comments on commit f084fc4

Please sign in to comment.