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

Implement Claims accounting as minimal balance #379

Merged
merged 38 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a7f428a
Add MinimalBalance
zhongeric Oct 30, 2023
d571ee6
Initial commmit
zhongeric Oct 30, 2023
31fb937
Router custodies Claims, has access to priviledged burnFrom anbd tests
zhongeric Oct 31, 2023
64f3222
updategas
zhongeric Oct 31, 2023
f20c0cc
remove 6909 lib
zhongeric Oct 31, 2023
e07d3e5
yarn snapshots
zhongeric Oct 31, 2023
2cc4bb3
Add gas snaps for swapping from claims balance
zhongeric Nov 1, 2023
8ac4c71
fix gas snaps by removing aux logic in router
zhongeric Nov 1, 2023
57f6910
gas
zhongeric Nov 1, 2023
20cc926
remove lib
zhongeric Nov 2, 2023
0eb8f80
Add transfer to minimalBalance, update tests
zhongeric Nov 2, 2023
f5f7036
nit: rename
zhongeric Nov 2, 2023
156b906
add back custom errors
zhongeric Nov 2, 2023
0fb4c0e
move addition out of unchecked
zhongeric Nov 2, 2023
f5b6908
Add transfer overflow check
zhongeric Nov 2, 2023
62379dc
Rename impl test
zhongeric Nov 2, 2023
8f6721d
nit comments
zhongeric Nov 2, 2023
e0c1eb9
comment#
zhongeric Nov 2, 2023
20ea785
Merge branch 'main' into minimal-balances
zhongeric Nov 6, 2023
caec8c0
Remove unused inheritance
zhongeric Nov 6, 2023
0be01db
remove comment
zhongeric Nov 6, 2023
b506694
Remove poolClaimTest
zhongeric Nov 6, 2023
f200569
fix interfaces
zhongeric Nov 6, 2023
37a17f5
Feedback
zhongeric Nov 7, 2023
56a4f22
Add address(0) and address(this) check for transfer
zhongeric Nov 7, 2023
cc32e04
remove address(0) check
zhongeric Nov 7, 2023
7a21d6b
Remove batchBurn
zhongeric Nov 7, 2023
0c9ed3d
Move mock claims to diff file
zhongeric Nov 7, 2023
95ba981
Add gas snaps for collect protocol fees
zhongeric Nov 7, 2023
a0b53cc
Add balance checks, make balances mapping private
zhongeric Nov 13, 2023
97bb3a3
Merge branch 'main' into minimal-balances
zhongeric Nov 13, 2023
505e02a
Fix imports
zhongeric Nov 13, 2023
7f7f980
fix fs perms
zhongeric Nov 13, 2023
ca7f811
Remove uint256 in mapping and use Currency
zhongeric Nov 13, 2023
0948233
Merge branch 'main' into minimal-balances
zhongeric Nov 13, 2023
b1a531c
Merge branch 'main' into minimal-balances
zhongeric Nov 14, 2023
44e5985
feedback
zhongeric Nov 14, 2023
49ca9a7
Add gas snaps
zhongeric Nov 14, 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
Merge branch 'main' into minimal-balances
  • Loading branch information
zhongeric committed Nov 6, 2023
commit 20ea78552340564f5797a257c48ae86ffc048ef4
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
85275
1 change: 1 addition & 0 deletions .forge-snapshots/cached dynamic fee, no hooks.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
82459
2 changes: 1 addition & 1 deletion .forge-snapshots/donate gas with 1 token.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
95904
95882
2 changes: 1 addition & 1 deletion .forge-snapshots/donate gas with 2 tokens.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
153268
153224
2 changes: 1 addition & 1 deletion .forge-snapshots/initialize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
37987
38101
2 changes: 1 addition & 1 deletion .forge-snapshots/mint with empty hook.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
306991
306969
2 changes: 1 addition & 1 deletion .forge-snapshots/mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
293657
293635
1 change: 0 additions & 1 deletion .forge-snapshots/poolExtsloadSlot0.snap

This file was deleted.

1 change: 0 additions & 1 deletion .forge-snapshots/poolExtsloadTickInfoStruct.snap

This file was deleted.

