Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access lock #404

Merged
merged 35 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
1cc37ed
rebase
snreynolds Nov 9, 2023
2a2321e
add access lock flag
snreynolds Nov 14, 2023
65069b3
create AccessLock tests
snreynolds Nov 15, 2023
589026f
add beforeModifyPosition tests for mint/swap/modify/take/donate
snreynolds Nov 16, 2023
70a869e
add beforeSwap tests
snreynolds Nov 17, 2023
e147a7c
add beforeDonate tests
snreynolds Nov 17, 2023
2396461
fix fuzz boundaries
snreynolds Nov 17, 2023
8b6b850
use transient storage
snreynolds Nov 17, 2023
400ce17
fix ci?
snreynolds Nov 17, 2023
7bda2b1
fix: comments
snreynolds Nov 20, 2023
fbda6c4
add revert test
snreynolds Nov 20, 2023
11c9321
more edge case tests
snreynolds Nov 20, 2023
d6864a4
add failing test
snreynolds Nov 20, 2023
d7829b7
fix: hooks can only call functions in the middle of a lock
snreynolds Nov 20, 2023
9d8f00b
fix comments
snreynolds Nov 20, 2023
2a7ccf9
fix: currentHook must be updated only on the first call, and cleared
snreynolds Nov 21, 2023
2e88e5f
merge main
snreynolds Nov 22, 2023
969fb9d
use IHooks, remove 1155 ref
snreynolds Nov 22, 2023
a958a37
remove special no access lock hook
snreynolds Nov 22, 2023
f70443a
add nested lock test
snreynolds Nov 22, 2023
88d9ce1
unset hook for noOp case
snreynolds Nov 26, 2023
448b557
add initialize
snreynolds Nov 27, 2023
fa432c2
add vanilla initialize tests
snreynolds Nov 27, 2023
fb803c3
fmt error
snreynolds Nov 27, 2023
f455e64
add natspec and flatten onlyByLocker check
snreynolds Nov 27, 2023
528ce4e
snaps
snreynolds Nov 27, 2023
83afc1e
move onlyByLocker, add comments
snreynolds Nov 29, 2023
b9645ef
update comments, use custom error, add test cases
snreynolds Nov 29, 2023
7fc2658
add burn test
snreynolds Nov 30, 2023
e571806
remove logs
snreynolds Nov 30, 2023
680faf7
add settle test
snreynolds Nov 30, 2023
53cdf3e
init test
snreynolds Nov 30, 2023
7755acd
add back noop test
snreynolds Nov 30, 2023
852ed5b
remove else
snreynolds Nov 30, 2023
0aee197
Merge branch 'main' into access-lock
snreynolds Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add vanilla initialize tests
  • Loading branch information
snreynolds committed Nov 27, 2023
commit fa432c22d46118565503ab6bceefec60ba052198
2 changes: 1 addition & 1 deletion .forge-snapshots/initialize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
77307
77664
9 changes: 9 additions & 0 deletions src/test/AccessLockHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ contract AccessLockHook is Test, BaseTestHooks {
NoOp
}

function beforeInitialize(
address, /* sender **/
PoolKey calldata key,
uint160, /* sqrtPriceX96 **/
bytes calldata hookData
) external override returns (bytes4) {
return _executeAction(key, hookData, IHooks.beforeInitialize.selector);
}

