Skip to content

Commit

Permalink
Merge PCSV3PositionUtils into PositionUtils to significantly reduce c…
Browse files Browse the repository at this point in the history
…ode duplication.
  • Loading branch information
gnarlycow committed Mar 31, 2024
1 parent 663c8a1 commit 48a4751
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 297 deletions.
33 changes: 0 additions & 33 deletions contracts/EphemeralAllPositionsByOwner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity ^0.8.0;

import "./PositionUtils.sol";
import "./PCSV3PositionUtils.sol";

/// @notice A lens for Uniswap v3 that peeks into the current state of all positions by an owner without deployment
/// @author Aperture Finance
Expand Down Expand Up @@ -35,35 +34,3 @@ contract EphemeralAllPositionsByOwner is PositionUtils {
}
}
}

/// @notice A lens for PancakeSwap v3 that peeks into the current state of all positions by an owner without deployment
/// @author Aperture Finance
/// @dev The return data can be accessed externally by `eth_call` without a `to` address or internally by catching the
/// revert data, and decoded by `abi.decode(data, (PCSV3PositionState[]))`
contract PCSV3EphemeralAllPositionsByOwner is PCSV3PositionUtils {
constructor(INPM npm, address owner) payable {
PCSV3PositionState[] memory positions = allPositions(npm, owner);
bytes memory returnData = abi.encode(positions);
assembly ("memory-safe") {
// The return data in a constructor will be written to code, which may exceed the contract size limit.
revert(add(returnData, 0x20), mload(returnData))
}
}

/// @dev Public function to expose the abi for easier decoding using TypeChain
/// @param npm Nonfungible position manager
/// @param owner The address that owns the NFTs
function allPositions(INPM npm, address owner) public payable returns (PCSV3PositionState[] memory positions) {
uint256 balance = NPMCaller.balanceOf(npm, owner);
positions = new PCSV3PositionState[](balance);
unchecked {
for (uint256 i; i < balance; ++i) {
uint256 tokenId = NPMCaller.tokenOfOwnerByIndex(npm, owner, i);
PCSV3PositionState memory state = positions[i];
state.owner = owner;
positionInPlace(npm, tokenId, state.position);
peek(npm, tokenId, state);
}
}
}
}
24 changes: 0 additions & 24 deletions contracts/EphemeralGetPosition.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity ^0.8.0;

import "./PositionUtils.sol";
import "./PCSV3PositionUtils.sol";

/// @notice A lens for Uniswap v3 that peeks into the current state of position and pool info without deployment
/// @author Aperture Finance
Expand All @@ -26,26 +25,3 @@ contract EphemeralGetPosition is PositionUtils {
peek(npm, tokenId, state);
}
}

/// @notice A lens for Uniswap v3 that peeks into the current state of position and pool info without deployment
/// @author Aperture Finance
/// @dev The return data can be accessed externally by `eth_call` without a `to` address or internally by catching the
/// revert data, and decoded by `abi.decode(data, (PositionState))`
contract PCSV3EphemeralGetPosition is PCSV3PositionUtils {
constructor(INPM npm, uint256 tokenId) payable {
PCSV3PositionState memory pos = getPosition(npm, tokenId);
bytes memory returnData = abi.encode(pos);
assembly ("memory-safe") {
revert(add(returnData, 0x20), mload(returnData))
}
}

/// @dev Public function to expose the abi for easier decoding using TypeChain
/// @param npm Nonfungible position manager
/// @param tokenId Token ID of the position
function getPosition(INPM npm, uint256 tokenId) public payable returns (PCSV3PositionState memory state) {
state.owner = NPMCaller.ownerOf(npm, tokenId);
positionInPlace(npm, tokenId, state.position);
peek(npm, tokenId, state);
}
}
41 changes: 0 additions & 41 deletions contracts/EphemeralGetPositions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity ^0.8.0;

import "./PositionUtils.sol";
import "./PCSV3PositionUtils.sol";

