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 23 commits
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
Original file line number Diff line number Diff line change
@@ -1 +1 @@
85384
85251
2 changes: 1 addition & 1 deletion .forge-snapshots/cached dynamic fee, no hooks.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
82539
82435
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 @@
95961
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 @@
153292
153224
2 changes: 1 addition & 1 deletion .forge-snapshots/gas overhead of no-op lock.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
58562
58461
2 changes: 1 addition & 1 deletion .forge-snapshots/initialize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
38123
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 @@
307130
306969
2 changes: 1 addition & 1 deletion .forge-snapshots/mint with native token.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
275102
274999
2 changes: 1 addition & 1 deletion .forge-snapshots/mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
293738
293635
2 changes: 1 addition & 1 deletion .forge-snapshots/poolManager bytecode size.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
29853
24850
2 changes: 1 addition & 1 deletion .forge-snapshots/simple swap.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
49771
49667
Original file line number Diff line number Diff line change
@@ -1 +1 @@
125033
124918
2 changes: 1 addition & 1 deletion .forge-snapshots/swap against liquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
109721
109606
1 change: 1 addition & 0 deletions .forge-snapshots/swap burn claim for input.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
126378
1 change: 1 addition & 0 deletions .forge-snapshots/swap mint output as claim.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
166331
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 @@
84493
84360
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with hooks.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
49742
49638
2 changes: 1 addition & 1 deletion .forge-snapshots/swap with native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
49771
49667
2 changes: 1 addition & 1 deletion .forge-snapshots/update dynamic fee in before swap.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
91231
91076
54 changes: 54 additions & 0 deletions contracts/MinimalBalance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;

import {Currency, CurrencyLibrary} from "./types/Currency.sol";
import {IMinimalBalance} from "./interfaces/IMinimalBalance.sol";

/// An intentionally barebone balance mapping only supporting mint/burn/transfer
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
contract MinimalBalance is IMinimalBalance {
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
using CurrencyLibrary for Currency;
// Mapping from Currency id to account balances

zhongeric marked this conversation as resolved.
Show resolved Hide resolved
mapping(uint256 => mapping(address => uint256)) public balances;

/// @inheritdoc IMinimalBalance
function balanceOf(address account, Currency currency) public view returns (uint256) {
return balances[currency.toId()][account];
}

/**
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
* @notice Mint `amount` of currency `id` to `to`
* @param to The address to mint to
* @param id The id to mint
* @param amount The amount to mint
*/
function _mint(address to, uint256 id, uint256 amount) internal {
balances[id][to] += amount;
emit Mint(to, id, amount);
}

/**
* @notice Burn `amount` of currency `id` from `msg.sender`
* @param id The id of the currency to burn
* @param amount The amount to burn
* @dev Will revert if the sender does not have enough balance
*/
function _burn(uint256 id, uint256 amount) internal {
if (amount > balances[id][msg.sender]) revert InsufficientBalance();
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
unchecked {
balances[id][msg.sender] -= amount;
}
emit Burn(msg.sender, id, amount);
}

/// @inheritdoc IMinimalBalance
function transfer(address to, Currency currency, uint256 amount) public {
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
uint256 id = currency.toId();
if (amount > balances[id][msg.sender]) revert InsufficientBalance();
unchecked {
balances[id][msg.sender] -= amount;
}
balances[id][to] += amount;
emit Transfer(msg.sender, to, id, amount);
}
}
41 changes: 20 additions & 21 deletions contracts/PoolManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@ import {IHookFeeManager} from "./interfaces/IHookFeeManager.sol";
import {IPoolManager} from "./interfaces/IPoolManager.sol";
import {ILockCallback} from "./interfaces/callback/ILockCallback.sol";
import {Fees} from "./Fees.sol";
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {MinimalBalance} from "./MinimalBalance.sol";
import {PoolId, PoolIdLibrary} from "./types/PoolId.sol";
import {BalanceDelta} from "./types/BalanceDelta.sol";

