Skip to content

Commit

Permalink
good place to stop invariants
Browse files Browse the repository at this point in the history
  • Loading branch information
giovannidisiena committed Sep 15, 2024
1 parent 0ac596c commit 40e8e45
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 121 deletions.
19 changes: 12 additions & 7 deletions contracts/SmartVaultYieldManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,26 @@ contract SmartVaultYieldManager is ISmartVaultYieldManager, Ownable {
: FullMath.mulDiv((10 ** bDec) * (10 ** (36 - aDec)), priceX192, 1 << 192);
}

uint256 _ratio = FullMath.mulDiv(_tokenABalance * (10 ** (36 - aDec)), 1e36, _midRatio * (10 ** (36 - bDec)));
uint256 _ratio =
FullMath.mulDiv(_tokenABalance * (10 ** (36 - aDec)), 1e36, _midRatio * (10 ** (36 - bDec)));
uint256 _rb = FullMath.mulDiv(_tokenBBalance * (10 ** (36 - bDec)), _ratio, 1e36);

if (_tokenABalance * (10 ** (36 - aDec)) > _rb) {
// a -> b

uint256 _denominator = 1e36 + FullMath.mulDiv(_ratio - FullMath.mulDiv(_ratio, _fee, 1e6), 1e36, price36);
uint256 _denominator =
1e36 + FullMath.mulDiv(_ratio - FullMath.mulDiv(_ratio, _fee, 1e6), 1e36, price36);
// a - rb / (1 + (1-f) * ratio / price)
_amountIn = FullMath.mulDiv(_tokenABalance * (10 ** (36 - aDec)) - _rb, 1e36, _denominator) / 10 ** (36 - aDec);
_amountIn =
FullMath.mulDiv(_tokenABalance * (10 ** (36 - aDec)) - _rb, 1e36, _denominator) / 10 ** (36 - aDec);
} else {
// b -> a

uint256 _denominator = 1e36 + FullMath.mulDiv(_ratio, 1e36, price36 + FullMath.mulDiv(price36, _fee, 1e6));

uint256 _denominator =
1e36 + FullMath.mulDiv(_ratio, 1e36, price36 + FullMath.mulDiv(price36, _fee, 1e6));
// rb - a / (1 + ratio / ((1+f) * price))
_amountOut = FullMath.mulDiv(_rb - _tokenABalance * (10 ** (36 - aDec)), 1e36, _denominator) / 10 ** (36 - aDec);
_amountOut =
FullMath.mulDiv(_rb - _tokenABalance * (10 ** (36 - aDec)), 1e36, _denominator) / 10 ** (36 - aDec);
}
}

Expand Down Expand Up @@ -253,7 +258,7 @@ contract SmartVaultYieldManager is ISmartVaultYieldManager, Ownable {
}

function _otherDeposit(address _collateralToken, HypervisorData memory _hypervisorData) private {
_swapToRatio(_collateralToken, _hypervisorData.hypervisor, uniswapRouter, _hypervisorData.poolFee); // TODO: for some reason, this is messing up the invariant tests – uniswap slot0 reverts
_swapToRatio(_collateralToken, _hypervisorData.hypervisor, uniswapRouter, _hypervisorData.poolFee);
_deposit(_hypervisorData.hypervisor);
}