1 change: 1 addition & 0 deletions .forge-snapshots/poolManager bytecode size.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24850
2 changes: 1 addition & 1 deletion .forge-snapshots/simple swap.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
49640
49691
Original file line number Diff line number Diff line change
@@ -1 +1 @@
124891
124942
2 changes: 1 addition & 1 deletion .forge-snapshots/swap against liquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
109601
109630
2 changes: 1 addition & 1 deletion .forge-snapshots/swap burn claim for input.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
126307
126402
1 change: 1 addition & 0 deletions .forge-snapshots/swap mint 1155 as output.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
169533
2 changes: 1 addition & 1 deletion .forge-snapshots/swap mint output as claim.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
166338
166355
1 change: 1 addition & 0 deletions .forge-snapshots/swap with 1155 as input.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
155963
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with dynamic fee.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
91422
84384
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with hooks.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
49611
49662
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
49640
49691
1 change: 1 addition & 0 deletions .forge-snapshots/update dynamic fee in before swap.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
91100
24 changes: 0 additions & 24 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,6 @@ on:
pull_request:

jobs:
unit-tests:
name: Hardhat Unit Tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'

- name: Install dependencies
run: yarn install --frozen-lockfile

# This is required separately from yarn test because it generates the typechain definitions
- name: Compile
run: yarn compile

- name: Run unit tests
run: yarn test