/// @notice A lens for Uniswap v3 that peeks into the current state of positions and pool info without deployment
/// @author Aperture Finance
Expand Down Expand Up @@ -43,43 +42,3 @@ contract EphemeralGetPositions is PositionUtils {
}
}
}

/// @notice A lens for PancakeSwap v3 that peeks into the current state of positions and pool info without deployment
/// @author Aperture Finance
/// @dev The return data can be accessed externally by `eth_call` without a `to` address or internally by catching the
/// revert data, and decoded by `abi.decode(data, (PCSV3PositionState[]))`
contract PCSV3EphemeralGetPositions is PCSV3PositionUtils {
constructor(INPM npm, uint256[] memory tokenIds) payable {
PCSV3PositionState[] memory positions = getPositions(npm, tokenIds);
bytes memory returnData = abi.encode(positions);
assembly ("memory-safe") {
revert(add(returnData, 0x20), mload(returnData))
}
}

/// @dev Public function to expose the abi for easier decoding using TypeChain
/// @param npm Nonfungible position manager
/// @param tokenIds Token IDs of the positions
function getPositions(
INPM npm,
uint256[] memory tokenIds
) public payable returns (PCSV3PositionState[] memory positions) {
unchecked {
uint256 length = tokenIds.length;
positions = new PCSV3PositionState[](length);
uint256 i;
for (uint256 j; j < length; ++j) {
uint256 tokenId = tokenIds[j];
PCSV3PositionState memory state = positions[i];
if (positionInPlace(npm, tokenId, state.position)) {
++i;
state.owner = NPMCaller.ownerOf(npm, tokenId);
peek(npm, tokenId, state);
}
}
assembly ("memory-safe") {
mstore(positions, i)
}
}
}
}
112 changes: 0 additions & 112 deletions contracts/PCSV3PositionUtils.sol

This file was deleted.

10 changes: 7 additions & 3 deletions contracts/PositionUtils.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {INonfungiblePositionManager as INPM} from "@aperture_finance/uni-v3-lib/src/interfaces/INonfungiblePositionManager.sol";
import {INonfungiblePositionManager as INPM, IPCSV3NonfungiblePositionManager as IPCSV3NPM} from "@aperture_finance/uni-v3-lib/src/interfaces/INonfungiblePositionManager.sol";
import {NPMCaller, PositionFull} from "@aperture_finance/uni-v3-lib/src/NPMCaller.sol";
import {PoolAddress} from "@aperture_finance/uni-v3-lib/src/PoolAddress.sol";
import {PoolAddressPancakeSwapV3} from "@aperture_finance/uni-v3-lib/src/PoolAddressPancakeSwapV3.sol";
import {IUniswapV3PoolState, V3PoolCallee} from "@aperture_finance/uni-v3-lib/src/PoolCaller.sol";
import {IUniswapV3Factory} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
import {ERC20Callee} from "./libraries/ERC20Caller.sol";
import {PoolUtils} from "./PoolUtils.sol";

Expand All @@ -14,7 +16,9 @@ struct Slot0 {
uint16 observationIndex;
uint16 observationCardinality;
uint16 observationCardinalityNext;
uint8 feeProtocol;
// `feeProtocol` is of type uint8 in Uniswap V3, and uint32 in PancakeSwap V3.
// We use uint32 here as this can hold both uint8 and uint32.
uint32 feeProtocol;
bool unlocked;
}

Expand Down Expand Up @@ -49,7 +53,7 @@ abstract contract PositionUtils is PoolUtils {
state.tokenId = tokenId;
PositionFull memory position = state.position;
V3PoolCallee pool = V3PoolCallee.wrap(
PoolAddress.computeAddressSorted(NPMCaller.factory(npm), position.token0, position.token1, position.fee)
IUniswapV3Factory(NPMCaller.factory(npm)).getPool(position.token0, position.token1, position.fee)
);
state.activeLiquidity = pool.liquidity();
slot0InPlace(pool, state.slot0);
Expand Down
Loading

0 comments on commit 48a4751

Please sign in to comment.