Expand Down
13 changes: 6 additions & 7 deletions contracts/test_utils/MockSwapRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ contract MockSwapRouter is ISwapRouter, IPeripheryImmutableState {

function getAmountOut(uint256 _amountIn, address _tokenIn, address _tokenOut) private view returns (uint256) {
uint160 sqrtPrice = sqrtRates[_tokenIn][_tokenOut];
if(sqrtPrice != 0) {
if (sqrtPrice != 0) {
uint256 priceX192 = uint256(sqrtPrice) * uint256(sqrtPrice);
return FullMath.mulDiv(_amountIn, priceX192, 1 << 192);
}

sqrtPrice = sqrtRates[_tokenOut][_tokenIn];
if(sqrtPrice != 0) {
if (sqrtPrice != 0) {
uint256 priceX192 = uint256(sqrtPrice) * uint256(sqrtPrice);
return FullMath.mulDiv(_amountIn, 1 << 192, priceX192);
}
Expand Down Expand Up @@ -100,16 +100,15 @@ contract MockSwapRouter is ISwapRouter, IPeripheryImmutableState {
IERC20(_tokenOut).transfer(params.recipient, params.amountOut);
}


function getAmountIn(uint256 _amountOut, address _tokenIn, address _tokenOut) private view returns (uint256) {
uint160 sqrtPrice = sqrtRates[_tokenIn][_tokenOut];
if(sqrtPrice != 0) {
if (sqrtPrice != 0) {
uint256 priceX192 = uint256(sqrtPrice) * uint256(sqrtPrice);
return FullMath.mulDiv(_amountOut, 1 << 192, priceX192);
}

sqrtPrice = sqrtRates[_tokenOut][_tokenIn];
if(sqrtPrice != 0) {
if (sqrtPrice != 0) {
uint256 priceX192 = uint256(sqrtPrice) * uint256(sqrtPrice);
return FullMath.mulDiv(_amountOut, priceX192, 1 << 192);
}
Expand All @@ -120,8 +119,8 @@ contract MockSwapRouter is ISwapRouter, IPeripheryImmutableState {
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 _amountIn) {
_amountIn = getAmountIn(params.amountOut, params.tokenIn, params.tokenOut);

uint256 amountInWithFee = _amountIn + (_amountIn * params.fee / 1e6);
require(amountInWithFee <= params.amountInMaximum,"price too high");
uint256 amountInWithFee = _amountIn + (_amountIn * params.fee / 1e6);
require(amountInWithFee <= params.amountInMaximum, "price too high");
if (msg.value == 0) {
IERC20(params.tokenIn).transferFrom(msg.sender, address(this), amountInWithFee);
}
Expand Down
17 changes: 11 additions & 6 deletions test/foundry/differential/SwapToRatio.sol
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,22 @@ contract SwapToRatioNew is SwapToRatioBase {
: FullMath.mulDiv((10 ** bDec) * (10 ** (36 - aDec)), priceX192, 1 << 192);
}

uint256 _ratio = FullMath.mulDiv(_tokenABalance * (10 ** (36 - aDec)), 1e36, _midRatio * (10 ** (36 - bDec)));
uint256 _ratio =
FullMath.mulDiv(_tokenABalance * (10 ** (36 - aDec)), 1e36, _midRatio * (10 ** (36 - bDec)));
uint256 _rb = FullMath.mulDiv(_tokenBBalance * (10 ** (36 - bDec)), _ratio, 1e36);

if (_tokenABalance * (10 ** (36 - aDec)) > _rb) {
// a -> b
uint256 _denominator = 1e36 + FullMath.mulDiv(_ratio - FullMath.mulDiv(_ratio, swapFee, 1e6), 1e36, price36);
_amountIn = FullMath.mulDiv(_tokenABalance * (10 ** (36 - aDec)) - _rb, 1e36, _denominator) / 10 ** (36 - aDec);
uint256 _denominator =
1e36 + FullMath.mulDiv(_ratio - FullMath.mulDiv(_ratio, swapFee, 1e6), 1e36, price36);
_amountIn =
FullMath.mulDiv(_tokenABalance * (10 ** (36 - aDec)) - _rb, 1e36, _denominator) / 10 ** (36 - aDec);
} else {
// b -> a
uint256 _denominator = 1e36 + FullMath.mulDiv(_ratio, 1e36, price36 - FullMath.mulDivRoundingUp(price36, swapFee, 1e6));
_amountOut = FullMath.mulDiv(_rb - _tokenABalance * (10 ** (36 - aDec)), 1e36, _denominator) / 10 ** (36 - aDec);
uint256 _denominator =
1e36 + FullMath.mulDiv(_ratio, 1e36, price36 - FullMath.mulDivRoundingUp(price36, swapFee, 1e6));
_amountOut =
FullMath.mulDiv(_rb - _tokenABalance * (10 ** (36 - aDec)), 1e36, _denominator) / 10 ** (36 - aDec);
}
}
if (_tokenBBalance < _midRatio) {
Expand All @@ -211,7 +216,7 @@ contract SwapToRatioNew is SwapToRatioBase {
IERC20(_tokenIn).safeApprove(swapRouter, 0);
} else {
// we want more tokenA

address _tokenIn = _tokenAIs0 ? _token1 : _token0;
address _tokenOut = _tokenAIs0 ? _token0 : _token1;

Expand Down
24 changes: 8 additions & 16 deletions test/foundry/differential/SwapToRatio.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ contract SwapToRatioTest is Test {
internal
returns (uint160 _boundedSqrtPriceX96)
{

// Ensure _sqrtPriceX96 is within uniswap limits
_boundedSqrtPriceX96 = uint160(bound(uint256(_sqrtPriceX96), 4295128739, 3e37));

Expand Down Expand Up @@ -80,14 +79,11 @@ contract SwapToRatioTest is Test {
return FullMath.mulDiv(1e18, priceX192, 1 << 192);
}

function test_swapToRatioFuzz(
uint256 priceTick,
uint256 ratioTick,
uint256 _tokenABalance,
uint256 _tokenBBalance
) public {
int24 boundedPriceTick = int24(int256(bound(priceTick, 0, 300_000*2))) - 300_000;
int24 boundedRatioTick = int24(int256(bound(ratioTick, 0, 80_000*2))) - 80_000;
function test_swapToRatioFuzz(uint256 priceTick, uint256 ratioTick, uint256 _tokenABalance, uint256 _tokenBBalance)
public
{
int24 boundedPriceTick = int24(int256(bound(priceTick, 0, 300_000 * 2))) - 300_000;
int24 boundedRatioTick = int24(int256(bound(ratioTick, 0, 80_000 * 2))) - 80_000;

console.log("max price: %s, min price: %s", getPriceAtTick(300_000), getPriceAtTick(-300_000));
console.log("max ratio %s, min ratio: %s", getPriceAtTick(80_000), getPriceAtTick(-80_000));
Expand Down Expand Up @@ -128,8 +124,8 @@ contract SwapToRatioTest is Test {
console.log("newTokenBBalance", newTokenBBalance);

// ratio passed in is reversed in uniProxy, hence B over A here
assertApproxEqAbs(_ratio, (oldTokenBBalance * 1e18) / oldTokenABalance , (_ratio) / 1000, "old wrong");
assertApproxEqAbs(_ratio, (newTokenBBalance * 1e18) / newTokenABalance , (_ratio) / 3000, "new wrong");
assertApproxEqAbs(_ratio, (oldTokenBBalance * 1e18) / oldTokenABalance, (_ratio) / 1000, "old wrong");
assertApproxEqAbs(_ratio, (newTokenBBalance * 1e18) / newTokenABalance, (_ratio) / 3000, "new wrong");
} else if (!successOld && successNew) {
console.log("old implementation reverted when the new one did not");
} else if (successOld && !successNew) {
Expand All @@ -142,11 +138,7 @@ contract SwapToRatioTest is Test {
}

// Run with forge test --mt test_swapToRatioFuzzPython -vvv --ffi
function test_xxswapToRatioFuzzPython(
uint160 _sqrtPriceX96,
uint256 _tokenABalance,
uint256 _tokenBBalance
) public {
function test_swapToRatioFuzzPython(uint160 _sqrtPriceX96, uint256 _tokenABalance, uint256 _tokenBBalance) public {
uint160 _boundedSqrtPriceX96 = setUpState(_sqrtPriceX96, _tokenABalance, _tokenBBalance, 0.5e18);

// Snapshot the state of the VM to revert to after each call
Expand Down
16 changes: 8 additions & 8 deletions test/foundry/fixtures/Common.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,29 +103,29 @@ contract Common {
ERC20Mock(address(0)),
clNativeUsd,
wbtcHypervisor,
abi.encode(address(weth), RAMSES_FEE, address(usdc)),
abi.encode(address(usdc), RAMSES_FEE, address(weth))
abi.encode(address(weth), UNISWAP_FEE, address(usdc)),
abi.encode(address(usdc), UNISWAP_FEE, address(weth))
); // wbtcHypervisor because all native token gets converted to its wrapped equivalent.
collateralData[bytes32(bytes(weth.symbol()))] = CollateralData(
ERC20Mock(address(weth)),
clNativeUsd,
wbtcHypervisor,
abi.encode(address(weth), RAMSES_FEE, address(usdc)),
abi.encode(address(usdc), RAMSES_FEE, address(weth))
abi.encode(address(weth), UNISWAP_FEE, address(usdc)),
abi.encode(address(usdc), UNISWAP_FEE, address(weth))
);
collateralData[bytes32(bytes(wbtcSymbol))] = CollateralData(
wbtc,
clWbtcUsd,
wbtcHypervisor,
abi.encode(address(wbtc), RAMSES_FEE, address(usdc)),
abi.encode(address(usdc), RAMSES_FEE, address(wbtc))
abi.encode(address(wbtc), UNISWAP_FEE, address(usdc)),
abi.encode(address(usdc), UNISWAP_FEE, address(wbtc))
);
collateralData[bytes32(bytes(linkSymbol))] = CollateralData(
link,
clLinkUsd,
linkHypervisor,
abi.encode(address(link), RAMSES_FEE, address(usdc)),
abi.encode(address(usdc), RAMSES_FEE, address(link))
abi.encode(address(link), UNISWAP_FEE, address(usdc)),
abi.encode(address(usdc), UNISWAP_FEE, address(link))
);

// all tokens
Expand Down
10 changes: 5 additions & 5 deletions test/foundry/fixtures/SmartVaultYieldManagerFixture.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ contract SmartVaultYieldManagerFixture is SmartVaultManagerFixture {
address(usdc), address(weth), 10 ** (18 + weth.decimals() - usdc.decimals()) / DEFAULT_ETH_USD_PRICE
); // 400000000000000000000000000: 2500 USDC <-> 1 WETH ✅ exactInput/Output

address wethUsdcPool = uniFactory.deploy(address(weth), address(usdc), RAMSES_FEE);
address wethUsdcPool = uniFactory.deploy(address(weth), address(usdc), UNISWAP_FEE);
IUniswapV3Pool(wethUsdcPool).initialize(_calcSqrtX96(address(usdc), address(weth), DEFAULT_ETH_USD_PRICE));

uniswapRouter.setRate(
Expand All @@ -93,7 +93,7 @@ contract SmartVaultYieldManagerFixture is SmartVaultManagerFixture {
address(wbtc),
10 ** (18 + wbtc.decimals() - usdc.decimals()) / (DEFAULT_ETH_USD_PRICE * DEFAULT_WBTC_ETH_MULTIPLIER)
); // 1600000000000000: 62500 USDC <-> 1 WBTC ✅ exactInput/Output
address usdcWbtcPool = uniFactory.deploy(address(usdc), address(wbtc), RAMSES_FEE);
address usdcWbtcPool = uniFactory.deploy(address(usdc), address(wbtc), UNISWAP_FEE);
IUniswapV3Pool(usdcWbtcPool).initialize(
_calcSqrtX96(address(usdc), address(wbtc), DEFAULT_ETH_USD_PRICE * DEFAULT_WBTC_ETH_MULTIPLIER)
);
Expand All @@ -108,7 +108,7 @@ contract SmartVaultYieldManagerFixture is SmartVaultManagerFixture {
address(link),
DEFAULT_LINK_ETH_DIVISOR * 10 ** (18 + link.decimals() - usdc.decimals()) / DEFAULT_ETH_USD_PRICE
); // 80000000000000000000000000000: 12.5 USDC <-> 1 LINK ✅ exactInput/Output
address usdcLinkPool = uniFactory.deploy(address(usdc), address(link), RAMSES_FEE);
address usdcLinkPool = uniFactory.deploy(address(usdc), address(link), UNISWAP_FEE);
IUniswapV3Pool(usdcLinkPool).initialize(
_calcSqrtX96(address(usdc), address(link), DEFAULT_ETH_USD_PRICE / DEFAULT_LINK_ETH_DIVISOR)
);
Expand All @@ -124,7 +124,7 @@ contract SmartVaultYieldManagerFixture is SmartVaultManagerFixture {
address(wbtc),
10 ** (18 + wbtc.decimals() - weth.decimals()) / (DEFAULT_WBTC_ETH_MULTIPLIER)
); // 4000000: 25 WETH <-> 1 WBTC ✅ exactInput/Output
address wbtcWethPool = uniFactory.deploy(address(wbtc), address(weth), RAMSES_FEE);
address wbtcWethPool = uniFactory.deploy(address(wbtc), address(weth), UNISWAP_FEE);
IUniswapV3Pool(wbtcWethPool).initialize(
_calcSqrtX96(address(weth), address(wbtc), DEFAULT_WBTC_ETH_MULTIPLIER)
);
Expand All @@ -135,7 +135,7 @@ contract SmartVaultYieldManagerFixture is SmartVaultManagerFixture {
uniswapRouter.setRate(
address(weth), address(link), DEFAULT_LINK_ETH_DIVISOR * 10 ** (18 + link.decimals() - weth.decimals())
); // 200000000000000000000: 1 WETH <-> 200 LINK ✅ exactInput/Output
address linkWethPool = uniFactory.deploy(address(link), address(weth), RAMSES_FEE);
address linkWethPool = uniFactory.deploy(address(link), address(weth), UNISWAP_FEE);
IUniswapV3Pool(linkWethPool).initialize(
_calcSqrtX96(address(link), address(weth), DEFAULT_LINK_ETH_DIVISOR)
);
Expand Down
Loading

0 comments on commit 40e8e45

Please sign in to comment.