function beforeSwap(
address, /* sender **/
PoolKey calldata key,
Expand Down
20 changes: 16 additions & 4 deletions src/test/PoolInitializeTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,28 @@ import {PoolKey} from "../types/PoolKey.sol";
import {PoolTestBase} from "./PoolTestBase.sol";
import {SafeCast} from "../libraries/SafeCast.sol";
import {Test} from "forge-std/Test.sol";
import {IHooks} from "../interfaces/IHooks.sol";
import {Hooks} from "../libraries/Hooks.sol";

contract PoolInitializeTest is Test, PoolTestBase {
using CurrencyLibrary for Currency;
using SafeCast for uint256;
using Hooks for IHooks;

constructor(IPoolManager _manager) PoolTestBase(_manager) {}

struct CallbackData {
PoolKey key;
uint160 sqrtPriceX96;
bytes hookData;
address sender;
}

function initialize(PoolKey memory key, uint160 sqrtPriceX96, bytes memory hookData)
external
returns (int24 tick)
{
tick = abi.decode(manager.lock(abi.encode(CallbackData(key, sqrtPriceX96, hookData))), (int24));
tick = abi.decode(manager.lock(abi.encode(CallbackData(key, sqrtPriceX96, hookData, msg.sender))), (int24));
}

function lockAcquired(bytes calldata rawData) external returns (bytes memory) {
Expand All @@ -38,9 +42,17 @@ contract PoolInitializeTest is Test, PoolTestBase {
int256 delta1 = manager.currencyDelta(address(this), data.key.currency1);
uint256 nonZeroDC = manager.getLockNonzeroDeltaCount();

assertEq(delta0, 0, "delta0");
assertEq(delta1, 0, "delta1");
assertEq(nonZeroDC, 0, "NonzeroDeltaCount");
if (!data.key.hooks.hasPermissionToAccessLock()) {
assertEq(delta0, 0, "delta0");
assertEq(delta1, 0, "delta1");
assertEq(nonZeroDC, 0, "NonzeroDeltaCount");
} else {
// settle deltas
if (delta0 > 0) _settle(data.key.currency0, data.sender, int128(delta0), true);
if (delta1 > 0) _settle(data.key.currency1, data.sender, int128(delta1), true);
if (delta0 < 0) _take(data.key.currency0, data.sender, int128(delta0), true);
if (delta1 < 0) _take(data.key.currency1, data.sender, int128(delta1), true);
}

return abi.encode(tick);
}
Expand Down
94 changes: 92 additions & 2 deletions test/AccessLock.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ contract AccessLockTest is Test, Deployers {
// Create AccessLockHook with NoOp.
address accessLockHook4Address = address(
uint160(
Hooks.NO_OP_FLAG | Hooks.ACCESS_LOCK_FLAG | Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_MODIFY_POSITION_FLAG
| Hooks.BEFORE_DONATE_FLAG
Hooks.NO_OP_FLAG | Hooks.ACCESS_LOCK_FLAG | Hooks.BEFORE_INITIALIZE_FLAG | Hooks.BEFORE_SWAP_FLAG
| Hooks.BEFORE_MODIFY_POSITION_FLAG | Hooks.BEFORE_DONATE_FLAG
)
);
deployCodeTo("AccessLockHook.sol:AccessLockHook", abi.encode(manager), accessLockHook4Address);
Expand Down Expand Up @@ -521,6 +521,96 @@ contract AccessLockTest is Test, Deployers {
assertLt(balanceOfAfter0, balanceOfBefore0);
assertLt(balanceOfAfter1, balanceOfBefore1);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about some edge casier tests like:

  • doing one hook operation, then another - the first hook should no longer have access rights but the new one should
  • doing one hook operation, then an operation on a pool with no hook - the first hook should no longer have access rights
  • .. im sure we can think of more

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add a hook accessing a lock and applying deltas when there is no outside locker

/**
*
* BEFORE INITIALIZE TESTS
*
*/

function test_beforeInitialize_mint_succeedsWithAccessLock(uint128 amount) public {
vm.assume(amount != 0 && amount < uint128(type(int128).max));

PoolKey memory key1 = PoolKey({
currency0: currency0,
currency1: currency1,
fee: Constants.FEE_MEDIUM,
tickSpacing: 60,
hooks: IHooks(address(accessLockHook4))
});

initializeRouter.initialize(key1, SQRT_RATIO_1_1, abi.encode(amount, AccessLockHook.LockAction.Mint));

assertEq(manager.balanceOf(address(accessLockHook4), currency1), amount);
}

function test_beforeInitialize_take_succeedsWithAccessLock(uint128 amount) public {
PoolKey memory key1 = PoolKey({
currency0: currency0,
currency1: currency1,
fee: Constants.FEE_MEDIUM,
tickSpacing: 60,
hooks: IHooks(address(accessLockHook4))
});

// Add liquidity to a different pool there is something to take.
modifyPositionRouter.modifyPosition(
key,
IPoolManager.ModifyPositionParams({tickLower: -120, tickUpper: 120, liquidityDelta: 100 * 10e18}),
ZERO_BYTES
);

// Can't take more than the manager has.
vm.assume(amount < key.currency1.balanceOf(address(manager)));

initializeRouter.initialize(key1, SQRT_RATIO_1_1, abi.encode(amount, AccessLockHook.LockAction.Take));

assertEq(MockERC20(Currency.unwrap(currency1)).balanceOf(address(accessLockHook4)), amount);
}

function test_beforeInitialize_swap_revertsOnPoolNotInitialized(uint128 amount) public {
vm.assume(amount != 0 && amount > 10); // precision

PoolKey memory key1 = PoolKey({
currency0: currency0,
currency1: currency1,
fee: Constants.FEE_MEDIUM,
tickSpacing: 60,
hooks: IHooks(address(accessLockHook4))
});

vm.expectRevert(IPoolManager.PoolNotInitialized.selector);
initializeRouter.initialize(key1, SQRT_RATIO_1_1, abi.encode(amount, AccessLockHook.LockAction.Swap));
}

function test_beforeInitialize_modifyPosition_revertsOnPoolNotInitialized(uint128 amount) public {
vm.assume(amount != 0 && amount > 10); // precision

PoolKey memory key1 = PoolKey({
currency0: currency0,
currency1: currency1,
fee: Constants.FEE_MEDIUM,
tickSpacing: 60,
hooks: IHooks(address(accessLockHook4))
});

vm.expectRevert(IPoolManager.PoolNotInitialized.selector);
initializeRouter.initialize(key1, SQRT_RATIO_1_1, abi.encode(amount, AccessLockHook.LockAction.ModifyPosition));
}

function test_beforeInitialize_donate_revertsOnPoolNotInitialized(uint128 amount) public {
vm.assume(amount != 0 && amount > 10); // precision

PoolKey memory key1 = PoolKey({
currency0: currency0,
currency1: currency1,
fee: Constants.FEE_MEDIUM,
tickSpacing: 60,
hooks: IHooks(address(accessLockHook4))
});

vm.expectRevert(IPoolManager.PoolNotInitialized.selector);
initializeRouter.initialize(key1, SQRT_RATIO_1_1, abi.encode(amount, AccessLockHook.LockAction.Donate));
}

/**
*
Expand Down
9 changes: 7 additions & 2 deletions test/utils/Deployers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,13 @@ contract Deployers {
function deployMintAndApprove2Currencies() internal returns (Currency, Currency) {
MockERC20[] memory tokens = deployTokens(2, 2 ** 255);

address[4] memory toApprove =
[address(swapRouter), address(modifyPositionRouter), address(donateRouter), address(takeRouter)];
address[5] memory toApprove = [
address(swapRouter),
address(modifyPositionRouter),
address(donateRouter),
address(takeRouter),
address(initializeRouter)
];

for (uint256 i = 0; i < toApprove.length; i++) {
tokens[0].approve(toApprove[i], Constants.MAX_UINT256);
Expand Down
Loading