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

Add transfer support #218

Merged
merged 30 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d59846b
move to a base actions router
snreynolds Jul 27, 2024
46f47b2
use one Planner file
snreynolds Jul 27, 2024
b198c30
msgSender
snreynolds Jul 27, 2024
3482b23
add transfer
snreynolds Jul 27, 2024
2cee496
add transfer test
snreynolds Jul 27, 2024
bf369e6
merge main
snreynolds Jul 29, 2024
494f7d6
use delta saving hook to get deltas
snreynolds Jul 29, 2024
0449cac
remove return values
snreynolds Jul 29, 2024
47bbc6d
add burn comment
snreynolds Jul 29, 2024
7c911cb
make gas snapshots more accurate, remove hook
snreynolds Jul 29, 2024
5f26936
merge main
snreynolds Jul 29, 2024
03cf453
move to 1 planner, fix merge conf
snreynolds Jul 29, 2024
2aba16d
sweep currency, pr comments
snreynolds Jul 30, 2024
486617e
merge updates from use-actions-router
snreynolds Jul 30, 2024
b3aa874
rename, add liquidityDelta return param
snreynolds Jul 30, 2024
6885931
rename
snreynolds Jul 30, 2024
a60f16d
comment
snreynolds Jul 30, 2024
7ac7043
gas check
snreynolds Jul 30, 2024
64897c3
add gas test, using uint256
snreynolds Jul 30, 2024
b0b1b73
gas check, using 0
snreynolds Jul 30, 2024
bdfc04d
comments
snreynolds Jul 30, 2024
767605d
Merge branch 'main' into use-actions-router
snreynolds Jul 30, 2024
68e3a66
remove SafeCallback
snreynolds Jul 30, 2024
9d403c3
merge actions router
snreynolds Jul 30, 2024
0778130
remove FULL_DELTA
snreynolds Jul 30, 2024
9087916
merge main
snreynolds Jul 30, 2024
03e978f
move helpers to delta resolver
snreynolds Jul 30, 2024
dedf310
remove import
snreynolds Jul 30, 2024
428db01
increase liq with sttle with balance test
hensha256 Jul 31, 2024
858707e
Merge branch 'main' into add-transfer-support
hensha256 Jul 31, 2024
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
Original file line number Diff line number Diff line change
@@ -1 +1 @@
152726
152736
Original file line number Diff line number Diff line change
@@ -1 +1 @@
134609
134536
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
372827
372837
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
337610
337537
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_nativeWithSweep.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
344548
346399
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickLower.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
315509
315519
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickUpper.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
316151
316161
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_sameRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
241733
241743
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
371451
Original file line number Diff line number Diff line change
@@ -1 +1 @@
321527
321537
Original file line number Diff line number Diff line change
@@ -1 +1 @@
417163
417173
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_Bytecode.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6595
6628
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
120991
121090
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
120158
120257
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
129030
129129
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135860
135959
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn2Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
187212
187311
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
179175
179274
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn3Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
238593
238692
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
230580
230679
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactInputSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
134618
134717
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
119749
119848
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
118894
118993
Original file line number Diff line number Diff line change
@@ -1 +1 @@
126794
126893
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
120999
121098
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
129871
129970
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
134672
134771
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut2Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
186633
186732
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
183556
183655
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut3Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
238638
238737
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
235585
235684
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
229790
229889
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOutputSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
133152
133251
Original file line number Diff line number Diff line change
@@ -1 +1 @@
125274
125373
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
119537
119636
37 changes: 26 additions & 11 deletions src/PositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ contract PositionManager is
} else if (action == Actions.BURN_POSITION) {
// Will automatically decrease liquidity to 0 if the position is not already empty.
_burn(params);
} else if (action == Actions.SETTLE_WITH_BALANCE) {
_settleWithBalance(params);
} else if (action == Actions.SWEEP) {
_sweep(params);
} else {
revert UnsupportedAction(action);
}
Expand Down Expand Up @@ -146,14 +150,20 @@ contract PositionManager is
address caller = _msgSender();
if (currencyDelta < 0) {
_settle(currency, caller, uint256(-currencyDelta));

// if there are native tokens left over after settling, return to locker
if (currency.isNative()) _sweepNativeToken(caller);
hensha256 marked this conversation as resolved.
Show resolved Hide resolved
} else if (currencyDelta > 0) {
_take(currency, caller, uint256(currencyDelta));
}
}

