Last active
January 15, 2025 11:30
-
-
Save naps62/8872612ddb3a043c3341e1ae6a7287fd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.24; | |
import "openzeppelin-contracts/contracts/utils/math/Math.sol"; | |
import "src/Interfaces/IBorrowerOperations.sol"; | |
import {DECIMAL_PRECISION} from "src/Dependencies/Constants.sol"; | |
import "src/Zappers/Modules/Exchanges/UniswapV3/IUniswapV3Pool.sol"; | |
import "src/Zappers/Modules/Exchanges/UniswapV3/INonfungiblePositionManager.sol"; | |
import {ICrocSwapDex, CrocSwapDexHelper} from "src/Exchanges/CrocSwap/ICrocSwapDex.sol"; | |
INonfungiblePositionManager constant scrollUniV3PositionManager = | |
INonfungiblePositionManager(0xB39002E4033b162fAc607fc3471E205FA2aE5967); | |
ICrocSwapDex crocSwapDex = ICrocSwapDex(0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106); | |
// Initial liquidity values (these values need to be changed) | |
uint256 constant initialLiquidityTroveUsdqAmount = 500e18; | |
uint256 constant initialLiquidityTroveWethAmount = 500e18; | |
uint256 constant initialLiquidityTroveInterestRate = _1pct / 2; | |
uint256 constant initialLiquiditySpAmount = 100e18; | |
uint256 constant initialLiquidityUniV3Amount = 200e18; | |
uint256 constant initialLiquidityCrocSwapAmount = 200e18; | |
uint256 constant initialLiquidityExchangePrice = DECIMAL_PRECISION; // 10e18; // 1:1 ratio, same amount for both tokens (?) | |
uint24 constant UNIV3_FEE = 0.3e4; | |
function openInitialLiquidityTrove( | |
address deployer, | |
IBorrowerOperations borrowerOperations, | |
uint256 boldAmount, | |
uint256 collAmount, | |
uint256 annualInterestRate, | |
uint256 maxUpfrontFee | |
) { | |
borrowerOperations.openTrove( | |
deployer, // _owner | |
0, // _ownerIndex | |
collAmount, // _collAmount | |
boldAmount, // _boldAmount | |
0, // _upperHint | |
0, // _lowerHint | |
annualInterestRate, // _annualInterestRate | |
// type(uint256).max, // _maxUpfrontFee | |
maxUpfrontFee, // _maxUpfrontFee | |
address(0), // _addManager | |
address(0), // _removeManager | |
address(0) // _receiver | |
); | |
} | |
function depositInStabilityPool(IStabilityPool stabilityPool, uint256 boldAmount) { | |
stabilityPool.provideToSP( | |
boldAmount, // _topUp | |
false // _doClaim | |
); | |
} | |
struct ProvideUniV3LiquidityVars { | |
uint256 token2Amount; | |
uint256 price; | |
int24 TICK_SPACING; | |
int24 tick; | |
int24 tickLower; | |
int24 tickUpper; | |
address[2] tokens; | |
uint256[2] amounts; | |
} | |
// _price should be _token1 / _token2 | |
function provideUniV3Liquidity( | |
address deployer, | |
INonfungiblePositionManager uniV3PositionManager, | |
IERC20 _token1, | |
IERC20 _token2, | |
uint256 _token1Amount, | |
uint256 _price, | |
uint24 _fee | |
) returns (address uniV3PoolAddress, uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) { | |
ProvideUniV3LiquidityVars memory vars; | |
// tokens and amounts | |
vars.token2Amount = _token1Amount * DECIMAL_PRECISION / _price; | |
if (address(_token1) < address(_token2)) { | |
vars.tokens[0] = address(_token1); | |
vars.tokens[1] = address(_token2); | |
vars.amounts[0] = _token1Amount; | |
vars.amounts[1] = vars.token2Amount; | |
// inverse price if token1 goes first | |
vars.price = DECIMAL_PRECISION * DECIMAL_PRECISION / _price; | |
} else { | |
vars.tokens[0] = address(_token2); | |
vars.tokens[1] = address(_token1); | |
vars.amounts[0] = vars.token2Amount; | |
vars.amounts[1] = _token1Amount; | |
vars.price = _price; | |
} | |
uniV3PoolAddress = uniV3PositionManager.createAndInitializePoolIfNecessary( | |
vars.tokens[0], | |
vars.tokens[1], | |
_fee, | |
priceToSqrtPriceX96(vars.price) // sqrtPriceX96 | |
); | |
_token1.approve(address(uniV3PositionManager), _token1Amount); | |
_token2.approve(address(uniV3PositionManager), vars.token2Amount); | |
vars.TICK_SPACING = IUniswapV3Pool(uniV3PoolAddress).tickSpacing(); | |
(, vars.tick,,,,,) = IUniswapV3Pool(uniV3PoolAddress).slot0(); | |
vars.tickLower = (vars.tick - 6000) / vars.TICK_SPACING * vars.TICK_SPACING; | |
vars.tickUpper = (vars.tick + 6000) / vars.TICK_SPACING * vars.TICK_SPACING; | |
INonfungiblePositionManager.MintParams memory params = INonfungiblePositionManager.MintParams({ | |
token0: vars.tokens[0], | |
token1: vars.tokens[1], | |
fee: _fee, | |
tickLower: vars.tickLower, | |
tickUpper: vars.tickUpper, | |
amount0Desired: vars.amounts[0], | |
amount1Desired: vars.amounts[1], | |
amount0Min: 0, | |
amount1Min: 0, | |
recipient: deployer, | |
deadline: block.timestamp + 600 minutes | |
}); | |
(tokenId, liquidity, amount0, amount1) = uniV3PositionManager.mint(params); | |
} | |
function priceToSqrtPriceX96(uint256 _price) pure returns (uint160 sqrtPriceX96) { | |
// overflow vs precision | |
if (_price > (1 << 64)) { | |
// ~18.4e18 | |
sqrtPriceX96 = uint160(Math.sqrt(_price / DECIMAL_PRECISION) << 96); | |
} else { | |
sqrtPriceX96 = uint160(Math.sqrt((_price << 192) / DECIMAL_PRECISION)); | |
} | |
} | |
struct ProvideCrocSwapLiquidityVars { | |
uint256 token2Amount; | |
uint256 price; | |
address[2] tokens; | |
uint256[2] amounts; | |
uint128 liq; | |
uint128 limitLower; | |
uint128 limitHigher; | |
uint256 priceConvertedToQ64; | |
address base; | |
address quote; | |
} | |
function _initAndFundCrocSwapPools( | |
ICrocSwapDex crocSwapDex, | |
address _base, | |
address _quote, | |
uint256, /* _poolIdx */ | |
uint128 _price, // Q64.64 | |
uint128 liq, | |
uint128 limitLower, | |
uint128 limitHigher | |
) { | |
crocSwapDex.userCmd( | |
CrocSwapDexHelper.COLD_PROXY, | |
abi.encode(CrocSwapDexHelper.FIXED_INITPOOL_SUBCODE, _base, _quote, CrocSwapDexHelper.POOL_TYPE_INDEX, _price) | |
); | |
crocSwapDex.userCmd( | |
CrocSwapDexHelper.WARM_PATH, | |
abi.encode( | |
CrocSwapDexHelper.MINT_AMBIENT_LIQ_LP, // uint8 code | |
_base, // address base | |
_quote, // address quote | |
CrocSwapDexHelper.POOL_TYPE_INDEX, // uint256 poolIdx | |
0, // int24 bidTick -- ignored for ambient mint | |
0, // int24 askTick -- ignored for ambient mint | |
liq, // uint128 liq -- The total amount of liquidity being minted. Represented as sqrt(X*Y) | |
limitLower, // uint128 limitLower | |
limitHigher, // uint128 limitHigher | |
3, // uint8 reserveFlags -- ignored for ambient mint | |
address(0x0) // lpConduit -- all examples use 0x0 | |
) | |
); | |
} | |
function provideCrocSwapLiquidity( | |
ICrocSwapDex crocSwapDex, | |
IERC20 _token1, // collateral | |
IERC20 _token2, // quill | |
uint256 _token1Amount, | |
uint256 _price | |
) { | |
uint256 priceConvertedToQ64 = CrocSwapDexHelper.convertDecimalToQ64(_price, 18, address(_token1) < address(_token2)); | |
uint256 collAmount = _token1Amount; | |
uint256 boldAmount = collAmount * _price / DECIMAL_PRECISION; | |
_token1.approve(address(crocSwapDex), collAmount); | |
_token2.approve(address(crocSwapDex), boldAmount); | |
// If the values aren't decreased, the transfer fails. Still haven't figured out how to calculate this value the correct way. | |
uint128 liq = CrocSwapDexHelper.calcLiq(collAmount - DECIMAL_PRECISION, boldAmount - DECIMAL_PRECISION); | |
(uint128 limitLower, uint128 limitHigher) = CrocSwapDexHelper.calcLimits(priceConvertedToQ64, 50); // 50 = 0.5% | |
(address base, address quote) = CrocSwapDexHelper.getQuoteBaseOrder(address(_token1), address(_token2)); | |
_initAndFundCrocSwapPools( | |
crocSwapDex, | |
base, | |
quote, | |
CrocSwapDexHelper.POOL_TYPE_INDEX, | |
uint128(priceConvertedToQ64), | |
liq, | |
limitLower, | |
limitHigher | |
); | |
} |
In the matter regarding the usage of CrocImpact to have a similar behaviour of uniV3Quoter.quoteExactOutputSingle
, we tried the following (fully expecting to have some errors along the way) with unsuccessful results (921$ vs 1000$ expected):
function testCrocSwapImpact() public {
CrocSwapDexHelper.SwapParams memory params;
// Give B 1M scroll
deal(address(SCR_Token), B, 1_000_000 * DECIMAL_PRECISION);
uint256 startingBalance = IERC20(USDC_Token).balanceOf(B);
uint128 goalBalance = 1000 * (10**6); //1000$ USDC -- the amount we want after the trade, 10**6 is usdc decimal precision
(params.base, params.quote) = CrocSwapDexHelper.getQuoteBaseOrder(SCR_Token, USDC_Token);
params.poolIdx = CrocSwapDexHelper.POOL_TYPE_INDEX;
params.qty = goalBalance;
bool isUSDCBase = params.base == USDC_Token;
params.inBaseQty = isUSDCBase;
params.isBuy = isUSDCBase;
params.limitPrice = isUSDCBase ? 21267430153580247136652501917186561137 : 65538; // pure guess work
params.tip = 0; // I have no idea how to calculate this value, but from source code doesn't go beyond a percentage
params.settleFlags = 0;
params.minOut = 0; // we don't protect in a simulation
(int128 baseFlow, int128 quoteFlow, uint128 finalPrice) = crocImpact.calcImpact(
params.base,
params.quote,
params.poolIdx,
params.isBuy,
params.inBaseQty,
params.qty,
params.tip,
params.limitPrice
);
uint128 positiveQuoteFlow = uint128(quoteFlow < 0 ? -quoteFlow : quoteFlow);
//lets make the trade using the quoteFlow and validate the final usdc received
params.inBaseQty = !isUSDCBase;
params.isBuy = !isUSDCBase;
params.limitPrice = !isUSDCBase ? 21267430153580247136652501917186561137 : 65538;
params.qty = uint128(positiveQuoteFlow);
vm.prank(B);
IERC20(SCR_Token).approve(address(crocSwapDex), params.qty);
_makeSwap(B, params);
uint256 endBalance = IERC20(USDC_Token).balanceOf(B);
assertEq(endBalance, startingBalance + goalBalance, "Should have swapped requested amount");
}
[767460] CrocSwapDexTest::testCrocSwapImpact()
├─ [7564] SCROLL_Token::balanceOf(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67]) [staticcall]
│ ├─ [2640] 0x7600174E2a730a05da046fFA8Fc32DEC27FfdDC8::balanceOf(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67]) [delegatecall]
│ │ └─ ← [Return] 10000000000000000000000 [1e22]
│ └─ ← [Return] 10000000000000000000000 [1e22]
├─ [0] VM::load(SCROLL_Token: [0xd29687c813D741E2F938F4aC377128810E217b1b], 0x224944ccfb924ee8b8902e9a49912a4619b803e9c6556b1c0d9cf29dab4d6bbf) [staticcall]
│ └─ ← [Return] 0x00000000000000000000000000000000000000000000021e19e0c9bab2400000
├─ [0] VM::store(SCROLL_Token: [0xd29687c813D741E2F938F4aC377128810E217b1b], 0x224944ccfb924ee8b8902e9a49912a4619b803e9c6556b1c0d9cf29dab4d6bbf, 0x00000000000000000000000000000000000000000000d3c21bcecceda1000000)
│ └─ ← [Return]
├─ [1064] SCROLL_Token::balanceOf(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67]) [staticcall]
│ ├─ [640] 0x7600174E2a730a05da046fFA8Fc32DEC27FfdDC8::balanceOf(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67]) [delegatecall]
│ │ └─ ← [Return] 1000000000000000000000000 [1e24]
│ └─ ← [Return] 1000000000000000000000000 [1e24]
├─ [9726] 0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4::balanceOf(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67]) [staticcall]
│ ├─ [2529] 0x72e2451a2da1535DBf0E7CB1e8C69F56E00A7B7b::balanceOf(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67]) [delegatecall]
│ │ └─ ← [Return] 0
│ └─ ← [Return] 0
├─ [142877] croc-impact::calcImpact(0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4, SCROLL_Token: [0xd29687c813D741E2F938F4aC377128810E217b1b], 420, true, true, 1000000000 [1e9], 0, 21267430153580247136652501917186561137 [2.126e37]) [staticcall]
│ ├─ [2359] crocswapdex::readSlot(65045675089258841282994332466172103527827742192530481468407093350446163516931 [6.504e76]) [staticcall]
│ │ └─ ← [Return] 2450239689446769665 [2.45e18]
│ ├─ [2359] crocswapdex::readSlot(65006889788353940852689926802351332735102890341882464401732428711872028765721 [6.5e76]) [staticcall]
│ │ └─ ← [Return] 115915590301724596222916627725442542969048562989658926 [1.159e53]
│ ├─ [2359] crocswapdex::readSlot(65006889788353940852689926802351332735102890341882464401732428711872028765722 [6.5e76]) [staticcall]
│ │ └─ ← [Return] 47149863050986826133900635475216288887282883183700653560429249206747136 [4.714e70]
│ ├─ [2359] crocswapdex::readSlot(66866552608990375605202052641522377046085742402946055868805720340955794758882 [6.686e76]) [staticcall]
│ │ └─ ← [Return] 356811923176489970264571492366877383723057152 [3.568e44]
│ ├─ [2359] crocswapdex::readSlot(20153743646870408477948354023889050143355904149972425598230418071012053525713 [2.015e76]) [staticcall]
│ │ └─ ← [Return] 431359146674410236714672241392314090778194310760649159697657780764672 [4.313e68]
│ ├─ [2359] crocswapdex::readSlot(32128763096103394929436351677355610673920633202447988756069013005903164036045 [3.212e76]) [staticcall]
│ │ └─ ← [Return] 46190794918041564291974713252088386299427536731386242342219948396380160 [4.619e70]
│ ├─ [359] crocswapdex::readSlot(20153743646870408477948354023889050143355904149972425598230418071012053525713 [2.015e76]) [staticcall]
│ │ └─ ← [Return] 431359146674410236714672241392314090778194310760649159697657780764672 [4.313e68]
│ ├─ [2359] crocswapdex::readSlot(14250542383800123457919502695374030191199068465377793824974215286162652751352 [1.425e76]) [staticcall]
│ │ └─ ← [Return] 30004676772158823823198739836488888885663217747909494069179197966448770 [3e70]
│ ├─ [359] crocswapdex::readSlot(20153743646870408477948354023889050143355904149972425598230418071012053525713 [2.015e76]) [staticcall]
│ │ └─ ← [Return] 431359146674410236714672241392314090778194310760649159697657780764672 [4.313e68]
│ ├─ [2359] crocswapdex::readSlot(83537090791684539960054826961347336137087932342510657830515061306442206102083 [8.353e76]) [staticcall]
│ │ └─ ← [Return] 1393796574908163946345982392040522594123776 [1.393e42]
│ ├─ [2359] crocswapdex::readSlot(52205914590282670903256600491672532795729353470765552465906913532172711425882 [5.22e76]) [staticcall]
│ │ └─ ← [Return] 46785001607690179280724252944740303628192785222684035316507359634784256 [4.678e70]
│ ├─ [359] crocswapdex::readSlot(83537090791684539960054826961347336137087932342510657830515061306442206102083 [8.353e76]) [staticcall]
│ │ └─ ← [Return] 1393796574908163946345982392040522594123776 [1.393e42]
│ ├─ [2359] crocswapdex::readSlot(66182594575269931767542812509651178709174552897375869543104101992825555619338 [6.618e76]) [staticcall]
│ │ └─ ← [Return] 110859300695323430835670766037824721329995938174971843863643114069557248 [1.108e71]
│ └─ ← [Return] 1000000000 [1e9], -1246761801763041213301 [-1.246e21], 16762899212379 [1.676e13]
├─ [0] VM::prank(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67])
│ └─ ← [Return]
├─ [25137] SCROLL_Token::approve(crocswapdex: [0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106], 1246761801763041213301 [1.246e21])
│ ├─ [24710] 0x7600174E2a730a05da046fFA8Fc32DEC27FfdDC8::approve(crocswapdex: [0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106], 1246761801763041213301 [1.246e21]) [delegatecall]
│ │ ├─ emit Approval(owner: userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67], spender: crocswapdex: [0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106], value: 1246761801763041213301 [1.246e21])
│ │ └─ ← [Return] true
│ └─ ← [Return] true
├─ [0] VM::startPrank(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67])
│ └─ ← [Return]
├─ [429071] crocswapdex::userCmd(1, 0x00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a4000000000000000000000000d29687c813d741e2f938f4ac377128810e217b1b00000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043964bb5138c0e7b750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)
│ ├─ [398894] croc-hotproxy-2::userCmd(0x00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a4000000000000000000000000d29687c813d741e2f938f4ac377128810e217b1b00000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043964bb5138c0e7b750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [delegatecall]
│ │ ├─ [35428] 0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4::transfer(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67], 921381319 [9.213e8])
│ │ │ ├─ [34728] 0x72e2451a2da1535DBf0E7CB1e8C69F56E00A7B7b::transfer(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67], 921381319 [9.213e8]) [delegatecall]
│ │ │ │ ├─ emit Transfer(from: crocswapdex: [0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106], to: userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67], value: 921381319 [9.213e8])
│ │ │ │ └─ ← [Return] true
│ │ │ └─ ← [Return] true
│ │ ├─ [14170] SCROLL_Token::transferFrom(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67], crocswapdex: [0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106], 1246761801763041213301 [1.246e21])
│ │ │ ├─ [13737] 0x7600174E2a730a05da046fFA8Fc32DEC27FfdDC8::transferFrom(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67], crocswapdex: [0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106], 1246761801763041213301 [1.246e21]) [delegatecall]
│ │ │ │ ├─ emit Transfer(from: userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67], to: crocswapdex: [0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106], value: 1246761801763041213301 [1.246e21])
│ │ │ │ └─ ← [Return] true
│ │ │ └─ ← [Return] true
│ │ ├─ emit topic 0: 0x1f5359759208315a45fc3fa86af1948560d8b87afdcaf1702a110ce0fbc305f3
│ │ │ data: 0x0000000000000000000000000000000000000000000000000000000000000060ffffffffffffffffffffffffffffffffffffffffffffffffffffffffc914d639000000000000000000000000000000000000000000000043964bb5138c0e7b75000000000000000000000000000000000000000000000000000000000000014000000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a4000000000000000000000000d29687c813d741e2f938f4ac377128810e217b1b00000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043964bb5138c0e7b750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
│ │ └─ ← [Return] 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffc914d639000000000000000000000000000000000000000000000043964bb5138c0e7b75
│ └─ ← [Return] 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffc914d639000000000000000000000000000000000000000000000043964bb5138c0e7b75
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [1226] 0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4::balanceOf(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67]) [staticcall]
│ ├─ [529] 0x72e2451a2da1535DBf0E7CB1e8C69F56E00A7B7b::balanceOf(userB: [0x1b1E98f4912aE9014064a70537025EF338e6aD67]) [delegatecall]
│ │ └─ ← [Return] 921381319 [9.213e8]
│ └─ ← [Return] 921381319 [9.213e8]
├─ [0] VM::assertEq(921381319 [9.213e8], 1000000000 [1e9], "Should have swapped requested amount") [staticcall]
│ └─ ← [Revert] Should have swapped requested amount: 921381319 != 1000000000
└─ ← [Revert] Should have swapped requested amount: 921381319 != 1000000000
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Answering some of the questions from the markdown:
uniV3Quoter.quoteExactOutputSingle
like function?