Skip to content

Commit

Permalink
ExactInSingleBatch
Browse files Browse the repository at this point in the history
  • Loading branch information
ConjunctiveNormalForm committed Nov 17, 2023
1 parent 1d8f14f commit 55db578
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 5 deletions.
8 changes: 5 additions & 3 deletions contracts/interfaces/IQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ interface IQuoter {
error InvalidQuoteType();
error InvalidQuoteTypeInRevert();
error InvalidLockAcquiredSender();
error InvalidQuoteBatchParams();
error UnexpectedRevertBytes();

struct NonZeroDeltaCurrency {
Currency currency;
int128 deltaAmount;
struct PoolDeltas {
int128 currency0Delta;
int128 currency1Delta;
}

/// @notice Returns the delta amounts for a given exact input but for a swap of a single pool
/// @param params The params for the quote, encoded as `ExactInputSingleParams`
/// poolKey The key for identifying a V4 pool
Expand Down
40 changes: 39 additions & 1 deletion contracts/lens/Quoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract Quoter is IQuoter {

/// @inheritdoc IQuoter
function quoteExactInputSingle(ExactInputSingleParams memory params)
external
public
override
returns (int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint32 initializedTicksLoaded)
{
Expand All @@ -51,6 +51,44 @@ contract Quoter is IQuoter {
}
}

function quoteExactInputBatch(ExactInputSingleBatchParams memory params)
external
returns (
IQuoter.PoolDeltas[] memory deltas,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksLoadedList
)
{
if (
params.zeroForOnes.length != params.recipients.length || params.recipients.length != params.amountIns.length
|| params.amountIns.length != params.sqrtPriceLimitX96s.length
|| params.sqrtPriceLimitX96s.length != params.hookData.length
) {
revert InvalidQuoteBatchParams();
}

deltas = new IQuoter.PoolDeltas[](params.amountIns.length);
sqrtPriceX96AfterList = new uint160[](params.amountIns.length);
initializedTicksLoadedList = new uint32[](params.amountIns.length);

for (uint256 i = 0; i < params.amountIns.length; i++) {
ExactInputSingleParams memory singleParams = ExactInputSingleParams({
poolKey: params.poolKey,
zeroForOne: params.zeroForOnes[i],
recipient: params.recipients[i],
amountIn: params.amountIns[i],
sqrtPriceLimitX96: params.sqrtPriceLimitX96s[i],
hookData: params.hookData[i]
});
(int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint32 initializedTicksLoaded) =
quoteExactInputSingle(singleParams);

deltas[i] = IQuoter.PoolDeltas({currency0Delta: deltaAmounts[0], currency1Delta: deltaAmounts[1]});
sqrtPriceX96AfterList[i] = sqrtPriceX96After;
initializedTicksLoadedList[i] = initializedTicksLoaded;
}
}

function lockAcquired(bytes calldata encodedSwapIntention) external returns (bytes memory) {
if (msg.sender != address(manager)) {
revert InvalidLockAcquiredSender();
Expand Down
9 changes: 9 additions & 0 deletions contracts/libraries/SwapIntention.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ struct ExactInputSingleParams {
bytes hookData;
}

struct ExactInputSingleBatchParams {
PoolKey poolKey;
bool[] zeroForOnes;
address[] recipients;
uint128[] amountIns;
uint160[] sqrtPriceLimitX96s;
bytes[] hookData;
}

struct ExactInputParams {
Currency currencyIn;
PathKey[] path;
Expand Down
52 changes: 51 additions & 1 deletion test/Quoter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pragma solidity ^0.8.20;
import "forge-std/console.sol";
import {Test} from "forge-std/Test.sol";
import "../contracts/libraries/SwapIntention.sol";
import {IQuoter} from "../contracts/interfaces/IQuoter.sol";
import {Quoter} from "../contracts/lens/Quoter.sol";
import {LiquidityAmounts} from "../contracts/libraries/LiquidityAmounts.sol";
import {MockERC20} from "solmate/test/utils/mocks/MockERC20.sol";
Expand Down Expand Up @@ -51,7 +52,7 @@ contract QuoterTest is Test, Deployers {
quoter = new Quoter(address(manager));
positionManager = new PoolModifyPositionTest(manager);

// salts are chose so that address(token0) < address(token2) && address(1) < address(token2)
// salts are chosen so that address(token0) < address(token2) && address(1) < address(token2)
bytes32 salt1 = "ffff";
bytes32 salt2 = "gm";
token0 = new MockERC20{salt: salt1}("Test0", "0", 18);
Expand Down Expand Up @@ -113,6 +114,55 @@ contract QuoterTest is Test, Deployers {
assertEq(initializedTicksLoaded, 2);
}

function testQuoter_quoteExactInputBatch() public {
bool[] memory zeroForOnes = new bool[](2);
zeroForOnes[0] = true;
zeroForOnes[1] = false;

address[] memory recipients = new address[](2);
recipients[0] = address(this);
recipients[1] = address(this);

// repeat for the three arrays below
uint128[] memory amountIns = new uint128[](2);
amountIns[0] = 10000;
amountIns[1] = 10000;

uint160[] memory sqrtPriceLimitX96s = new uint160[](2);
sqrtPriceLimitX96s[0] = 0;
sqrtPriceLimitX96s[1] = 0;

bytes[] memory hookData = new bytes[](2);
hookData[0] = ZERO_BYTES;
hookData[1] = ZERO_BYTES;

(
IQuoter.PoolDeltas[] memory deltas,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksLoadedList
) = quoter.quoteExactInputBatch(
ExactInputSingleBatchParams({
poolKey: key02,
zeroForOnes: zeroForOnes,
recipients: recipients,
amountIns: amountIns,
sqrtPriceLimitX96s: sqrtPriceLimitX96s,
hookData: hookData
})
);
assertEq(deltas.length, 2);
assertEq(uint128(-deltas[0].currency1Delta), 9871);
assertEq(uint128(-deltas[1].currency0Delta), 9871);

assertEq(sqrtPriceX96AfterList.length, 2);
assertEq(sqrtPriceX96AfterList[0], 78461846509168490764501028180);
assertEq(sqrtPriceX96AfterList[1], 80001962924147897865541384515);

assertEq(initializedTicksLoadedList.length, 2);
assertEq(initializedTicksLoadedList[0], 2);
assertEq(initializedTicksLoadedList[1], 2);
}

function testQuoter_quoteExactInput_0to2_2TicksLoaded() public {
tokenPath.push(token0);
tokenPath.push(token2);
Expand Down

0 comments on commit 55db578

Please sign in to comment.