/// @param params is an encoding of Currency
/// @dev uses this addresses balance to settle a negative delta
function _settleWithBalance(bytes memory params) internal {
Currency currency = abi.decode(params, (Currency));

// set the payer to this address, performs a transfer.
_settle(currency, address(this), _getFullSettleAmount(currency));
}

/// @param params is an encoding of uint256 tokenId, PositionConfig memory config, bytes hookData
/// @dev this is overloaded with ERC721Permit._burn
function _burn(bytes memory params) internal {
Expand Down Expand Up @@ -202,16 +212,21 @@ contract PositionManager is
liquidity = poolManager.getPositionLiquidity(config.poolKey.toId(), positionId);
}

/// @dev Send excess native tokens back to the recipient (locker)
/// @param recipient the receiver of the excess native tokens. Should be the caller, the one that sent the native tokens
function _sweepNativeToken(address recipient) internal {
uint256 nativeBalance = address(this).balance;
if (nativeBalance > 0) recipient.safeTransferETH(nativeBalance);
/// @notice Sweeps the entire contract balance of specified currency to the recipient
/// @param params an encoding of Currency, address
function _sweep(bytes calldata params) internal {
(Currency currency, address to) = abi.decode(params, (Currency, address));
uint256 balance = currency.balanceOfSelf();
if (balance > 0) currency.transfer(to, balance);
}

// implementation of abstract function DeltaResolver._pay
function _pay(Currency token, address payer, uint256 amount) internal override {
// TODO: Should we also support direct transfer?
permit2.transferFrom(payer, address(poolManager), uint160(amount), Currency.unwrap(token));
function _pay(Currency currency, address payer, uint256 amount) internal override {
if (payer == address(this)) {
// TODO: currency is guaranteed to not be eth so the native check in transfer is not optimal.
currency.transfer(address(poolManager), amount);
} else {
permit2.transferFrom(payer, address(poolManager), uint160(amount), Currency.unwrap(currency));
}
}
}
12 changes: 4 additions & 8 deletions src/V4Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";

import {PathKey, PathKeyLib} from "./libraries/PathKey.sol";
import {CalldataDecoder} from "./libraries/CalldataDecoder.sol";
Expand All @@ -24,7 +23,6 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
using SafeCastTemp for *;
using PathKeyLib for PathKey;
using CalldataDecoder for bytes;
using TransientStateLibrary for IPoolManager;

constructor(IPoolManager _poolManager) BaseActionsRouter(_poolManager) {}

Expand All @@ -51,12 +49,11 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
currency := calldataload(params.offset)
}

int256 delta = poolManager.currencyDelta(address(this), currency);
if (delta > 0) revert InvalidDeltaForAction();
uint256 amount = _getFullSettleAmount(currency);

// TODO support address(this) paying too
// TODO should it have a maxAmountOut added slippage protection?
_settle(currency, _msgSender(), uint256(-delta));
_settle(currency, _msgSender(), amount);
} else if (action == Actions.TAKE_ALL) {
// equivalent: abi.decode(params, (Currency, address))
Currency currency;
Expand All @@ -66,12 +63,11 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
recipient := calldataload(add(params.offset, 0x20))
}

int256 delta = poolManager.currencyDelta(address(this), currency);
hensha256 marked this conversation as resolved.
Show resolved Hide resolved
if (delta < 0) revert InvalidDeltaForAction();
uint256 amount = _getFullTakeAmount(currency);

// TODO should _take have a minAmountOut added slippage check?
// TODO recipient mapping
_take(currency, recipient, uint256(delta));
_take(currency, recipient, amount);
} else {
revert UnsupportedAction(action);
}
Expand Down
24 changes: 22 additions & 2 deletions src/base/DeltaResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
pragma solidity ^0.8.24;