/// @notice Holds the state for all pools
contract PoolManager is IPoolManager, Fees, NoDelegateCall, ERC1155, IERC1155Receiver {
contract PoolManager is IPoolManager, Fees, NoDelegateCall, MinimalBalance {
using PoolIdLibrary for PoolKey;
using SafeCast for *;
using Pool for *;
Expand Down Expand Up @@ -51,7 +50,7 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, ERC1155, IERC1155Rec

mapping(PoolId id => Pool.State) public pools;

constructor(uint256 controllerGasLimit) Fees(controllerGasLimit) ERC1155("") {}
constructor(uint256 controllerGasLimit) Fees(controllerGasLimit) {}

function _getPool(PoolKey memory key) private view returns (Pool.State storage) {
return pools[key.toId()];
Expand Down Expand Up @@ -324,9 +323,9 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, ERC1155, IERC1155Rec
}

/// @inheritdoc IPoolManager
function mint(Currency currency, address to, uint256 amount) external override noDelegateCall onlyByLocker {
function mint(Currency currency, address to, uint256 amount) external noDelegateCall onlyByLocker {
_accountDelta(currency, amount.toInt128());
_mint(to, currency.toId(), amount, "");
_mint(to, currency.toId(), amount);
}

/// @inheritdoc IPoolManager
Expand All @@ -338,26 +337,26 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, ERC1155, IERC1155Rec
_accountDelta(currency, -(paid.toInt128()));
}

function _burnAndAccount(Currency currency, uint256 amount) internal {
_burn(address(this), currency.toId(), amount);
_accountDelta(currency, -(amount.toInt128()));
}

function onERC1155Received(address, address, uint256 id, uint256 value, bytes calldata) external returns (bytes4) {
if (msg.sender != address(this)) revert NotPoolManagerToken();
_burnAndAccount(CurrencyLibrary.fromId(id), value);
return IERC1155Receiver.onERC1155Received.selector;
/// @inheritdoc IPoolManager
function burn(Currency currency, uint256 amount) external noDelegateCall onlyByLocker {
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
_burnAndAccount(currency, amount);
}

function onERC1155BatchReceived(address, address, uint256[] calldata ids, uint256[] calldata values, bytes calldata)
/// @inheritdoc IPoolManager
function batchBurn(Currency[] calldata currencies, uint256[] calldata amounts)
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
external
returns (bytes4)
noDelegateCall
onlyByLocker
{
if (msg.sender != address(this)) revert NotPoolManagerToken();
for (uint256 i; i < ids.length; i++) {
_burnAndAccount(CurrencyLibrary.fromId(ids[i]), values[i]);
uint256 length = currencies.length;
for (uint256 i; i < length; i++) {
_burnAndAccount(currencies[i], amounts[i]);
}
return IERC1155Receiver.onERC1155BatchReceived.selector;
}

function _burnAndAccount(Currency currency, uint256 amount) internal {
_accountDelta(currency, -(amount.toInt128()));
_burn(currency.toId(), amount);
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
}

function setProtocolFees(PoolKey memory key) external {
Expand Down
24 changes: 24 additions & 0 deletions contracts/interfaces/IMinimalBalance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Currency} from "../types/Currency.sol";

interface IMinimalBalance {
error InsufficientBalance();

/// @notice Get the balance of `account` for `currency`
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
function balanceOf(address account, Currency currency) external returns (uint256);

/*
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
@notice Transfer `amount` of `currency` from sender to `to`
@param to The address to transfer to
@param currency The currency to transfer
@param amount The amount to transfer
@dev Will revert if the sender does not have enough balance
**/
function transfer(address to, Currency currency, uint256 amount) external;

event Mint(address indexed to, uint256 indexed id, uint256 amount);
event Burn(address indexed from, uint256 indexed id, uint256 amount);
event Transfer(address indexed from, address indexed to, uint256 indexed id, uint256 amount);
}
11 changes: 8 additions & 3 deletions contracts/interfaces/IPoolManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ pragma solidity ^0.8.20;
import {Currency} from "../types/Currency.sol";
import {PoolKey} from "../types/PoolKey.sol";
import {Pool} from "../libraries/Pool.sol";
import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import {IHooks} from "./IHooks.sol";
import {IFees} from "./IFees.sol";
import {BalanceDelta} from "../types/BalanceDelta.sol";
import {PoolId} from "../types/PoolId.sol";
import {Position} from "../libraries/Position.sol";

interface IPoolManager is IFees, IERC1155 {
interface IPoolManager is IFees {
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
/// @notice Thrown when currencies touched has exceeded max of 256
error MaxCurrenciesTouched();

Expand Down Expand Up @@ -176,9 +175,15 @@ interface IPoolManager is IFees, IERC1155 {
/// @dev Can also be used as a mechanism for _free_ flash loans
function take(Currency currency, address to, uint256 amount) external;

/// @notice Called by the user to move value into ERC1155 balance
/// @notice Called by the user to move value into Claims balance
function mint(Currency token, address to, uint256 amount) external;

/// @notice Called by the user to redeem their Claims balance
function burn(Currency token, uint256 amount) external;

/// @notice Called by the user to batch redeem their Claims balances
function batchBurn(Currency[] calldata tokens, uint256[] calldata amounts) external;

/// @notice Called by the user to pay what is owed
function settle(Currency token) external payable returns (uint256 paid);

Expand Down
31 changes: 12 additions & 19 deletions contracts/test/PoolSwapTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pragma solidity ^0.8.20;

import {CurrencyLibrary, Currency} from "../types/Currency.sol";
import {IERC20Minimal} from "../interfaces/external/IERC20Minimal.sol";

import {ILockCallback} from "../interfaces/callback/ILockCallback.sol";
import {IPoolManager} from "../interfaces/IPoolManager.sol";
import {BalanceDelta} from "../types/BalanceDelta.sol";
Expand Down Expand Up @@ -45,6 +44,14 @@ contract PoolSwapTest is ILockCallback {
if (ethBalance > 0) CurrencyLibrary.NATIVE.transfer(msg.sender, ethBalance);
}

function _mintForSelf(Currency currency, uint256 amount) internal {
manager.mint(currency, address(this), amount);
}

function _burnFromSelf(Currency currency, uint256 amount) internal {
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
manager.burn(currency, amount);
}
zhongeric marked this conversation as resolved.
Show resolved Hide resolved

function lockAcquired(bytes calldata rawData) external returns (bytes memory) {
require(msg.sender == address(manager));

Expand All @@ -64,21 +71,14 @@ contract PoolSwapTest is ILockCallback {
manager.settle(data.key.currency0);
}
} else {
// the received hook on this transfer will burn the tokens
manager.safeTransferFrom(
data.sender,
address(manager),
uint256(uint160(Currency.unwrap(data.key.currency0))),
uint128(delta.amount0()),
""
);
_burnFromSelf(data.key.currency0, uint128(delta.amount0()));
}
}
if (delta.amount1() < 0) {
if (data.testSettings.withdrawTokens) {
manager.take(data.key.currency1, data.sender, uint128(-delta.amount1()));
} else {
manager.mint(data.key.currency1, data.sender, uint128(-delta.amount1()));
_mintForSelf(data.key.currency1, uint128(-delta.amount1()));
}
}
} else {
Expand All @@ -93,21 +93,14 @@ contract PoolSwapTest is ILockCallback {
manager.settle(data.key.currency1);
}
} else {
// the received hook on this transfer will burn the tokens
manager.safeTransferFrom(
data.sender,
address(manager),
uint256(uint160(Currency.unwrap(data.key.currency1))),
uint128(delta.amount1()),
""
);
_burnFromSelf(data.key.currency1, uint128(delta.amount1()));
}
}
if (delta.amount0() < 0) {
if (data.testSettings.withdrawTokens) {
manager.take(data.key.currency0, data.sender, uint128(-delta.amount0()));
} else {
manager.mint(data.key.currency0, data.sender, uint128(-delta.amount0()));
_mintForSelf(data.key.currency0, uint128(-delta.amount0()));
}
}
}
Expand Down
Loading