Skip to content

Commit

Permalink
fixes bad slippage usage in the MM
Browse files Browse the repository at this point in the history
  • Loading branch information
maxcoto committed Dec 12, 2023
1 parent cfb83cd commit 7a5d74e
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 160 deletions.
77 changes: 23 additions & 54 deletions contracts/AMM/BalancerAMM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -128,69 +128,42 @@ contract BalancerAMM {

/**
* @notice Buy Sweep
* @param tokenAddress Token Address to use for buying sweep.
* @param tokenAmount Token Amount.
* @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 tokenAddress,
uint256 tokenAmount,
uint256 amountOutMin
) external returns (uint256 sweepAmount) {
bool lowerPriceInPool = true;

if (address(marketMaker) != address(0)) {
uint256 buyPrice = marketMaker.getBuyPrice();
if (buyPrice < getPrice()) {
lowerPriceInPool = false;
sweepAmount = (tokenAmount * (10 ** sweep.decimals())) / buyPrice;
uint256 slippage = (sweepAmount * (10 ** base.decimals()) / amountOutMin) - (10 ** base.decimals());

TransferHelper.safeTransferFrom(address(base), msg.sender, address(this), tokenAmount);
TransferHelper.safeApprove(address(base), address(marketMaker), tokenAmount);
marketMaker.buySweep(sweepAmount, slippage);
TransferHelper.safeTransfer(address(sweep), msg.sender, sweepAmount);
}
}

if(lowerPriceInPool) {
checkRate(tokenAddress, tokenAmount, amountOutMin);
sweepAmount = swap(
tokenAddress,
address(sweep),
tokenAmount,
amountOutMin,
address(pool)
);
}

emit Bought(tokenAmount);
function buySweep(address usdxAddress, uint256 usdxAmount, uint256 amountOutMin)
external returns (uint256 sweepAmount)
{
emit Bought(usdxAmount);

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, address(pool));
}
}

/**
* @notice Sell Sweep
* @param tokenAddress Token Address to return after selling 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 tokenAddress,
address usdxAddress,
uint256 sweepAmount,
uint256 amountOutMin
) external returns (uint256 tokenAmount) {
checkRate(tokenAddress, amountOutMin, sweepAmount);

tokenAmount = swap(
address(sweep),
tokenAddress,
sweepAmount,
amountOutMin,
address(pool)
);

emit Sold(sweepAmount);
checkRate(usdxAddress, amountOutMin, sweepAmount);
tokenAmount = swap(address(sweep), usdxAddress, sweepAmount, amountOutMin, address(pool));
}

/**
Expand Down Expand Up @@ -240,13 +213,9 @@ contract BalancerAMM {
* @param amountOutMin Minimum amount out.
* @param poolAddress The pool to execute the swap into
*/
function swap(
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOutMin,
address poolAddress
) public returns (uint256 amountOut) {
function swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOutMin, address poolAddress)
private returns (uint256 amountOut)
{
bytes32 poolId = IBalancerPool(poolAddress).getPoolId();
address vaultAddress = IBalancerPool(poolAddress).getVault();

Expand Down
104 changes: 50 additions & 54 deletions contracts/AMM/UniswapAMM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import "@openzeppelin/contracts/utils/math/Math.sol";
import "../Balancer/IMarketMaker.sol";
import "../Sweep/ISweep.sol";

import "hardhat/console.sol";

contract UniswapAMM {
using Math for uint256;

Expand Down Expand Up @@ -65,6 +67,8 @@ contract UniswapAMM {
event Sold(uint256 sweepAmount);

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

modifier onlyOwner () {
Expand Down Expand Up @@ -135,65 +139,44 @@ contract UniswapAMM {

/**
* @notice Buy Sweep
* @param tokenAddress Token Address to use for buying sweep.
* @param tokenAmount Token Amount.
* @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 tokenAddress,
uint256 tokenAmount,
uint256 amountOutMin
) external returns (uint256 sweepAmount) {
bool lowerPriceInPool = true;

if (address(marketMaker) != address(0)) {
uint256 buyPrice = marketMaker.getBuyPrice();
if (buyPrice < getPrice()) {
lowerPriceInPool = false;
sweepAmount = (tokenAmount * (10 ** sweep.decimals())) / buyPrice;
uint256 slippage = (sweepAmount * (10 ** base.decimals()) / amountOutMin) - (10 ** base.decimals());

TransferHelper.safeTransferFrom(address(base), msg.sender, address(this), tokenAmount);
TransferHelper.safeApprove(address(base), address(marketMaker), tokenAmount);
marketMaker.buySweep(sweepAmount, slippage);
TransferHelper.safeTransfer(address(sweep), msg.sender, sweepAmount);
}
}

if(lowerPriceInPool) {
sweepAmount = swap(
tokenAddress,
address(sweep),
tokenAmount,
amountOutMin,
pool
);
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(tokenAmount);
emit Bought(usdxAmount);
}

/**
* @notice Sell Sweep
* @param tokenAddress Token Address to return after selling 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 tokenAddress,
uint256 sweepAmount,
uint256 amountOutMin
) external returns (uint256 tokenAmount) {
function sellSweep(address usdxAddress, uint256 sweepAmount, uint256 amountOutMin)
external returns (uint256 tokenAmount)
{
emit Sold(sweepAmount);
tokenAmount = swap(
address(sweep),
tokenAddress,
sweepAmount,
amountOutMin,
pool
);
checkRate(usdxAddress, amountOutMin, sweepAmount);
tokenAmount = swap(address(sweep), usdxAddress, sweepAmount, amountOutMin, pool);
}

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

/**
Expand All @@ -204,13 +187,9 @@ contract UniswapAMM {
* @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
) public returns (uint256 amountOut) {
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);
Expand All @@ -230,7 +209,24 @@ contract UniswapAMM {
amountOut = ROUTER.exactInputSingle(swapParams);
}

function setMarketMaker(address _marketMaker) external onlyOwner {
marketMaker = IMarketMaker(_marketMaker);
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 * 1e6 / (tokenFactor * sweepAmount);

console.log("usdxAmount:");
console.log(usdxAmount);

console.log("sweepAmount:");
console.log(sweepAmount);

console.log("usdxAddress:");
console.log(usdxAddress);

console.log("rate:");
console.log(rate);

if(rate > 16e5 || rate < 6e5) revert BadRate();
}
}
73 changes: 59 additions & 14 deletions contracts/Assets/ERC20Asset.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,21 @@ pragma solidity 0.8.19;
* @dev Representation of an on-chain investment like Wrapped Ether, Wrapped Bitcoin ...
*/

import "../Stabilizer/Stabilizer.sol";
import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import { Stabilizer, IPriceFeed, IAMM, ChainlinkLibrary, OvnMath, TransferHelper, IERC20Metadata } from "../Stabilizer/Stabilizer.sol";
import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";

import "hardhat/console.sol";

contract ERC20Asset is Stabilizer {
uint16 private constant DEADLINE_GAP = 15 minutes;
ISwapRouter private constant ROUTER = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);

// Variables
IERC20Metadata private immutable token;
IPriceFeed private immutable oracleToken;
address private immutable poolAddress;
IUniswapV3Pool private immutable pool;

// Events
event Invested(uint256 indexed tokenAmount);
Expand All @@ -30,12 +38,12 @@ contract ERC20Asset is Stabilizer {
address _oracleUsdx,
address _oracleToken,
address _borrower,
address _poolAddress
address _pool

) Stabilizer(_name, _sweep, _usdx, _oracleUsdx, _borrower) {
token = IERC20Metadata(_token);
oracleToken = IPriceFeed(_oracleToken);
poolAddress = _poolAddress;
pool = IUniswapV3Pool(_pool);
}

/* ========== Views ========== */
Expand Down Expand Up @@ -108,15 +116,12 @@ contract ERC20Asset is Stabilizer {
if (usdxBalance == 0) revert NotEnoughBalance();
if (usdxBalance < usdxAmount) usdxAmount = usdxBalance;

IAMM _amm = amm();
uint256 usdxInToken = _oracleUsdxToToken(usdxAmount);
TransferHelper.safeApprove(address(usdx), address(_amm), usdxAmount);
uint256 tokenAmount = _amm.swap(
uint256 tokenAmount = swap(
address(usdx),
address(token),
usdxAmount,
OvnMath.subBasisPoints(usdxInToken, slippage),
poolAddress
OvnMath.subBasisPoints(usdxInToken, slippage)
);

emit Invested(tokenAmount);
Expand All @@ -130,20 +135,60 @@ contract ERC20Asset is Stabilizer {
uint256 tokenBalance = token.balanceOf(address(this));
if (tokenBalance < tokenAmount) tokenAmount = tokenBalance;

IAMM _amm = amm();
uint256 tokenInUsdx = _oracleTokenToUsdx(tokenAmount);
TransferHelper.safeApprove(address(token), address(_amm), tokenAmount);
divestedAmount = _amm.swap(
divestedAmount = swap(
address(token),
address(usdx),
tokenAmount,
OvnMath.subBasisPoints(tokenInUsdx, slippage),
poolAddress
OvnMath.subBasisPoints(tokenInUsdx, slippage)
);

emit Divested(divestedAmount);
}

/**
* @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.
*/
function swap(
address tokenA,
address tokenB,
uint256 amountIn,
uint256 amountOutMin
) internal returns (uint256 amountOut) {
// Approval
TransferHelper.safeApprove(tokenA, address(ROUTER), amountIn);

console.log("tokenA:");
console.log(tokenA);

console.log("tokenB:");
console.log(tokenB);

console.log("amountIn:");
console.log(amountIn);

console.log("amountOutMin:");
console.log(amountOutMin);

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

amountOut = ROUTER.exactInputSingle(swapParams);
}

function _oracleTokenToUsd(
uint256 tokenAmount
) internal view returns (uint256) {
Expand Down
Loading

0 comments on commit 7a5d74e

Please sign in to comment.