import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {ImmutableState} from "./ImmutableState.sol";

/// @notice Abstract contract used to sync, send, and settle funds to the pool manager
/// @dev Note that sync() is called before any erc-20 transfer in `settle`.
abstract contract DeltaResolver is ImmutableState {
/// @notice Emitted trying to settle a positive delta, or take a negative delta
error InvalidDeltaForAction();
using TransientStateLibrary for IPoolManager;

/// @notice Emitted trying to settle a positive delta.
error IncorrectUseOfSettle();
/// @notice Emitted trying to take a negative delta.
error IncorrectUseOfTake();

/// @notice Take an amount of currency out of the PoolManager
/// @param currency Currency to take
Expand Down Expand Up @@ -39,4 +45,18 @@ abstract contract DeltaResolver is ImmutableState {
/// @param payer The address who should pay tokens
/// @param amount The number of tokens to send
function _pay(Currency token, address payer, uint256 amount) internal virtual;

function _getFullSettleAmount(Currency currency) internal view returns (uint256 amount) {
int256 _amount = poolManager.currencyDelta(address(this), currency);
// If the amount is positive, it should be taken not settled for.
if (_amount > 0) revert IncorrectUseOfSettle();
amount = uint256(-_amount);
}

function _getFullTakeAmount(Currency currency) internal view returns (uint256 amount) {
int256 _amount = poolManager.currencyDelta(address(this), currency);
// If the amount is negative, it should be settled not taken.
if (_amount < 0) revert IncorrectUseOfTake();
amount = uint256(_amount);
}
}
36 changes: 20 additions & 16 deletions src/libraries/Actions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,35 @@ pragma solidity ^0.8.24;
/// @dev These are suggested common commands, however additional commands should be defined as required
library Actions {
// pool actions
// liquidity actions
uint256 constant INCREASE_LIQUIDITY = 0x00;
uint256 constant DECREASE_LIQUIDITY = 0x01;
uint256 constant SWAP_EXACT_IN_SINGLE = 0x02;
uint256 constant SWAP_EXACT_IN = 0x03;
uint256 constant SWAP_EXACT_OUT_SINGLE = 0x04;
uint256 constant SWAP_EXACT_OUT = 0x05;
uint256 constant DONATE = 0x06;
uint256 constant MINT_POSITION = 0x02;
uint256 constant BURN_POSITION = 0x03;
// swapping
uint256 constant SWAP_EXACT_IN_SINGLE = 0x04;
uint256 constant SWAP_EXACT_IN = 0x05;
uint256 constant SWAP_EXACT_OUT_SINGLE = 0x06;
uint256 constant SWAP_EXACT_OUT = 0x07;
// donate
uint256 constant DONATE = 0x08;

// closing deltas on the pool manager
// settling
uint256 constant SETTLE = 0x10;
uint256 constant SETTLE_ALL = 0x11;
uint256 constant SETTLE_WITH_BALANCE = 0x12;
// taking
uint256 constant TAKE = 0x13;
uint256 constant TAKE_ALL = 0x14;
uint256 constant TAKE_PORTION = 0x15;

uint256 constant TAKE = 0x12;
uint256 constant TAKE_ALL = 0x13;
uint256 constant TAKE_PORTION = 0x14;

uint256 constant CLOSE_CURRENCY = 0x15;
uint256 constant CLOSE_PAIR = 0x16;
uint256 constant CLEAR = 0x17;
uint256 constant CLOSE_CURRENCY = 0x16;
uint256 constant CLOSE_PAIR = 0x17;
uint256 constant CLEAR = 0x18;
uint256 constant SWEEP = 0x19;

// minting/burning 6909s to close deltas
uint256 constant MINT_6909 = 0x20;
uint256 constant BURN_6909 = 0x21;

// mint + burn ERC721 position
uint256 constant MINT_POSITION = 0x22;
uint256 constant BURN_POSITION = 0x23;
}
Loading
Loading