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 msg.sender #21

Merged
merged 7 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
120 changes: 120 additions & 0 deletions forge-test/GetCurrentLockCaller.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "forge-std/Test.sol";
import {IHooks} from "v4-core/interfaces/IHooks.sol";
import {Hooks} from "v4-core/libraries/Hooks.sol";
import {TickMath} from "v4-core/libraries/TickMath.sol";
import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol";
import {PoolSwapTest} from "v4-core/test/PoolSwapTest.sol";
import {PoolKey} from "v4-core/types/PoolKey.sol";
import {BalanceDelta} from "v4-core/types/BalanceDelta.sol";
import {PoolId, PoolIdLibrary} from "v4-core/types/PoolId.sol";
import {Constants} from "v4-core/../test/utils/Constants.sol";
import {CurrencyLibrary, Currency} from "v4-core/types/Currency.sol";
import {HookTest} from "@v4-by-example/utils/HookTest.sol";
import {GetCurrentLockCaller} from "src/pages/hooks/msg-sender/GetCurrentLockCaller.sol";
import {HookMiner} from "./utils/HookMiner.sol";

contract GetCurrentLockCallerTest is HookTest {
using PoolIdLibrary for PoolKey;
using CurrencyLibrary for Currency;

GetCurrentLockCaller counter;
PoolKey poolKey;
PoolId poolId;

address alice = makeAddr("alice");

function setUp() public {
// creates the pool manager, test tokens, and other utility routers
HookTest.initHookTestEnv();

// Deploy the hook to an address with the correct flags
uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG);
(address hookAddress, bytes32 salt) =
HookMiner.find(address(this), flags, type(GetCurrentLockCaller).creationCode, abi.encode(address(manager)));
counter = new GetCurrentLockCaller{salt: salt}(IPoolManager(address(manager)));
require(address(counter) == hookAddress, "GetCurrentLockCallerTest: hook address mismatch");

// Create the pool
poolKey = PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 3000, 60, IHooks(counter));
poolId = poolKey.toId();
initializeRouter.initialize(poolKey, Constants.SQRT_RATIO_1_1, ZERO_BYTES);

// Provide liquidity to the pool
modifyPositionRouter.modifyLiquidity(poolKey, IPoolManager.ModifyLiquidityParams(-60, 60, 10 ether), ZERO_BYTES);
modifyPositionRouter.modifyLiquidity(
poolKey, IPoolManager.ModifyLiquidityParams(-120, 120, 10 ether), ZERO_BYTES
);
modifyPositionRouter.modifyLiquidity(
poolKey,
IPoolManager.ModifyLiquidityParams(TickMath.minUsableTick(60), TickMath.maxUsableTick(60), 10 ether),
ZERO_BYTES
);
}

function test_getCurrentLockCaller() public {
counter.setAllowedUser(alice, true);
token0.mint(alice, 100 ether);

vm.startPrank(alice);
token0.approve(address(swapRouter), type(uint256).max);

// Perform a test swap //
int256 amount = 1e18;
bool zeroForOne = true;
lockSwap(poolKey, amount, zeroForOne, ZERO_BYTES, false);
// ------------------- //
vm.stopPrank();
}

function test_getCurrentLockCallerRevert() public {
counter.setAllowedUser(alice, false);
token0.mint(alice, 100 ether);

vm.startPrank(alice);
token0.approve(address(swapRouter), type(uint256).max);

// Perform a test swap //
int256 amount = 1e18;
bool zeroForOne = true;
vm.expectRevert();
lockSwap(poolKey, amount, zeroForOne, ZERO_BYTES, true);
// ------------------- //
vm.stopPrank();
}