forge-tests:
name: Forge Tests
runs-on: ubuntu-latest
Expand Down
16 changes: 1 addition & 15 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Finally, before opening a pull request please do the following:
- Run the tests and snapshots. Commands are outlined in the [tests](#tests) section.
- Document any new functions, structs, or interfaces following the natspec standard.
- Add tests! For smaller contributions, they should be tested with unit tests, and fuzz tests where possible. For bigger contributions, they should be tested with integration tests and invariant tests where possible.
- Make sure all commits are [signed](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
- Make sure all commits are [signed](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)

## Standards

Expand All @@ -46,28 +46,14 @@ All contributions must follow the below standards. Maintainers will close out PR

## Setup

`yarn install` to install dependencies for hardhat

`yarn compile` to compile contracts for hardhat

`forge build` to get contract artifacts and dependencies for forge

## Tests

This repo currently uses hardhat and forge tests. Please run both test suites before opening a PR.

`yarn snapshots` to update the hardhat gas snapshots

`yarn test` to run hardhat tests

`yarn prettier` to run the formatter (runs both typescript and solidity formatting)

`forge snapshot`to update the forge gas snapshots

`forge test` to run forge tests

Any new tests that you add should be written with forge, as the repo is undergoing a full migration to the forge test suite.

## Code of Conduct

Above all else, please be respectful of the people behind the code. Any kind of aggressive or disrespectful comments, issues, and language will be removed.
Expand Down
9 changes: 9 additions & 0 deletions contracts/Fees.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ import {FeeLibrary} from "./libraries/FeeLibrary.sol";
import {Pool} from "./libraries/Pool.sol";
import {PoolKey} from "./types/PoolKey.sol";
import {Owned} from "./Owned.sol";
import {IDynamicFeeManager} from "./interfaces/IDynamicFeeManager.sol";

abstract contract Fees is IFees, Owned {
using FeeLibrary for uint24;
using CurrencyLibrary for Currency;

uint8 public constant MIN_PROTOCOL_FEE_DENOMINATOR = 4;

// the swap fee is represented in hundredths of a bip, so the max is 100%
uint24 public constant MAX_SWAP_FEE = 1000000;

mapping(Currency currency => uint256) public protocolFeesAccrued;

mapping(address hookAddress => mapping(Currency currency => uint256)) public hookFeesAccrued;
Expand Down Expand Up @@ -61,6 +65,11 @@ abstract contract Fees is IFees, Owned {
}
}

function _fetchDynamicSwapFee(PoolKey memory key) internal view returns (uint24 dynamicSwapFee) {
dynamicSwapFee = IDynamicFeeManager(address(key.hooks)).getFee(msg.sender, key);
if (dynamicSwapFee >= MAX_SWAP_FEE) revert FeeTooLarge();
}

/// @dev Only the lower 12 bits are used here to encode the fee denominator.
function _checkProtocolFee(uint16 fee) internal pure {
if (fee != 0) {
Expand Down
45 changes: 21 additions & 24 deletions contracts/PoolManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, MinimalBalance {
// see TickBitmap.sol for overflow conditions that can arise from tick spacing being too large
if (key.tickSpacing > MAX_TICK_SPACING) revert TickSpacingTooLarge();
if (key.tickSpacing < MIN_TICK_SPACING) revert TickSpacingTooSmall();
if (key.currency0 > key.currency1) revert CurrenciesInitializedOutOfOrder();
if (key.currency0 >= key.currency1) revert CurrenciesInitializedOutOfOrder();
if (!key.hooks.isValidHookAddress(key.fee)) revert Hooks.HookAddressNotValid(address(key.hooks));

if (key.hooks.shouldCallBeforeInitialize()) {
Expand All @@ -119,9 +119,10 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, MinimalBalance {
}

PoolId id = key.toId();
uint24 protocolFees = _fetchProtocolFees(key);
uint24 hookFees = _fetchHookFees(key);
tick = pools[id].initialize(sqrtPriceX96, protocolFees, hookFees);

uint24 swapFee = key.fee.isDynamicFee() ? _fetchDynamicSwapFee(key) : key.fee.getStaticFee();

tick = pools[id].initialize(sqrtPriceX96, _fetchProtocolFees(key), _fetchHookFees(key), swapFee);

if (key.hooks.shouldCallAfterInitialize()) {
if (
Expand All @@ -132,6 +133,7 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, MinimalBalance {
}
}

// On intitalize we emit the key's fee, which tells us all fee settings a pool can have: either a static swap fee or dynamic swap fee and if the hook has enabled swap or withdraw fees.
emit Initialize(id, key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks);
}

Expand Down Expand Up @@ -250,23 +252,14 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, MinimalBalance {
}
}

// Set the total swap fee, either through the hook or as the static fee set an initialization.
uint24 totalSwapFee;
if (key.fee.isDynamicFee()) {
totalSwapFee = IDynamicFeeManager(address(key.hooks)).getFee(msg.sender, key, params, hookData);
if (totalSwapFee >= 1000000) revert FeeTooLarge();
} else {
// clear the top 4 bits since they may be flagged for hook fees
totalSwapFee = key.fee.getStaticFee();
}
PoolId id = key.toId();

uint256 feeForProtocol;
uint256 feeForHook;
uint24 swapFee;
Pool.SwapState memory state;
PoolId id = key.toId();
(delta, feeForProtocol, feeForHook, state) = pools[id].swap(
(delta, feeForProtocol, feeForHook, swapFee, state) = pools[id].swap(
Pool.SwapParams({
fee: totalSwapFee,
tickSpacing: key.tickSpacing,
zeroForOne: params.zeroForOne,
amountSpecified: params.amountSpecified,
Expand All @@ -293,14 +286,7 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, MinimalBalance {
}

emit Swap(
id,
msg.sender,
delta.amount0(),
delta.amount1(),
state.sqrtPriceX96,
state.liquidity,
state.tick,
totalSwapFee
id, msg.sender, delta.amount0(), delta.amount1(), state.sqrtPriceX96, state.liquidity, state.tick, swapFee
);
}

Expand Down Expand Up @@ -387,6 +373,17 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, MinimalBalance {
emit HookFeeUpdated(id, newHookFees);
}

function updateDynamicSwapFee(PoolKey memory key) external {
if (key.fee.isDynamicFee()) {
uint24 newDynamicSwapFee = _fetchDynamicSwapFee(key);
PoolId id = key.toId();
pools[id].setSwapFee(newDynamicSwapFee);
emit DynamicSwapFeeUpdated(id, newDynamicSwapFee);
} else {
revert FeeNotDynamic();
}
}

function extsload(bytes32 slot) external view returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
Expand Down
4 changes: 1 addition & 3 deletions contracts/interfaces/IDynamicFeeManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,5 @@ import {IPoolManager} from "./IPoolManager.sol";
/// @notice The dynamic fee manager determines fees for pools
/// @dev note that this pool is only called if the PoolKey fee value is equal to the DYNAMIC_FEE magic value
interface IDynamicFeeManager {
function getFee(address sender, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata data)
external
returns (uint24);
function getFee(address sender, PoolKey calldata key) external view returns (uint24);
}
2 changes: 2 additions & 0 deletions contracts/interfaces/IFees.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ interface IFees {
error FeeTooLarge();
/// @notice Thrown when not enough gas is provided to look up the protocol fee
error ProtocolFeeCannotBeFetched();
/// @notice Thrown when a pool does not have a dynamic fee.
error FeeNotDynamic();

event ProtocolFeeControllerUpdated(address protocolFeeController);

Expand Down
5 changes: 5 additions & 0 deletions contracts/interfaces/IPoolManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ interface IPoolManager is IFees {

event HookFeeUpdated(PoolId indexed id, uint24 hookFees);

event DynamicSwapFeeUpdated(PoolId indexed id, uint24 dynamicSwapFee);

/// @notice Returns the constant representing the maximum tickSpacing for an initialized pool key
function MAX_TICK_SPACING() external view returns (int24);

Expand Down Expand Up @@ -192,6 +194,9 @@ interface IPoolManager is IFees {
/// @notice Sets the hook's swap and withdrawal fees for the given pool
function setHookFees(PoolKey memory key) external;

/// @notice Updates the pools swap fees for the a pool that has enabled dynamic swap fees.
function updateDynamicSwapFee(PoolKey memory key) external;

/// @notice Called by external contracts to access granular pool state
/// @param slot Key of slot to sload
/// @return value The value of the slot as bytes32
Expand Down
31 changes: 25 additions & 6 deletions contracts/libraries/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ library Pool {
int24 tick;
uint24 protocolFees;
uint24 hookFees;
// used for the swap fee, either static at initialize or dynamic via hook
uint24 swapFee;
}
// 24 bits left!

// info stored for each initialized individual tick
struct TickInfo {
Expand Down Expand Up @@ -107,15 +108,21 @@ library Pool {
if (tickUpper > TickMath.MAX_TICK) revert TickUpperOutOfBounds(tickUpper);
}

function initialize(State storage self, uint160 sqrtPriceX96, uint24 protocolFees, uint24 hookFees)
function initialize(State storage self, uint160 sqrtPriceX96, uint24 protocolFees, uint24 hookFees, uint24 swapFee)
internal
returns (int24 tick)
{
if (self.slot0.sqrtPriceX96 != 0) revert PoolAlreadyInitialized();

tick = TickMath.getTickAtSqrtRatio(sqrtPriceX96);

self.slot0 = Slot0({sqrtPriceX96: sqrtPriceX96, tick: tick, protocolFees: protocolFees, hookFees: hookFees});
self.slot0 = Slot0({
sqrtPriceX96: sqrtPriceX96,
tick: tick,
protocolFees: protocolFees,
hookFees: hookFees,
swapFee: swapFee
});
}

function getSwapFee(uint24 feesStorage) internal pure returns (uint16) {
Expand All @@ -138,6 +145,12 @@ library Pool {
self.slot0.hookFees = hookFees;
}

/// @notice Only dynamic fee pools may update the swap fee.
function setSwapFee(State storage self, uint24 swapFee) internal {
if (self.slot0.sqrtPriceX96 == 0) revert PoolNotInitialized();
self.slot0.swapFee = swapFee;
}

struct ModifyPositionParams {
// the address that owns the position
address owner;
Expand Down Expand Up @@ -367,7 +380,6 @@ library Pool {
}

struct SwapParams {
uint24 fee;
int24 tickSpacing;
bool zeroForOne;
int256 amountSpecified;
Expand All @@ -377,11 +389,18 @@ library Pool {
/// @dev Executes a swap against the state, and returns the amount deltas of the pool
function swap(State storage self, SwapParams memory params)
internal
returns (BalanceDelta result, uint256 feeForProtocol, uint256 feeForHook, SwapState memory state)
returns (
BalanceDelta result,
uint256 feeForProtocol,
uint256 feeForHook,
uint24 swapFee,
SwapState memory state
)
{
if (params.amountSpecified == 0) revert SwapAmountCannotBeZero();

Slot0 memory slot0Start = self.slot0;
swapFee = slot0Start.swapFee;
if (slot0Start.sqrtPriceX96 == 0) revert PoolNotInitialized();
if (params.zeroForOne) {
if (params.sqrtPriceLimitX96 >= slot0Start.sqrtPriceX96) {
Expand Down Expand Up @@ -446,7 +465,7 @@ library Pool {
) ? params.sqrtPriceLimitX96 : step.sqrtPriceNextX96,
state.liquidity,
state.amountSpecifiedRemaining,
params.fee
swapFee
);

if (exactInput) {
Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.