Skip to content

Commit

Permalink
Merge branch 'main' into feat/align-binPm-tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
ChefMist authored Nov 8, 2024
2 parents edfc7d3 + 7f4a38e commit fbb935d
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 7 deletions.
5 changes: 5 additions & 0 deletions src/interfaces/IPositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ interface IPositionManager is IImmutableState {
/// @notice Thrown when the block.timestamp exceeds the user-provided deadline
error DeadlinePassed(uint256 deadline);

/// @notice Thrown when calling transfer, subscribe, or unsubscribe on CLPositionManager
/// or batchTransferFrom on BinPositionManager when the vault is locked.
/// @dev This is to prevent hooks from being able to trigger actions or notifications at the same time the position is being modified.
error VaultMustBeUnlocked();

/// @notice Thrown when the token ID is bind to an unexisting pool
error InvalidTokenID();

Expand Down
4 changes: 4 additions & 0 deletions src/pool-bin/BinFungibleToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ abstract contract BinFungibleToken is IBinFungibleToken {
_;
}

/// @notice Enforces that the Vault is unlocked.
modifier onlyIfVaultUnlocked() virtual;

/*//////////////////////////////////////////////////////////////
LOGIC
//////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -73,6 +76,7 @@ abstract contract BinFungibleToken is IBinFungibleToken {
public
virtual
override
onlyIfVaultUnlocked
{
if (ids.length != amounts.length) revert BinFungibleToken_InvalidLength();
if (to == address(0) || to == address(this)) revert BinFungibleToken_AddressThisOrZero();
Expand Down
6 changes: 6 additions & 0 deletions src/pool-bin/BinPositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ contract BinPositionManager is
_;
}

/// @notice Enforces that the vault is unlocked.
modifier onlyIfVaultUnlocked() override {
if (vault.getLocker() != address(0)) revert VaultMustBeUnlocked();
_;
}

/// @inheritdoc IBinPositionManager
function positions(uint256 tokenId) external view returns (PoolKey memory poolKey, uint24 binId) {
TokenPosition memory position = _positions[tokenId];
Expand Down
4 changes: 0 additions & 4 deletions src/pool-cl/interfaces/ICLPositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ interface ICLPositionManager is IPositionManager {
/// @notice Thrown when the caller is not approved to modify a position
error NotApproved(address caller);

/// @notice Thrown when calling transfer, subscribe, or unsubscribe when the vault is locked.
/// @dev This is to prevent hooks from being able to trigger notifications at the same time the position is being modified.
error VaultMustBeUnlocked();

/// @notice Emitted when a new liquidity position is minted
event MintPosition(uint256 indexed tokenId);

Expand Down
65 changes: 65 additions & 0 deletions test/pool-bin/BinPositionManager_ModifyLiquidites.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,71 @@ contract BinPositionManager_ModifyLiquidityTest is BinLiquidityHelper, GasSnapsh
binPm.modifyLiquidities(actions, _deadline);
}

function test_transferLiquidityToken() public {
uint24[] memory binIds = getBinIds(activeId, 1);
IBinPositionManager.BinAddLiquidityParams memory param =
_getAddParams(key1, binIds, 1 ether, 1 ether, activeId, address(this));
Plan memory planner = Planner.init().add(Actions.BIN_ADD_LIQUIDITY, abi.encode(param));
bytes memory payload = planner.finalizeModifyLiquidityWithClose(key1);
binPm.modifyLiquidities(payload, _deadline);

uint256 tokenId = key1.toId().toTokenId(binIds[0]);
uint256 tokenBalance = binPm.balanceOf(address(this), tokenId);
assertGt(tokenBalance, 0);

uint256[] memory ids = new uint256[](1);
ids[0] = tokenId;
uint256[] memory amounts = new uint256[](1);
amounts[0] = tokenBalance;
binPm.batchTransferFrom(address(this), makeAddr("someone"), ids, amounts);

// verify transfer successful
assertEq(binPm.balanceOf(address(this), tokenId), 0);
assertEq(binPm.balanceOf(makeAddr("someone"), tokenId), tokenBalance);
}

function test_transferLiquidityToken_revertIfVaultLocked() public {
uint24[] memory binIds = getBinIds(activeId, 1);
IBinPositionManager.BinAddLiquidityParams memory param =
_getAddParams(key1, binIds, 1 ether, 1 ether, activeId, address(this));
Plan memory planner = Planner.init().add(Actions.BIN_ADD_LIQUIDITY, abi.encode(param));
bytes memory payload = planner.finalizeModifyLiquidityWithClose(key1);
binPm.modifyLiquidities(payload, _deadline);

uint256 tokenId = key1.toId().toTokenId(binIds[0]);
uint256 tokenBalance = binPm.balanceOf(address(this), tokenId);
assertGt(tokenBalance, 0);

uint256[] memory ids = new uint256[](1);
ids[0] = tokenId;
uint256[] memory amounts = new uint256[](1);
amounts[0] = tokenBalance;
// lock the vault so that the transfer fails
vault.lock(
abi.encodeCall(
BinPositionManager_ModifyLiquidityTest._test_transferLiquidityToken_revertIfVaultLocked, (ids, amounts)
)
);
}

function _test_transferLiquidityToken_revertIfVaultLocked(uint256[] memory ids, uint256[] memory amounts)
external
{
vm.expectRevert(IPositionManager.VaultMustBeUnlocked.selector);
binPm.batchTransferFrom(address(this), makeAddr("someone"), ids, amounts);
}

function lockAcquired(bytes calldata data) external returns (bytes memory result) {
// forward the call and bubble up the error if revert
bool success;
(success, result) = address(this).call(data);
if (!success) {
assembly ("memory-safe") {
revert(add(result, 0x20), mload(result))
}
}
}

// to receive refunds of spare eth from test helpers
receive() external payable {}
}
6 changes: 3 additions & 3 deletions test/pool-cl/position-managers/CLPositionManager.notifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ contract CLPositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot {
abi.encodeWithSelector(
Hooks.Wrap__FailedHookCall.selector,
address(reenterHook),
abi.encodeWithSelector(ICLPositionManager.VaultMustBeUnlocked.selector)
abi.encodeWithSelector(IPositionManager.VaultMustBeUnlocked.selector)
)
);
lpm.modifyLiquidities(actions, _deadline);
Expand All @@ -683,7 +683,7 @@ contract CLPositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot {
abi.encodeWithSelector(
Hooks.Wrap__FailedHookCall.selector,
address(reenterHook),
abi.encodeWithSelector(ICLPositionManager.VaultMustBeUnlocked.selector)
abi.encodeWithSelector(IPositionManager.VaultMustBeUnlocked.selector)
)
);
lpm.modifyLiquidities(actions, _deadline);
Expand All @@ -704,7 +704,7 @@ contract CLPositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot {
abi.encodeWithSelector(
Hooks.Wrap__FailedHookCall.selector,
address(reenterHook),
abi.encodeWithSelector(ICLPositionManager.VaultMustBeUnlocked.selector)
abi.encodeWithSelector(IPositionManager.VaultMustBeUnlocked.selector)
)
);
lpm.modifyLiquidities(actions, _deadline);
Expand Down

0 comments on commit fbb935d

Please sign in to comment.