function lockSwap(
PoolKey memory key,
int256 amountSpecified,
bool zeroForOne,
bytes memory hookData,
bool expectRevert
) internal returns (BalanceDelta swapDelta) {
IPoolManager.SwapParams memory params = IPoolManager.SwapParams({
zeroForOne: zeroForOne,
amountSpecified: amountSpecified,
sqrtPriceLimitX96: zeroForOne ? MIN_PRICE_LIMIT : MAX_PRICE_LIMIT // unlimited impact
});

PoolSwapTest.TestSettings memory testSettings =
PoolSwapTest.TestSettings({withdrawTokens: true, settleUsingTransfer: true, currencyAlreadySent: false});

bytes memory result;
if (expectRevert) {
vm.expectRevert();
result = manager.lock(
address(swapRouter),
abi.encode(PoolSwapTest.CallbackData(address(this), testSettings, key, params, hookData))
);
} else {
result = manager.lock(
address(swapRouter),
abi.encode(PoolSwapTest.CallbackData(address(this), testSettings, key, params, hookData))
);
}

swapDelta = abi.decode(result, (BalanceDelta));
}
}
86 changes: 86 additions & 0 deletions forge-test/MsgSenderHookData.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "forge-std/Test.sol";
import {IHooks} from "v4-core/interfaces/IHooks.sol";
import {Hooks} from "v4-core/libraries/Hooks.sol";
import {TickMath} from "v4-core/libraries/TickMath.sol";
import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol";
import {PoolKey} from "v4-core/types/PoolKey.sol";
import {BalanceDelta} from "v4-core/types/BalanceDelta.sol";
import {PoolId, PoolIdLibrary} from "v4-core/types/PoolId.sol";
import {Constants} from "v4-core/../test/utils/Constants.sol";
import {CurrencyLibrary, Currency} from "v4-core/types/Currency.sol";
import {HookTest} from "@v4-by-example/utils/HookTest.sol";
import {MsgSenderHookData} from "src/pages/hooks/msg-sender/MsgSenderHookData.sol";
import {HookMiner} from "./utils/HookMiner.sol";

contract MsgSenderHookDataTest is HookTest {
using PoolIdLibrary for PoolKey;
using CurrencyLibrary for Currency;

MsgSenderHookData counter;
PoolKey poolKey;
PoolId poolId;

address alice = makeAddr("alice");

function setUp() public {
// creates the pool manager, test tokens, and other utility routers
HookTest.initHookTestEnv();

// Deploy the hook to an address with the correct flags
uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG);
(address hookAddress, bytes32 salt) =
HookMiner.find(address(this), flags, type(MsgSenderHookData).creationCode, abi.encode(address(manager)));
counter = new MsgSenderHookData{salt: salt}(IPoolManager(address(manager)));
require(address(counter) == hookAddress, "MsgSenderHookDataTest: hook address mismatch");

// Create the pool
poolKey = PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 3000, 60, IHooks(counter));
poolId = poolKey.toId();
initializeRouter.initialize(poolKey, Constants.SQRT_RATIO_1_1, ZERO_BYTES);

// Provide liquidity to the pool
modifyPositionRouter.modifyLiquidity(poolKey, IPoolManager.ModifyLiquidityParams(-60, 60, 10 ether), ZERO_BYTES);
modifyPositionRouter.modifyLiquidity(
poolKey, IPoolManager.ModifyLiquidityParams(-120, 120, 10 ether), ZERO_BYTES
);
modifyPositionRouter.modifyLiquidity(
poolKey,
IPoolManager.ModifyLiquidityParams(TickMath.minUsableTick(60), TickMath.maxUsableTick(60), 10 ether),
ZERO_BYTES
);
}

function test_msgSenderHookData() public {
counter.setAllowedUser(alice, true);
token0.mint(alice, 100 ether);

vm.startPrank(alice);
token0.approve(address(swapRouter), type(uint256).max);

// Perform a test swap //
int256 amount = 1e18;
bool zeroForOne = true;
swap(poolKey, amount, zeroForOne, abi.encode(alice));
// ------------------- //
vm.stopPrank();
}

function test_msgSenderRevert() public {
counter.setAllowedUser(alice, false);
token0.mint(alice, 100 ether);

vm.startPrank(alice);
token0.approve(address(swapRouter), type(uint256).max);

// Perform a test swap //
int256 amount = 1e18;
bool zeroForOne = true;
vm.expectRevert();
swap(poolKey, amount, zeroForOne, abi.encode(alice));
// ------------------- //
vm.stopPrank();
}
}
7 changes: 7 additions & 0 deletions src/keywords.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
"swap",
"skip swap"
],
"/hooks/msg-sender": [
"hook",
"hooks",
"msg.sender",
"msgsender",
"sender"
],
"/hooks/custom-curve": [
"hook",
"hooks",
Expand Down
4 changes: 4 additions & 0 deletions src/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export const HOOK_ROUTES: Route[] = [
{
path: "custom-curve",
title: "Custom Curve"
},
{
path: "msg-sender",
title: "Access msg.sender"
}
]

Expand Down
51 changes: 51 additions & 0 deletions src/pages/hooks/msg-sender/GetCurrentLockCaller.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

// TODO: update to v4-periphery/BaseHook.sol when its compatible
import {BaseHook} from "@v4-by-example/utils/BaseHook.sol";

import {console2} from "forge-std/console2.sol";
import {Hooks} from "v4-core/libraries/Hooks.sol";
import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol";
import {PoolKey} from "v4-core/types/PoolKey.sol";
import {BalanceDelta} from "v4-core/types/BalanceDelta.sol";
import {Lockers} from "v4-core/libraries/Lockers.sol";

contract GetCurrentLockCaller is BaseHook {
mapping(address user => bool allowed) public allowedUsers;

constructor(IPoolManager _poolManager) BaseHook(_poolManager) {}

function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata, bytes calldata hookData)
external
override
returns (bytes4)
{
// --- Read the user's address --- //
(, address user) = poolManager.getLock(1);
require(allowedUsers[user], "GetCurrentLockCaller: User not allowed");
return BaseHook.beforeSwap.selector;
}

// Helper function for demonstration
function setAllowedUser(address user, bool allowed) external {
allowedUsers[user] = allowed;
}

function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
return Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
beforeRemoveLiquidity: false,
afterAddLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: true,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
noOp: false,
accessLock: false
});
}
}
52 changes: 52 additions & 0 deletions src/pages/hooks/msg-sender/MsgSenderHookData.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

// TODO: update to v4-periphery/BaseHook.sol when its compatible
import {BaseHook} from "@v4-by-example/utils/BaseHook.sol";

import {Hooks} from "v4-core/libraries/Hooks.sol";
import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol";
import {PoolKey} from "v4-core/types/PoolKey.sol";
import {PoolId, PoolIdLibrary} from "v4-core/types/PoolId.sol";
import {BalanceDelta} from "v4-core/types/BalanceDelta.sol";

contract MsgSenderHookData is BaseHook {
using PoolIdLibrary for PoolKey;

mapping(address user => bool allowed) public allowedUsers;

constructor(IPoolManager _poolManager) BaseHook(_poolManager) {}

function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata, bytes calldata hookData)
external
override
returns (bytes4)
{
// --- Read the user's address --- //
address user = abi.decode(hookData, (address));
require(allowedUsers[user], "MsgSenderHookData: User not allowed");
return BaseHook.beforeSwap.selector;
}

// Helper function for demonstration
function setAllowedUser(address user, bool allowed) external {
allowedUsers[user] = allowed;
}

function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
return Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
beforeRemoveLiquidity: false,
afterAddLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: true,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
noOp: false,
accessLock: false
});
}
}
7 changes: 7 additions & 0 deletions src/pages/hooks/msg-sender/PoolManagerLock.solsnippet
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// User directly locks on the PoolManager
// - poolManager.getLock(1) returns alice's address
vm.prank(alice);
manager.lock(
address(swapRouter),
abi.encode(PoolSwapTest.CallbackData(address(this), testSettings, key, params, hookData))
);
7 changes: 7 additions & 0 deletions src/pages/hooks/msg-sender/PoolSwapTestHookData.solsnippet
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
IPoolManager.SwapParams memory params = ...;

PoolSwapTest.TestSettings memory testSettings = ...;

// provide the user's address as hookData to be available inside the hook function
bytes memory hookData = abi.encode(address(USER_ADDRESS));
swapRouter.swap(key, params, testSettings, hookData);
Loading
Loading