From 262d72862d60e8c34cc9e2646b9b5b74353c1c7a Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Fri, 16 Aug 2024 13:20:53 +0700 Subject: [PATCH 01/21] BREAKING CHANGE: restructure factory to be behind TransparentUpgradeableProxy --- script/DeployKatanaV3Core.s.sol | 23 +++++++++-- script/DeployKatanaV3Periphery.s.sol | 4 +- script/local/DeployKatanaV3Local.s.sol | 2 + .../ronin-mainnet/DeployKatanaV3Mainnet.s.sol | 2 +- .../ronin-testnet/DeployKatanaV3Testnet.s.sol | 2 +- src/core/KatanaV3Factory.sol | 8 ++-- src/core/KatanaV3FactoryProxy.sol | 40 ------------------- src/core/KatanaV3Pool.sol | 8 ++-- src/core/KatanaV3PoolBeacon.sol | 19 +++++++++ src/core/KatanaV3PoolDeployer.sol | 20 ++++++---- src/core/KatanaV3PoolProxy.sol | 4 +- src/core/KatanaV3PoolProxyBytecode.sol | 16 -------- src/core/interfaces/IKatanaV3Factory.sol | 4 ++ .../interfaces/IKatanaV3FactoryImmutables.sol | 14 ------- .../IKatanaV3PoolBeaconImmutables.sol | 11 +++++ src/core/interfaces/IKatanaV3PoolDeployer.sol | 3 ++ .../interfaces/pool/IKatanaV3PoolEvents.sol | 2 +- src/periphery/NonfungiblePositionManager.sol | 3 ++ src/periphery/libraries/PoolAddress.sol | 2 +- test/core/KatanaV3Factory.t.sol | 1 - test/core/KatanaV3Pool.t.sol | 1 - 21 files changed, 90 insertions(+), 99 deletions(-) delete mode 100644 src/core/KatanaV3FactoryProxy.sol create mode 100644 src/core/KatanaV3PoolBeacon.sol delete mode 100644 src/core/KatanaV3PoolProxyBytecode.sol delete mode 100644 src/core/interfaces/IKatanaV3FactoryImmutables.sol create mode 100644 src/core/interfaces/IKatanaV3PoolBeaconImmutables.sol diff --git a/script/DeployKatanaV3Core.s.sol b/script/DeployKatanaV3Core.s.sol index c7dbf3f..e832391 100644 --- a/script/DeployKatanaV3Core.s.sol +++ b/script/DeployKatanaV3Core.s.sol @@ -3,13 +3,18 @@ pragma solidity ^0.7.6; import { Script, console } from "forge-std/Script.sol"; import { KatanaV3Factory } from "@katana/v3-contracts/core/KatanaV3Factory.sol"; -import { KatanaV3FactoryProxy } from "@katana/v3-contracts/core/KatanaV3FactoryProxy.sol"; +import { KatanaV3Pool } from "@katana/v3-contracts/core/KatanaV3Pool.sol"; +import { KatanaV3PoolBeacon } from "@katana/v3-contracts/core/KatanaV3PoolBeacon.sol"; +import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/TransparentUpgradeableProxy.sol"; abstract contract DeployKatanaV3Core is Script { + address public sender; address public proxyAdmin; address public governance; address public treasury; + address poolImplementation; + address public beacon; address public factory; function setUp() public virtual { @@ -22,12 +27,22 @@ abstract contract DeployKatanaV3Core is Script { function run() public virtual { vm.startBroadcast(); - address factoryImplementation = address(new KatanaV3Factory()); + address predictedFactory = vm.computeCreateAddress(sender, vm.getNonce(sender) + 3); + vm.label(predictedFactory, "PredictedFactory"); + + poolImplementation = address(new KatanaV3Pool(predictedFactory, governance)); + beacon = address(new KatanaV3PoolBeacon(poolImplementation)); + + address factoryImplementation = address(new KatanaV3Factory(beacon)); factory = address( - new KatanaV3FactoryProxy( - factoryImplementation, proxyAdmin, abi.encodeWithSelector(KatanaV3Factory.initialize.selector, governance, treasury) + new TransparentUpgradeableProxy( + factoryImplementation, + proxyAdmin, + abi.encodeWithSelector(KatanaV3Factory.initialize.selector, governance, treasury) ) ); + require(factory == predictedFactory, "Factory address mismatch"); + console.log("KatanaV3Factory deployed:", factory); vm.stopBroadcast(); diff --git a/script/DeployKatanaV3Periphery.s.sol b/script/DeployKatanaV3Periphery.s.sol index 6acff83..f60dd3c 100644 --- a/script/DeployKatanaV3Periphery.s.sol +++ b/script/DeployKatanaV3Periphery.s.sol @@ -47,7 +47,9 @@ abstract contract DeployKatanaV3Periphery is DeployKatanaV3Core { abi.encodeWithSelector(NonfungiblePositionManager.initialize.selector) ) ); - require(NonfungiblePositionManager(payable(nonfungiblePositionManager)).governance() == governance, "governance mismatch"); + require( + NonfungiblePositionManager(payable(nonfungiblePositionManager)).governance() == governance, "governance mismatch" + ); console.log("NonfungiblePositionManager deployed:", nonfungiblePositionManager); v3migrator = address(new V3Migrator(factory, wron, nonfungiblePositionManager)); diff --git a/script/local/DeployKatanaV3Local.s.sol b/script/local/DeployKatanaV3Local.s.sol index 8e00663..c35ca5c 100644 --- a/script/local/DeployKatanaV3Local.s.sol +++ b/script/local/DeployKatanaV3Local.s.sol @@ -18,6 +18,8 @@ contract DeployKatanaV3Local is DeployKatanaV3Periphery { wron = address(new ERC20Mock("Wrapped Ronin", "WRON", address(this), 10 ** 9 * 10 ** 9)); factoryV2 = makeAddr("KatanaV2Factory"); + sender = DEFAULT_SENDER; + super.setUp(); } diff --git a/script/ronin-mainnet/DeployKatanaV3Mainnet.s.sol b/script/ronin-mainnet/DeployKatanaV3Mainnet.s.sol index 8f14a02..5086b60 100644 --- a/script/ronin-mainnet/DeployKatanaV3Mainnet.s.sol +++ b/script/ronin-mainnet/DeployKatanaV3Mainnet.s.sol @@ -16,7 +16,7 @@ contract DeployKatanaV3Mainnet is DeployKatanaV3Periphery { wron = 0xe514d9DEB7966c8BE0ca922de8a064264eA6bcd4; // WRON factoryV2 = 0xB255D6A720BB7c39fee173cE22113397119cB930; // Katana V2 Factory - vm.rememberKey(vm.envUint("MAINNET_PK")); + sender = vm.rememberKey(vm.envUint("MAINNET_PK")); super.setUp(); } diff --git a/script/ronin-testnet/DeployKatanaV3Testnet.s.sol b/script/ronin-testnet/DeployKatanaV3Testnet.s.sol index 916646e..c1abf71 100644 --- a/script/ronin-testnet/DeployKatanaV3Testnet.s.sol +++ b/script/ronin-testnet/DeployKatanaV3Testnet.s.sol @@ -16,7 +16,7 @@ contract DeployKatanaV3Testnet is DeployKatanaV3Periphery { wron = 0xA959726154953bAe111746E265E6d754F48570E6; factoryV2 = 0x86587380C4c815Ba0066c90aDB2B45CC9C15E72c; - vm.rememberKey(vm.envUint("TESTNET_PK")); + sender = vm.rememberKey(vm.envUint("TESTNET_PK")); super.setUp(); } diff --git a/src/core/KatanaV3Factory.sol b/src/core/KatanaV3Factory.sol index 28d7f1e..f940634 100644 --- a/src/core/KatanaV3Factory.sol +++ b/src/core/KatanaV3Factory.sol @@ -20,6 +20,8 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { address public override treasury; /// @inheritdoc IKatanaV3Factory bool public override flashLoanEnabled; + /// @dev Whether the factory has been initialized + bool private _initialized; /// @inheritdoc IKatanaV3Factory mapping(uint24 => int24) public override feeAmountTickSpacing; @@ -28,10 +30,7 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { /// @inheritdoc IKatanaV3Factory mapping(address => mapping(address => mapping(uint24 => address))) public override getPool; - /// @dev Whether the factory has been initialized - bool private _initialized; - - constructor() { + constructor(address beacon) KatanaV3PoolDeployer(beacon) { // disable initialization _initialized = true; } @@ -93,6 +92,7 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { function toggleFlashLoanPermission() external override { require(msg.sender == owner); flashLoanEnabled = !flashLoanEnabled; + emit FlashLoanPermissionUpdated(flashLoanEnabled); } /// @inheritdoc IKatanaV3Factory diff --git a/src/core/KatanaV3FactoryProxy.sol b/src/core/KatanaV3FactoryProxy.sol deleted file mode 100644 index a18e2e1..0000000 --- a/src/core/KatanaV3FactoryProxy.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity =0.7.6; - -import "@openzeppelin/contracts/proxy/TransparentUpgradeableProxy.sol"; -import "@openzeppelin/contracts/proxy/UpgradeableBeacon.sol"; - -import "./interfaces/IKatanaV3FactoryImmutables.sol"; -import "./interfaces/IKatanaV3Factory.sol"; - -import "./KatanaV3Pool.sol"; -import "./KatanaV3PoolProxy.sol"; -import "./KatanaV3PoolProxyBytecode.sol"; - -contract KatanaV3FactoryProxy is TransparentUpgradeableProxy, IKatanaV3FactoryImmutables { - /// @inheritdoc IKatanaV3FactoryImmutables - bytes32 public constant override POOL_PROXY_INIT_CODE_HASH = keccak256(type(KatanaV3PoolProxy).creationCode); - /// @inheritdoc IKatanaV3FactoryImmutables - address public immutable override POOL_PROXY_BYTECODE_POINTER; - /// @inheritdoc IKatanaV3FactoryImmutables - address public immutable override BEACON; - - constructor(address _logic, address proxyAdmin, bytes memory _data) TransparentUpgradeableProxy(_logic, proxyAdmin, _data) { - POOL_PROXY_BYTECODE_POINTER = address(new KatanaV3PoolProxyBytecode()); - - address governance; - assembly { - // the first 32 bytes of _data is the length of the bytes array - // the next 4 bytes is the function selector of the initialize function (initialize(address,address)) - // the next 32 bytes (start at offset 36) is the owner (governance) address - governance := mload(add(_data, 36)) - } - address poolImplementation = address(new KatanaV3Pool(address(this), governance)); - BEACON = address(new UpgradeableBeacon(poolImplementation)); - } - - /// @notice Upgrades the beacon to a new pool implementation - function upgradeBeaconTo(address newImplementation) external ifAdmin { - UpgradeableBeacon(BEACON).upgradeTo(newImplementation); - } -} diff --git a/src/core/KatanaV3Pool.sol b/src/core/KatanaV3Pool.sol index 9355f03..4d1061a 100644 --- a/src/core/KatanaV3Pool.sol +++ b/src/core/KatanaV3Pool.sol @@ -95,15 +95,13 @@ contract KatanaV3Pool is IKatanaV3Pool { address public override token0; /// @inheritdoc IKatanaV3PoolImmutables address public override token1; + + /// @inheritdoc IKatanaV3PoolImmutables + uint128 public override maxLiquidityPerTick; /// @inheritdoc IKatanaV3PoolImmutables uint24 public override fee; - /// @inheritdoc IKatanaV3PoolImmutables int24 public override tickSpacing; - - /// @inheritdoc IKatanaV3PoolImmutables - uint128 public override maxLiquidityPerTick; - /// @dev The contract is initialized with the immutable parameters bool private _immutablesInitialized; diff --git a/src/core/KatanaV3PoolBeacon.sol b/src/core/KatanaV3PoolBeacon.sol new file mode 100644 index 0000000..2d7452e --- /dev/null +++ b/src/core/KatanaV3PoolBeacon.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity =0.7.6; + +import "@openzeppelin/contracts/proxy/UpgradeableBeacon.sol"; + +import "./interfaces/IKatanaV3PoolBeaconImmutables.sol"; + +import "./KatanaV3PoolProxy.sol"; + +/// @title Beacon for deploying and upgrading Katana V3 pools +contract KatanaV3PoolBeacon is IKatanaV3PoolBeaconImmutables, UpgradeableBeacon { + /// @inheritdoc IKatanaV3PoolBeaconImmutables + bytes public constant override POOL_PROXY_INIT_CODE = type(KatanaV3PoolProxy).creationCode; + + /// @inheritdoc IKatanaV3PoolBeaconImmutables + bytes32 public constant override POOL_PROXY_INIT_CODE_HASH = keccak256(POOL_PROXY_INIT_CODE); + + constructor(address poolImplementation) UpgradeableBeacon(poolImplementation) { } +} diff --git a/src/core/KatanaV3PoolDeployer.sol b/src/core/KatanaV3PoolDeployer.sol index ecd6920..0ff15d2 100644 --- a/src/core/KatanaV3PoolDeployer.sol +++ b/src/core/KatanaV3PoolDeployer.sol @@ -1,10 +1,15 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; +import "@openzeppelin/contracts/utils/Create2.sol"; + import "./interfaces/IKatanaV3PoolDeployer.sol"; -import "./interfaces/IKatanaV3FactoryImmutables.sol"; +import "./interfaces/IKatanaV3PoolBeaconImmutables.sol"; + +abstract contract KatanaV3PoolDeployer is IKatanaV3PoolDeployer { + /// @inheritdoc IKatanaV3PoolDeployer + address public immutable override BEACON; -contract KatanaV3PoolDeployer is IKatanaV3PoolDeployer { struct Parameters { address factory; address token0; @@ -16,6 +21,10 @@ contract KatanaV3PoolDeployer is IKatanaV3PoolDeployer { /// @inheritdoc IKatanaV3PoolDeployer Parameters public override parameters; + constructor(address beacon) { + BEACON = beacon; + } + /// @dev Deploys a pool with the given parameters by transiently setting the parameters storage slot and then /// clearing it after deploying the pool. /// @param factory The contract address of the Katana V3 factory @@ -28,12 +37,9 @@ contract KatanaV3PoolDeployer is IKatanaV3PoolDeployer { returns (address pool) { parameters = Parameters({ factory: factory, token0: token0, token1: token1, fee: fee, tickSpacing: tickSpacing }); - address pointer = IKatanaV3FactoryImmutables(factory).POOL_PROXY_BYTECODE_POINTER(); - (, bytes memory creationCode) = pointer.staticcall(""); + bytes memory creationCode = IKatanaV3PoolBeaconImmutables(BEACON).POOL_PROXY_INIT_CODE(); bytes32 salt = keccak256(abi.encode(token0, token1, fee)); - assembly { - pool := create2(0, add(creationCode, 0x20), mload(creationCode), salt) - } + pool = Create2.deploy(0, salt, creationCode); delete parameters; } } diff --git a/src/core/KatanaV3PoolProxy.sol b/src/core/KatanaV3PoolProxy.sol index bdee5b6..f31d230 100644 --- a/src/core/KatanaV3PoolProxy.sol +++ b/src/core/KatanaV3PoolProxy.sol @@ -5,7 +5,7 @@ import "@openzeppelin/contracts/proxy/BeaconProxy.sol"; import "./interfaces/IKatanaV3PoolDeployer.sol"; import "./interfaces/IKatanaV3Factory.sol"; -import "./interfaces/IKatanaV3FactoryImmutables.sol"; +import "./interfaces/IKatanaV3PoolDeployer.sol"; import "./interfaces/pool/IKatanaV3PoolImmutablesInitializable.sol"; @@ -17,7 +17,7 @@ contract KatanaV3PoolProxy is BeaconProxy { (address factory, address token0, address token1, uint24 fee, int24 tickSpacing) = IKatanaV3PoolDeployer(msg.sender).parameters(); - beacon = IKatanaV3FactoryImmutables(factory).BEACON(); + beacon = IKatanaV3PoolDeployer(factory).BEACON(); data = abi.encodeWithSelector( IKatanaV3PoolImmutablesInitializable.initializeImmutables.selector, factory, token0, token1, fee, tickSpacing ); diff --git a/src/core/KatanaV3PoolProxyBytecode.sol b/src/core/KatanaV3PoolProxyBytecode.sol deleted file mode 100644 index 6bd56b2..0000000 --- a/src/core/KatanaV3PoolProxyBytecode.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity =0.7.6; - -import "./KatanaV3PoolProxy.sol"; - -/// @title The canonical storage location for the KatanaV3PoolProxy creation code. -/// @dev Always returns the creation code (in low-level calls) of the KatanaV3PoolProxy contract. -/// @dev The existence of this contract ensures the KatanaV3PoolProxy creation code is constant in later development. -contract KatanaV3PoolProxyBytecode { - fallback() external { - bytes memory bytecode = type(KatanaV3PoolProxy).creationCode; - assembly { - return(add(bytecode, 0x20), mload(bytecode)) - } - } -} diff --git a/src/core/interfaces/IKatanaV3Factory.sol b/src/core/interfaces/IKatanaV3Factory.sol index 975c1a4..afd8cf0 100644 --- a/src/core/interfaces/IKatanaV3Factory.sol +++ b/src/core/interfaces/IKatanaV3Factory.sol @@ -14,6 +14,10 @@ interface IKatanaV3Factory { /// @param newTreasury The treasury address after the treasury was changed event TreasuryChanged(address indexed oldTreasury, address indexed newTreasury); + /// @notice Emitted when the ability to call the `flash` function on KatanaV3Pool is toggled + /// @param enabled Whether flash loans are enabled + event FlashLoanPermissionUpdated(bool indexed enabled); + /// @notice Emitted when a pool is created /// @param token0 The first token of the pool by address sort order /// @param token1 The second token of the pool by address sort order diff --git a/src/core/interfaces/IKatanaV3FactoryImmutables.sol b/src/core/interfaces/IKatanaV3FactoryImmutables.sol deleted file mode 100644 index b628268..0000000 --- a/src/core/interfaces/IKatanaV3FactoryImmutables.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title The interface for the Katana V3 Factory immutables -interface IKatanaV3FactoryImmutables { - /// @dev The init code hash for the pool proxy - function POOL_PROXY_INIT_CODE_HASH() external view returns (bytes32); - - /// @dev The address that stores the pool proxy bytecode - function POOL_PROXY_BYTECODE_POINTER() external view returns (address); - - /// @dev The address of the beacon that returns the current pool implementation - function BEACON() external view returns (address); -} diff --git a/src/core/interfaces/IKatanaV3PoolBeaconImmutables.sol b/src/core/interfaces/IKatanaV3PoolBeaconImmutables.sol new file mode 100644 index 0000000..40152bd --- /dev/null +++ b/src/core/interfaces/IKatanaV3PoolBeaconImmutables.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +/// @title The interface for the Katana V3 Factory immutables +interface IKatanaV3PoolBeaconImmutables { + /// @dev The init code for the pool proxy + function POOL_PROXY_INIT_CODE() external view returns (bytes memory); + + /// @dev The init code hash for the pool proxy + function POOL_PROXY_INIT_CODE_HASH() external view returns (bytes32); +} diff --git a/src/core/interfaces/IKatanaV3PoolDeployer.sol b/src/core/interfaces/IKatanaV3PoolDeployer.sol index 031ec95..e9f21d5 100644 --- a/src/core/interfaces/IKatanaV3PoolDeployer.sol +++ b/src/core/interfaces/IKatanaV3PoolDeployer.sol @@ -6,6 +6,9 @@ pragma solidity >=0.5.0; /// @dev This is used to avoid having constructor arguments in the pool contract, which results in the init code hash /// of the pool being constant allowing the CREATE2 address of the pool to be cheaply computed on-chain interface IKatanaV3PoolDeployer { + /// @notice Returns the address of the beacon that pool proxies must be deployed with + function BEACON() external view returns (address); + /// @notice Get the parameters to be used in constructing the pool, set transiently during pool creation. /// @dev Called by the pool constructor to fetch the parameters of the pool /// Returns factory The factory address diff --git a/src/core/interfaces/pool/IKatanaV3PoolEvents.sol b/src/core/interfaces/pool/IKatanaV3PoolEvents.sol index 60b3e56..e8c037b 100644 --- a/src/core/interfaces/pool/IKatanaV3PoolEvents.sol +++ b/src/core/interfaces/pool/IKatanaV3PoolEvents.sol @@ -101,7 +101,7 @@ interface IKatanaV3PoolEvents { /// @param feeProtocolNumeratorOld The numerator of the previous value of protocol fee /// @param feeProtocolDenominatorOld The denominator of the previous value of protocol fee /// @param feeProtocolNumeratorNew The numerator of the updated value of protocol fee - /// @param feeProtocolDenominatorNew The denominator of the oupdated value of protocol fee + /// @param feeProtocolDenominatorNew The denominator of the updated value of protocol fee event SetFeeProtocol( uint8 feeProtocolNumeratorOld, uint8 feeProtocolDenominatorOld, diff --git a/src/periphery/NonfungiblePositionManager.sol b/src/periphery/NonfungiblePositionManager.sol index 572afa1..9816e38 100644 --- a/src/periphery/NonfungiblePositionManager.sol +++ b/src/periphery/NonfungiblePositionManager.sol @@ -104,15 +104,18 @@ contract NonfungiblePositionManager is _initialized = true; } + /// @inheritdoc IERC165 function supportsInterface(bytes4 interfaceId) public pure override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC165).interfaceId || interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || interfaceId == type(IERC721Enumerable).interfaceId; } + /// @inheritdoc IERC721Metadata function name() public pure override(ERC721, IERC721Metadata) returns (string memory) { return "Katana V3 Positions NFT-V1"; } + /// @inheritdoc IERC721Metadata function symbol() public pure override(ERC721, IERC721Metadata) returns (string memory) { return "KATANA-V3-POS"; } diff --git a/src/periphery/libraries/PoolAddress.sol b/src/periphery/libraries/PoolAddress.sol index 648bf56..8597d79 100644 --- a/src/periphery/libraries/PoolAddress.sol +++ b/src/periphery/libraries/PoolAddress.sol @@ -4,7 +4,7 @@ pragma solidity >=0.5.0; /// @title Provides functions for deriving a pool address from the factory, tokens, and the fee library PoolAddress { bytes32 internal constant POOL_PROXY_INIT_CODE_HASH = - 0x8055b6834943f8f684de0aebfd2f61ab734b814b3b15f7e76661ed7012d0ec11; + 0xdb6dc063a9c77abbc8b5d31a246baa926088cdb7892d44b1b09f921b83870df1; /// @notice The identifying key of the pool struct PoolKey { diff --git a/test/core/KatanaV3Factory.t.sol b/test/core/KatanaV3Factory.t.sol index a2da7e2..66ae5e9 100644 --- a/test/core/KatanaV3Factory.t.sol +++ b/test/core/KatanaV3Factory.t.sol @@ -7,7 +7,6 @@ import { Test, console } from "forge-std/Test.sol"; import { IKatanaV3Pool } from "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; import { KatanaV3Factory } from "@katana/v3-contracts/core/KatanaV3Factory.sol"; -import { KatanaV3FactoryProxy } from "@katana/v3-contracts/core/KatanaV3FactoryProxy.sol"; import { KatanaGovernanceMock } from "@katana/v3-contracts/external/KatanaGovernanceMock.sol"; import { DeployKatanaV3Local } from "script/local/DeployKatanaV3Local.s.sol"; diff --git a/test/core/KatanaV3Pool.t.sol b/test/core/KatanaV3Pool.t.sol index f5599a7..5b2644e 100644 --- a/test/core/KatanaV3Pool.t.sol +++ b/test/core/KatanaV3Pool.t.sol @@ -13,7 +13,6 @@ import { TickMath } from "@katana/v3-contracts/core/libraries/TickMath.sol"; import { KatanaV3Pool } from "@katana/v3-contracts/core/KatanaV3Pool.sol"; import { KatanaV3Factory } from "@katana/v3-contracts/core/KatanaV3Factory.sol"; -import { KatanaV3FactoryProxy } from "@katana/v3-contracts/core/KatanaV3FactoryProxy.sol"; import { NonfungiblePositionManager } from "@katana/v3-contracts/periphery/NonfungiblePositionManager.sol"; import { KatanaGovernanceMock } from "@katana/v3-contracts/external/KatanaGovernanceMock.sol"; From 92d6672af81379134f12fdcb045de4ccd6541d82 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Fri, 16 Aug 2024 13:21:30 +0700 Subject: [PATCH 02/21] chore: storage layout --- logs/storage/ERC721Permit.sol:ERC721Permit.log | 9 +++++++++ .../KatanaV3Factory.sol:KatanaV3Factory.log | 8 ++++++++ logs/storage/KatanaV3Pool.sol:KatanaV3Pool.log | 15 +++++++++++++++ ...naV3PoolDeployer.sol:KatanaV3PoolDeployer.log | 1 + ...ionManager.sol:NonfungiblePositionManager.log | 16 ++++++++++++++++ 5 files changed, 49 insertions(+) create mode 100644 logs/storage/ERC721Permit.sol:ERC721Permit.log create mode 100644 logs/storage/KatanaV3Factory.sol:KatanaV3Factory.log create mode 100644 logs/storage/KatanaV3Pool.sol:KatanaV3Pool.log create mode 100644 logs/storage/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer.log create mode 100644 logs/storage/NonfungiblePositionManager.sol:NonfungiblePositionManager.log diff --git a/logs/storage/ERC721Permit.sol:ERC721Permit.log b/logs/storage/ERC721Permit.sol:ERC721Permit.log new file mode 100644 index 0000000..73b1361 --- /dev/null +++ b/logs/storage/ERC721Permit.sol:ERC721Permit.log @@ -0,0 +1,9 @@ +src/periphery/base/ERC721Permit.sol:ERC721Permit:_supportedInterfaces (storage_slot: 0) (offset: 0) (type: mapping(bytes4 => bool)) (numberOfBytes: 32) +src/periphery/base/ERC721Permit.sol:ERC721Permit:_holderTokens (storage_slot: 1) (offset: 0) (type: mapping(address => struct EnumerableSet.UintSet)) (numberOfBytes: 32) +src/periphery/base/ERC721Permit.sol:ERC721Permit:_tokenOwners (storage_slot: 2) (offset: 0) (type: struct EnumerableMap.UintToAddressMap) (numberOfBytes: 64) +src/periphery/base/ERC721Permit.sol:ERC721Permit:_tokenApprovals (storage_slot: 4) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/periphery/base/ERC721Permit.sol:ERC721Permit:_operatorApprovals (storage_slot: 5) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/periphery/base/ERC721Permit.sol:ERC721Permit:_name (storage_slot: 6) (offset: 0) (type: string) (numberOfBytes: 32) +src/periphery/base/ERC721Permit.sol:ERC721Permit:_symbol (storage_slot: 7) (offset: 0) (type: string) (numberOfBytes: 32) +src/periphery/base/ERC721Permit.sol:ERC721Permit:_tokenURIs (storage_slot: 8) (offset: 0) (type: mapping(uint256 => string)) (numberOfBytes: 32) +src/periphery/base/ERC721Permit.sol:ERC721Permit:_baseURI (storage_slot: 9) (offset: 0) (type: string) (numberOfBytes: 32) \ No newline at end of file diff --git a/logs/storage/KatanaV3Factory.sol:KatanaV3Factory.log b/logs/storage/KatanaV3Factory.sol:KatanaV3Factory.log new file mode 100644 index 0000000..ee8d623 --- /dev/null +++ b/logs/storage/KatanaV3Factory.sol:KatanaV3Factory.log @@ -0,0 +1,8 @@ +src/core/KatanaV3Factory.sol:KatanaV3Factory:parameters (storage_slot: 0) (offset: 0) (type: struct KatanaV3PoolDeployer.Parameters) (numberOfBytes: 96) +src/core/KatanaV3Factory.sol:KatanaV3Factory:owner (storage_slot: 3) (offset: 0) (type: address) (numberOfBytes: 20) +src/core/KatanaV3Factory.sol:KatanaV3Factory:treasury (storage_slot: 4) (offset: 0) (type: address) (numberOfBytes: 20) +src/core/KatanaV3Factory.sol:KatanaV3Factory:flashLoanEnabled (storage_slot: 4) (offset: 20) (type: bool) (numberOfBytes: 1) +src/core/KatanaV3Factory.sol:KatanaV3Factory:_initialized (storage_slot: 4) (offset: 21) (type: bool) (numberOfBytes: 1) +src/core/KatanaV3Factory.sol:KatanaV3Factory:feeAmountTickSpacing (storage_slot: 5) (offset: 0) (type: mapping(uint24 => int24)) (numberOfBytes: 32) +src/core/KatanaV3Factory.sol:KatanaV3Factory:feeAmountProtocol (storage_slot: 6) (offset: 0) (type: mapping(uint24 => uint16)) (numberOfBytes: 32) +src/core/KatanaV3Factory.sol:KatanaV3Factory:getPool (storage_slot: 7) (offset: 0) (type: mapping(address => mapping(address => mapping(uint24 => address)))) (numberOfBytes: 32) \ No newline at end of file diff --git a/logs/storage/KatanaV3Pool.sol:KatanaV3Pool.log b/logs/storage/KatanaV3Pool.sol:KatanaV3Pool.log new file mode 100644 index 0000000..bdf1d11 --- /dev/null +++ b/logs/storage/KatanaV3Pool.sol:KatanaV3Pool.log @@ -0,0 +1,15 @@ +src/core/KatanaV3Pool.sol:KatanaV3Pool:slot0 (storage_slot: 0) (offset: 0) (type: struct KatanaV3Pool.Slot0) (numberOfBytes: 32) +src/core/KatanaV3Pool.sol:KatanaV3Pool:feeGrowthGlobal0X128 (storage_slot: 1) (offset: 0) (type: uint256) (numberOfBytes: 32) +src/core/KatanaV3Pool.sol:KatanaV3Pool:feeGrowthGlobal1X128 (storage_slot: 2) (offset: 0) (type: uint256) (numberOfBytes: 32) +src/core/KatanaV3Pool.sol:KatanaV3Pool:protocolFees (storage_slot: 3) (offset: 0) (type: struct KatanaV3Pool.ProtocolFees) (numberOfBytes: 32) +src/core/KatanaV3Pool.sol:KatanaV3Pool:liquidity (storage_slot: 4) (offset: 0) (type: uint128) (numberOfBytes: 16) +src/core/KatanaV3Pool.sol:KatanaV3Pool:ticks (storage_slot: 5) (offset: 0) (type: mapping(int24 => struct Tick.Info)) (numberOfBytes: 32) +src/core/KatanaV3Pool.sol:KatanaV3Pool:tickBitmap (storage_slot: 6) (offset: 0) (type: mapping(int16 => uint256)) (numberOfBytes: 32) +src/core/KatanaV3Pool.sol:KatanaV3Pool:positions (storage_slot: 7) (offset: 0) (type: mapping(bytes32 => struct Position.Info)) (numberOfBytes: 32) +src/core/KatanaV3Pool.sol:KatanaV3Pool:observations (storage_slot: 8) (offset: 0) (type: struct Oracle.Observation[65535]) (numberOfBytes: 2097120) +src/core/KatanaV3Pool.sol:KatanaV3Pool:token0 (storage_slot: 65543) (offset: 0) (type: address) (numberOfBytes: 20) +src/core/KatanaV3Pool.sol:KatanaV3Pool:token1 (storage_slot: 65544) (offset: 0) (type: address) (numberOfBytes: 20) +src/core/KatanaV3Pool.sol:KatanaV3Pool:maxLiquidityPerTick (storage_slot: 65545) (offset: 0) (type: uint128) (numberOfBytes: 16) +src/core/KatanaV3Pool.sol:KatanaV3Pool:fee (storage_slot: 65545) (offset: 16) (type: uint24) (numberOfBytes: 3) +src/core/KatanaV3Pool.sol:KatanaV3Pool:tickSpacing (storage_slot: 65545) (offset: 19) (type: int24) (numberOfBytes: 3) +src/core/KatanaV3Pool.sol:KatanaV3Pool:_immutablesInitialized (storage_slot: 65545) (offset: 22) (type: bool) (numberOfBytes: 1) \ No newline at end of file diff --git a/logs/storage/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer.log b/logs/storage/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer.log new file mode 100644 index 0000000..431749e --- /dev/null +++ b/logs/storage/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer.log @@ -0,0 +1 @@ +src/core/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer:parameters (storage_slot: 0) (offset: 0) (type: struct KatanaV3PoolDeployer.Parameters) (numberOfBytes: 96) \ No newline at end of file diff --git a/logs/storage/NonfungiblePositionManager.sol:NonfungiblePositionManager.log b/logs/storage/NonfungiblePositionManager.sol:NonfungiblePositionManager.log new file mode 100644 index 0000000..d13b5fc --- /dev/null +++ b/logs/storage/NonfungiblePositionManager.sol:NonfungiblePositionManager.log @@ -0,0 +1,16 @@ +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_supportedInterfaces (storage_slot: 0) (offset: 0) (type: mapping(bytes4 => bool)) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_holderTokens (storage_slot: 1) (offset: 0) (type: mapping(address => struct EnumerableSet.UintSet)) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_tokenOwners (storage_slot: 2) (offset: 0) (type: struct EnumerableMap.UintToAddressMap) (numberOfBytes: 64) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_tokenApprovals (storage_slot: 4) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_operatorApprovals (storage_slot: 5) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_name (storage_slot: 6) (offset: 0) (type: string) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_symbol (storage_slot: 7) (offset: 0) (type: string) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_tokenURIs (storage_slot: 8) (offset: 0) (type: mapping(uint256 => string)) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_baseURI (storage_slot: 9) (offset: 0) (type: string) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_poolIds (storage_slot: 10) (offset: 0) (type: mapping(address => uint80)) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_poolIdToPoolKey (storage_slot: 11) (offset: 0) (type: mapping(uint80 => struct PoolAddress.PoolKey)) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_positions (storage_slot: 12) (offset: 0) (type: mapping(uint256 => struct NonfungiblePositionManager.Position)) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_collectedFees (storage_slot: 13) (offset: 0) (type: mapping(uint256 => struct NonfungiblePositionManager.CollectedFees)) (numberOfBytes: 32) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_nextId (storage_slot: 14) (offset: 0) (type: uint176) (numberOfBytes: 22) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_nextPoolId (storage_slot: 14) (offset: 22) (type: uint80) (numberOfBytes: 10) +src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_initialized (storage_slot: 15) (offset: 0) (type: bool) (numberOfBytes: 1) \ No newline at end of file From 165e5cb7eee6b68a20e7caf3baafcb1c8b283e54 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Mon, 19 Aug 2024 15:49:50 +0700 Subject: [PATCH 03/21] fix: record only fees, not burned liquidity in the collectedFees method --- foundry.toml | 2 +- .../interfaces/pool/IKatanaV3PoolActions.sol | 12 +++---- src/periphery/NonfungiblePositionManager.sol | 31 +++++++++++++++---- src/periphery/libraries/PoolAddress.sol | 2 +- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/foundry.toml b/foundry.toml index ccdd836..582c39e 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,7 +7,7 @@ libs = ["lib"] # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options solc = '0.7.6' -optimizer_runs = 800 +optimizer_runs = 250 evm_version = 'istanbul' use_literal_content = true diff --git a/src/core/interfaces/pool/IKatanaV3PoolActions.sol b/src/core/interfaces/pool/IKatanaV3PoolActions.sol index 07c6b2e..69cee9a 100644 --- a/src/core/interfaces/pool/IKatanaV3PoolActions.sol +++ b/src/core/interfaces/pool/IKatanaV3PoolActions.sol @@ -30,12 +30,12 @@ interface IKatanaV3PoolActions { /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity. /// @param recipient The address which should receive the fees collected - /// @param tickLower The lower tick of the position for which to collect fees - /// @param tickUpper The upper tick of the position for which to collect fees - /// @param amount0Requested How much token0 should be withdrawn from the fees owed - /// @param amount1Requested How much token1 should be withdrawn from the fees owed - /// @return amount0 The amount of fees collected in token0 - /// @return amount1 The amount of fees collected in token1 + /// @param tickLower The lower tick of the position for which to collect tokens + /// @param tickUpper The upper tick of the position for which to collect tokens + /// @param amount0Requested How much token0 should be withdrawn from the tokens owed + /// @param amount1Requested How much token1 should be withdrawn from the tokens owed + /// @return amount0 The amount of tokens collected in token0 + /// @return amount1 The amount of tokens collected in token1 function collect( address recipient, int24 tickLower, diff --git a/src/periphery/NonfungiblePositionManager.sol b/src/periphery/NonfungiblePositionManager.sol index 9816e38..2c114ba 100644 --- a/src/periphery/NonfungiblePositionManager.sol +++ b/src/periphery/NonfungiblePositionManager.sol @@ -58,6 +58,13 @@ contract NonfungiblePositionManager is uint128 tokensOwed1; } + // position's burned liquidity is owed in token0/token1 units + struct BurnedLiquidtyOwed { + uint128 token0; + uint128 token1; + } + + // position's collected fees in token0/token1 units struct CollectedFees { uint256 token0; uint256 token1; @@ -72,9 +79,6 @@ contract NonfungiblePositionManager is /// @dev The token ID position data mapping(uint256 => Position) private _positions; - /// @dev How many tokens are collected by the position, as of the last colection - mapping(uint256 => CollectedFees) private _collectedFees; - /// @dev The ID of the next token that will be minted. Skips 0 uint176 private _nextId = 1; /// @dev The ID of the next pool that is used for the first time. Skips 0 @@ -83,6 +87,12 @@ contract NonfungiblePositionManager is /// @dev The address of the token descriptor contract, which handles generating token URIs for position tokens address private immutable _tokenDescriptor; + /// @dev How many tokens from burning liquidity are owed to the position + mapping(uint256 => BurnedLiquidtyOwed) private _burnedLiquidityOwed; + + /// @dev How many tokens are collected by the position, as of the last colection + mapping(uint256 => CollectedFees) private _collectedFees; + /// @dev Whether this contract has been initialized bool private _initialized; @@ -311,6 +321,10 @@ contract NonfungiblePositionManager is require(amount0 >= params.amount0Min && amount1 >= params.amount1Min, "Price slippage check"); + BurnedLiquidtyOwed storage burnedLiquidityOwed = _burnedLiquidityOwed[params.tokenId]; + burnedLiquidityOwed.token0 += uint128(amount0); + burnedLiquidityOwed.token1 += uint128(amount1); + bytes32 positionKey = PositionKey.compute(address(this), position.tickLower, position.tickUpper); // this is now updated to the current transaction (, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128,,) = pool.positions(positionKey); @@ -344,7 +358,9 @@ contract NonfungiblePositionManager is isAuthorizedForToken(params.tokenId) returns (uint256 amount0, uint256 amount1) { - require(params.amount0Max > 0 || params.amount1Max > 0); + require( + params.amount0Max == type(uint128).max && params.amount1Max == type(uint128).max, "Must collect all tokens owed" + ); // allow collecting to the nft position manager address with address 0 address recipient = params.recipient == address(0) ? address(this) : params.recipient; @@ -387,8 +403,11 @@ contract NonfungiblePositionManager is (amount0, amount1) = pool.collect(recipient, position.tickLower, position.tickUpper, amount0Collect, amount1Collect); CollectedFees storage fees = _collectedFees[params.tokenId]; - fees.token0 += amount0; - fees.token1 += amount1; + BurnedLiquidtyOwed storage burnedLiquidityOwed = _burnedLiquidityOwed[params.tokenId]; + // we record only the fees collected, not wholly the tokens owed + fees.token0 += amount0 - burnedLiquidityOwed.token0; + fees.token1 += amount1 - burnedLiquidityOwed.token1; + (burnedLiquidityOwed.token0, burnedLiquidityOwed.token1) = (0, 0); // sometimes there will be a few less wei than expected due to rounding down in core, but we just subtract the full amount expected // instead of the actual amount so we can burn the token diff --git a/src/periphery/libraries/PoolAddress.sol b/src/periphery/libraries/PoolAddress.sol index 8597d79..2152476 100644 --- a/src/periphery/libraries/PoolAddress.sol +++ b/src/periphery/libraries/PoolAddress.sol @@ -4,7 +4,7 @@ pragma solidity >=0.5.0; /// @title Provides functions for deriving a pool address from the factory, tokens, and the fee library PoolAddress { bytes32 internal constant POOL_PROXY_INIT_CODE_HASH = - 0xdb6dc063a9c77abbc8b5d31a246baa926088cdb7892d44b1b09f921b83870df1; + 0xbdb54666e014e207a2a77148a9e5d7a2216bb84841ff9457ddb3505a58fad1ae; /// @notice The identifying key of the pool struct PoolKey { From fca3e103116c168c5afbfbda6252521bcfbcee61 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Mon, 19 Aug 2024 15:50:17 +0700 Subject: [PATCH 04/21] chore: storage layout --- logs/contract-code-sizes.log | 32 +++++++++---------- .../storage/ERC721Permit.sol:ERC721Permit.log | 9 ------ .../KatanaV3Factory.sol:KatanaV3Factory.log | 8 ----- .../storage/KatanaV3Pool.sol:KatanaV3Pool.log | 15 --------- ...3PoolDeployer.sol:KatanaV3PoolDeployer.log | 1 - ...Manager.sol:NonfungiblePositionManager.log | 16 ---------- 6 files changed, 16 insertions(+), 65 deletions(-) delete mode 100644 logs/storage/ERC721Permit.sol:ERC721Permit.log delete mode 100644 logs/storage/KatanaV3Factory.sol:KatanaV3Factory.log delete mode 100644 logs/storage/KatanaV3Pool.sol:KatanaV3Pool.log delete mode 100644 logs/storage/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer.log delete mode 100644 logs/storage/NonfungiblePositionManager.sol:NonfungiblePositionManager.log diff --git a/logs/contract-code-sizes.log b/logs/contract-code-sizes.log index 200c839..16977c8 100644 --- a/logs/contract-code-sizes.log +++ b/logs/contract-code-sizes.log @@ -4,22 +4,22 @@ | AddressStringUtil | 86 | 24,490 | | AuthorizationLib | 86 | 24,490 | | Base64 | 86 | 24,490 | -| BeaconProxy | 785 | 23,791 | +| BeaconProxy | 759 | 23,817 | | BitMath | 86 | 24,490 | | BytesLib | 86 | 24,490 | | CallbackValidation | 86 | 24,490 | | ChainId | 86 | 24,490 | | ERC20 | 2,578 | 21,998 | | ERC20Mock | 3,518 | 21,058 | -| ERC721 | 6,650 | 17,926 | +| ERC721 | 6,557 | 18,019 | | EnumerableMap | 86 | 24,490 | | EnumerableSet | 86 | 24,490 | | FixedPoint128 | 86 | 24,490 | | FixedPoint96 | 86 | 24,490 | | FullMath | 86 | 24,490 | | HexStrings | 86 | 24,490 | -| KatanaGovernanceMock | 2,346 | 22,230 | -| KatanaInterfaceMulticall | 1,334 | 23,242 | +| KatanaGovernanceMock | 2,310 | 22,266 | +| KatanaInterfaceMulticall | 1,295 | 23,281 | | KatanaV2Library | 86 | 24,490 | | KatanaV2LibraryTestnet | 86 | 24,490 | | KatanaV3Factory | 2,945 | 21,631 | @@ -31,23 +31,23 @@ | LiquidityAmounts | 86 | 24,490 | | LiquidityMath | 86 | 24,490 | | LowGasSafeMath | 86 | 24,490 | -| MixedRouteQuoterV1 | 7,328 | 17,248 | -| MixedRouteQuoterV1Testnet | 7,328 | 17,248 | -| NFTDescriptor | 23,833 | 743 | +| MixedRouteQuoterV1 | 7,182 | 17,394 | +| MixedRouteQuoterV1Testnet | 7,182 | 17,394 | +| NFTDescriptor | 23,372 | 1,204 | | NFTSVG | 86 | 24,490 | -| NonfungiblePositionManager | 24,381 | 195 | -| NonfungibleTokenPositionDescriptor | 5,219 | 19,357 | +| NonfungiblePositionManager | 24,361 | 215 | +| NonfungibleTokenPositionDescriptor | 5,158 | 19,418 | | Oracle | 86 | 24,490 | | OracleLibrary | 86 | 24,490 | -| PairFlash | 5,510 | 19,066 | +| PairFlash | 5,428 | 19,148 | | Path | 86 | 24,490 | | PoolAddress | 86 | 24,490 | | PoolTicksCounter | 86 | 24,490 | | Position | 86 | 24,490 | | PositionKey | 86 | 24,490 | | PositionValue | 86 | 24,490 | -| Quoter | 3,944 | 20,632 | -| QuoterV2 | 7,103 | 17,473 | +| Quoter | 3,822 | 20,754 | +| QuoterV2 | 6,981 | 17,595 | | SafeCast | 86 | 24,490 | | SafeERC20Namer | 86 | 24,490 | | SafeMath | 86 | 24,490 | @@ -56,16 +56,16 @@ | SqrtPriceMathPartial | 86 | 24,490 | | Strings | 86 | 24,490 | | SwapMath | 86 | 24,490 | -| SwapRouter | 10,213 | 14,363 | +| SwapRouter | 9,945 | 14,631 | | Tick | 86 | 24,490 | | TickBitmap | 86 | 24,490 | -| TickLens | 1,349 | 23,227 | +| TickLens | 1,322 | 23,254 | | TickMath | 86 | 24,490 | | TokenRatioSortOrder | 86 | 24,490 | | TransferHelper | 86 | 24,490 | -| TransparentUpgradeableProxy | 2,107 | 22,469 | +| TransparentUpgradeableProxy | 2,091 | 22,485 | | UnsafeMath | 86 | 24,490 | -| UpgradeableBeacon | 1,208 | 23,368 | +| UpgradeableBeacon | 1,153 | 23,423 | | UpgradeableProxy | 738 | 23,838 | | V3Migrator | 6,084 | 18,492 | diff --git a/logs/storage/ERC721Permit.sol:ERC721Permit.log b/logs/storage/ERC721Permit.sol:ERC721Permit.log deleted file mode 100644 index 73b1361..0000000 --- a/logs/storage/ERC721Permit.sol:ERC721Permit.log +++ /dev/null @@ -1,9 +0,0 @@ -src/periphery/base/ERC721Permit.sol:ERC721Permit:_supportedInterfaces (storage_slot: 0) (offset: 0) (type: mapping(bytes4 => bool)) (numberOfBytes: 32) -src/periphery/base/ERC721Permit.sol:ERC721Permit:_holderTokens (storage_slot: 1) (offset: 0) (type: mapping(address => struct EnumerableSet.UintSet)) (numberOfBytes: 32) -src/periphery/base/ERC721Permit.sol:ERC721Permit:_tokenOwners (storage_slot: 2) (offset: 0) (type: struct EnumerableMap.UintToAddressMap) (numberOfBytes: 64) -src/periphery/base/ERC721Permit.sol:ERC721Permit:_tokenApprovals (storage_slot: 4) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) -src/periphery/base/ERC721Permit.sol:ERC721Permit:_operatorApprovals (storage_slot: 5) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) -src/periphery/base/ERC721Permit.sol:ERC721Permit:_name (storage_slot: 6) (offset: 0) (type: string) (numberOfBytes: 32) -src/periphery/base/ERC721Permit.sol:ERC721Permit:_symbol (storage_slot: 7) (offset: 0) (type: string) (numberOfBytes: 32) -src/periphery/base/ERC721Permit.sol:ERC721Permit:_tokenURIs (storage_slot: 8) (offset: 0) (type: mapping(uint256 => string)) (numberOfBytes: 32) -src/periphery/base/ERC721Permit.sol:ERC721Permit:_baseURI (storage_slot: 9) (offset: 0) (type: string) (numberOfBytes: 32) \ No newline at end of file diff --git a/logs/storage/KatanaV3Factory.sol:KatanaV3Factory.log b/logs/storage/KatanaV3Factory.sol:KatanaV3Factory.log deleted file mode 100644 index ee8d623..0000000 --- a/logs/storage/KatanaV3Factory.sol:KatanaV3Factory.log +++ /dev/null @@ -1,8 +0,0 @@ -src/core/KatanaV3Factory.sol:KatanaV3Factory:parameters (storage_slot: 0) (offset: 0) (type: struct KatanaV3PoolDeployer.Parameters) (numberOfBytes: 96) -src/core/KatanaV3Factory.sol:KatanaV3Factory:owner (storage_slot: 3) (offset: 0) (type: address) (numberOfBytes: 20) -src/core/KatanaV3Factory.sol:KatanaV3Factory:treasury (storage_slot: 4) (offset: 0) (type: address) (numberOfBytes: 20) -src/core/KatanaV3Factory.sol:KatanaV3Factory:flashLoanEnabled (storage_slot: 4) (offset: 20) (type: bool) (numberOfBytes: 1) -src/core/KatanaV3Factory.sol:KatanaV3Factory:_initialized (storage_slot: 4) (offset: 21) (type: bool) (numberOfBytes: 1) -src/core/KatanaV3Factory.sol:KatanaV3Factory:feeAmountTickSpacing (storage_slot: 5) (offset: 0) (type: mapping(uint24 => int24)) (numberOfBytes: 32) -src/core/KatanaV3Factory.sol:KatanaV3Factory:feeAmountProtocol (storage_slot: 6) (offset: 0) (type: mapping(uint24 => uint16)) (numberOfBytes: 32) -src/core/KatanaV3Factory.sol:KatanaV3Factory:getPool (storage_slot: 7) (offset: 0) (type: mapping(address => mapping(address => mapping(uint24 => address)))) (numberOfBytes: 32) \ No newline at end of file diff --git a/logs/storage/KatanaV3Pool.sol:KatanaV3Pool.log b/logs/storage/KatanaV3Pool.sol:KatanaV3Pool.log deleted file mode 100644 index bdf1d11..0000000 --- a/logs/storage/KatanaV3Pool.sol:KatanaV3Pool.log +++ /dev/null @@ -1,15 +0,0 @@ -src/core/KatanaV3Pool.sol:KatanaV3Pool:slot0 (storage_slot: 0) (offset: 0) (type: struct KatanaV3Pool.Slot0) (numberOfBytes: 32) -src/core/KatanaV3Pool.sol:KatanaV3Pool:feeGrowthGlobal0X128 (storage_slot: 1) (offset: 0) (type: uint256) (numberOfBytes: 32) -src/core/KatanaV3Pool.sol:KatanaV3Pool:feeGrowthGlobal1X128 (storage_slot: 2) (offset: 0) (type: uint256) (numberOfBytes: 32) -src/core/KatanaV3Pool.sol:KatanaV3Pool:protocolFees (storage_slot: 3) (offset: 0) (type: struct KatanaV3Pool.ProtocolFees) (numberOfBytes: 32) -src/core/KatanaV3Pool.sol:KatanaV3Pool:liquidity (storage_slot: 4) (offset: 0) (type: uint128) (numberOfBytes: 16) -src/core/KatanaV3Pool.sol:KatanaV3Pool:ticks (storage_slot: 5) (offset: 0) (type: mapping(int24 => struct Tick.Info)) (numberOfBytes: 32) -src/core/KatanaV3Pool.sol:KatanaV3Pool:tickBitmap (storage_slot: 6) (offset: 0) (type: mapping(int16 => uint256)) (numberOfBytes: 32) -src/core/KatanaV3Pool.sol:KatanaV3Pool:positions (storage_slot: 7) (offset: 0) (type: mapping(bytes32 => struct Position.Info)) (numberOfBytes: 32) -src/core/KatanaV3Pool.sol:KatanaV3Pool:observations (storage_slot: 8) (offset: 0) (type: struct Oracle.Observation[65535]) (numberOfBytes: 2097120) -src/core/KatanaV3Pool.sol:KatanaV3Pool:token0 (storage_slot: 65543) (offset: 0) (type: address) (numberOfBytes: 20) -src/core/KatanaV3Pool.sol:KatanaV3Pool:token1 (storage_slot: 65544) (offset: 0) (type: address) (numberOfBytes: 20) -src/core/KatanaV3Pool.sol:KatanaV3Pool:maxLiquidityPerTick (storage_slot: 65545) (offset: 0) (type: uint128) (numberOfBytes: 16) -src/core/KatanaV3Pool.sol:KatanaV3Pool:fee (storage_slot: 65545) (offset: 16) (type: uint24) (numberOfBytes: 3) -src/core/KatanaV3Pool.sol:KatanaV3Pool:tickSpacing (storage_slot: 65545) (offset: 19) (type: int24) (numberOfBytes: 3) -src/core/KatanaV3Pool.sol:KatanaV3Pool:_immutablesInitialized (storage_slot: 65545) (offset: 22) (type: bool) (numberOfBytes: 1) \ No newline at end of file diff --git a/logs/storage/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer.log b/logs/storage/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer.log deleted file mode 100644 index 431749e..0000000 --- a/logs/storage/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer.log +++ /dev/null @@ -1 +0,0 @@ -src/core/KatanaV3PoolDeployer.sol:KatanaV3PoolDeployer:parameters (storage_slot: 0) (offset: 0) (type: struct KatanaV3PoolDeployer.Parameters) (numberOfBytes: 96) \ No newline at end of file diff --git a/logs/storage/NonfungiblePositionManager.sol:NonfungiblePositionManager.log b/logs/storage/NonfungiblePositionManager.sol:NonfungiblePositionManager.log deleted file mode 100644 index d13b5fc..0000000 --- a/logs/storage/NonfungiblePositionManager.sol:NonfungiblePositionManager.log +++ /dev/null @@ -1,16 +0,0 @@ -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_supportedInterfaces (storage_slot: 0) (offset: 0) (type: mapping(bytes4 => bool)) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_holderTokens (storage_slot: 1) (offset: 0) (type: mapping(address => struct EnumerableSet.UintSet)) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_tokenOwners (storage_slot: 2) (offset: 0) (type: struct EnumerableMap.UintToAddressMap) (numberOfBytes: 64) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_tokenApprovals (storage_slot: 4) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_operatorApprovals (storage_slot: 5) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_name (storage_slot: 6) (offset: 0) (type: string) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_symbol (storage_slot: 7) (offset: 0) (type: string) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_tokenURIs (storage_slot: 8) (offset: 0) (type: mapping(uint256 => string)) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_baseURI (storage_slot: 9) (offset: 0) (type: string) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_poolIds (storage_slot: 10) (offset: 0) (type: mapping(address => uint80)) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_poolIdToPoolKey (storage_slot: 11) (offset: 0) (type: mapping(uint80 => struct PoolAddress.PoolKey)) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_positions (storage_slot: 12) (offset: 0) (type: mapping(uint256 => struct NonfungiblePositionManager.Position)) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_collectedFees (storage_slot: 13) (offset: 0) (type: mapping(uint256 => struct NonfungiblePositionManager.CollectedFees)) (numberOfBytes: 32) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_nextId (storage_slot: 14) (offset: 0) (type: uint176) (numberOfBytes: 22) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_nextPoolId (storage_slot: 14) (offset: 22) (type: uint80) (numberOfBytes: 10) -src/periphery/NonfungiblePositionManager.sol:NonfungiblePositionManager:_initialized (storage_slot: 15) (offset: 0) (type: bool) (numberOfBytes: 1) \ No newline at end of file From a9196effc33500def61ea9bb969238dc649b9de9 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Tue, 20 Aug 2024 13:58:13 +0700 Subject: [PATCH 05/21] chore: replace remapping by src directory --- remappings.txt | 1 - script/DeployKatanaV3Core.s.sol | 6 +++--- script/DeployKatanaV3Periphery.s.sol | 13 ++++++------ script/local/DeployKatanaV3Local.s.sol | 4 ++-- .../ronin-mainnet/DeployKatanaV3Mainnet.s.sol | 2 +- .../ronin-testnet/DeployKatanaV3Testnet.s.sol | 2 +- src/periphery/NonfungiblePositionManager.sol | 6 +++--- .../NonfungibleTokenPositionDescriptor.sol | 2 +- src/periphery/SwapRouter.sol | 6 +++--- src/periphery/V3Migrator.sol | 2 +- src/periphery/base/LiquidityManagement.sol | 6 +++--- .../base/PeripheryImmutableState.sol | 2 +- .../base/PeripheryPaymentsWithFee.sol | 2 +- src/periphery/base/PoolInitializer.sol | 4 ++-- src/periphery/examples/PairFlash.sol | 4 ++-- src/periphery/interfaces/ISwapRouter.sol | 2 +- src/periphery/lens/MixedRouteQuoterV1.sol | 20 +++++++++---------- .../lens/MixedRouteQuoterV1Testnet.sol | 20 +++++++++---------- src/periphery/lens/Quoter.sol | 8 ++++---- src/periphery/lens/QuoterV2.sol | 10 +++++----- src/periphery/lens/TickLens.sol | 2 +- .../libraries/CallbackValidation.sol | 2 +- src/periphery/libraries/KatanaV2Library.sol | 2 +- .../libraries/KatanaV2LibraryTestnet.sol | 2 +- src/periphery/libraries/LiquidityAmounts.sol | 4 ++-- src/periphery/libraries/NFTDescriptor.sol | 8 ++++---- src/periphery/libraries/NFTSVG.sol | 2 +- src/periphery/libraries/OracleLibrary.sol | 6 +++--- src/periphery/libraries/PoolAddress.sol | 2 +- src/periphery/libraries/PoolTicksCounter.sol | 2 +- src/periphery/libraries/PositionValue.sol | 8 ++++---- .../libraries/SqrtPriceMathPartial.sol | 8 ++++---- test/core/KatanaV3Factory.t.sol | 6 +++--- test/core/KatanaV3Pool.t.sol | 14 ++++++------- test/core/PoolProxyInitCodeHash.t.sol | 4 ++-- 35 files changed, 96 insertions(+), 98 deletions(-) diff --git a/remappings.txt b/remappings.txt index b3eae3c..f53c4c5 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,4 +1,3 @@ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ @uniswap/lib/contracts/=lib/solidity-lib/contracts/ base64-sol/=lib/base64/ -@katana/v3-contracts/=src/ \ No newline at end of file diff --git a/script/DeployKatanaV3Core.s.sol b/script/DeployKatanaV3Core.s.sol index e832391..2b41951 100644 --- a/script/DeployKatanaV3Core.s.sol +++ b/script/DeployKatanaV3Core.s.sol @@ -2,9 +2,9 @@ pragma solidity ^0.7.6; import { Script, console } from "forge-std/Script.sol"; -import { KatanaV3Factory } from "@katana/v3-contracts/core/KatanaV3Factory.sol"; -import { KatanaV3Pool } from "@katana/v3-contracts/core/KatanaV3Pool.sol"; -import { KatanaV3PoolBeacon } from "@katana/v3-contracts/core/KatanaV3PoolBeacon.sol"; +import { KatanaV3Factory } from "src/core/KatanaV3Factory.sol"; +import { KatanaV3Pool } from "src/core/KatanaV3Pool.sol"; +import { KatanaV3PoolBeacon } from "src/core/KatanaV3PoolBeacon.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/TransparentUpgradeableProxy.sol"; abstract contract DeployKatanaV3Core is Script { diff --git a/script/DeployKatanaV3Periphery.s.sol b/script/DeployKatanaV3Periphery.s.sol index f60dd3c..9ffcc92 100644 --- a/script/DeployKatanaV3Periphery.s.sol +++ b/script/DeployKatanaV3Periphery.s.sol @@ -3,13 +3,12 @@ pragma solidity ^0.7.6; import { Script, console } from "forge-std/Script.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/TransparentUpgradeableProxy.sol"; -import { NonfungibleTokenPositionDescriptor } from - "@katana/v3-contracts/periphery/NonfungibleTokenPositionDescriptor.sol"; -import { NonfungiblePositionManager } from "@katana/v3-contracts/periphery/NonfungiblePositionManager.sol"; -import { V3Migrator } from "@katana/v3-contracts/periphery/V3Migrator.sol"; -import { TickLens } from "@katana/v3-contracts/periphery/lens/TickLens.sol"; -import { QuoterV2 } from "@katana/v3-contracts/periphery/lens/QuoterV2.sol"; -import { KatanaInterfaceMulticall } from "@katana/v3-contracts/periphery/lens/KatanaInterfaceMulticall.sol"; +import { NonfungibleTokenPositionDescriptor } from "src/periphery/NonfungibleTokenPositionDescriptor.sol"; +import { NonfungiblePositionManager } from "src/periphery/NonfungiblePositionManager.sol"; +import { V3Migrator } from "src/periphery/V3Migrator.sol"; +import { TickLens } from "src/periphery/lens/TickLens.sol"; +import { QuoterV2 } from "src/periphery/lens/QuoterV2.sol"; +import { KatanaInterfaceMulticall } from "src/periphery/lens/KatanaInterfaceMulticall.sol"; import { DeployKatanaV3Core } from "./DeployKatanaV3Core.s.sol"; abstract contract DeployKatanaV3Periphery is DeployKatanaV3Core { diff --git a/script/local/DeployKatanaV3Local.s.sol b/script/local/DeployKatanaV3Local.s.sol index c35ca5c..5543cb0 100644 --- a/script/local/DeployKatanaV3Local.s.sol +++ b/script/local/DeployKatanaV3Local.s.sol @@ -4,8 +4,8 @@ pragma solidity ^0.7.6; import { Script } from "forge-std/Script.sol"; import { console } from "forge-std/console.sol"; import { DeployKatanaV3Periphery } from "../DeployKatanaV3Periphery.s.sol"; -import { MixedRouteQuoterV1 } from "@katana/v3-contracts/periphery/lens/MixedRouteQuoterV1.sol"; -import { KatanaGovernanceMock } from "@katana/v3-contracts/external/KatanaGovernanceMock.sol"; +import { MixedRouteQuoterV1 } from "src/periphery/lens/MixedRouteQuoterV1.sol"; +import { KatanaGovernanceMock } from "src/external/KatanaGovernanceMock.sol"; import { ERC20Mock } from "@openzeppelin/contracts/mocks/ERC20Mock.sol"; contract DeployKatanaV3Local is DeployKatanaV3Periphery { diff --git a/script/ronin-mainnet/DeployKatanaV3Mainnet.s.sol b/script/ronin-mainnet/DeployKatanaV3Mainnet.s.sol index 5086b60..e07d2e3 100644 --- a/script/ronin-mainnet/DeployKatanaV3Mainnet.s.sol +++ b/script/ronin-mainnet/DeployKatanaV3Mainnet.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.7.6; import { Script } from "forge-std/Script.sol"; import { console } from "forge-std/console.sol"; import { DeployKatanaV3Periphery } from "../DeployKatanaV3Periphery.s.sol"; -import { MixedRouteQuoterV1 } from "@katana/v3-contracts/periphery/lens/MixedRouteQuoterV1.sol"; +import { MixedRouteQuoterV1 } from "src/periphery/lens/MixedRouteQuoterV1.sol"; contract DeployKatanaV3Mainnet is DeployKatanaV3Periphery { address mixedRouteQuoterV1; diff --git a/script/ronin-testnet/DeployKatanaV3Testnet.s.sol b/script/ronin-testnet/DeployKatanaV3Testnet.s.sol index c1abf71..ddc5627 100644 --- a/script/ronin-testnet/DeployKatanaV3Testnet.s.sol +++ b/script/ronin-testnet/DeployKatanaV3Testnet.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.7.6; import { Script } from "forge-std/Script.sol"; import { console } from "forge-std/console.sol"; import { DeployKatanaV3Periphery } from "../DeployKatanaV3Periphery.s.sol"; -import { MixedRouteQuoterV1Testnet } from "@katana/v3-contracts/periphery/lens/MixedRouteQuoterV1Testnet.sol"; +import { MixedRouteQuoterV1Testnet } from "src/periphery/lens/MixedRouteQuoterV1Testnet.sol"; contract DeployKatanaV3Testnet is DeployKatanaV3Periphery { address mixedRouteQuoterV1Testnet; diff --git a/src/periphery/NonfungiblePositionManager.sol b/src/periphery/NonfungiblePositionManager.sol index 2c114ba..ec2d535 100644 --- a/src/periphery/NonfungiblePositionManager.sol +++ b/src/periphery/NonfungiblePositionManager.sol @@ -7,9 +7,9 @@ import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721Metadata.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol"; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; -import "@katana/v3-contracts/core/libraries/FixedPoint128.sol"; -import "@katana/v3-contracts/core/libraries/FullMath.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/libraries/FixedPoint128.sol"; +import "src/core/libraries/FullMath.sol"; import "./interfaces/INonfungiblePositionManager.sol"; import "./interfaces/INonfungibleTokenPositionDescriptor.sol"; diff --git a/src/periphery/NonfungibleTokenPositionDescriptor.sol b/src/periphery/NonfungibleTokenPositionDescriptor.sol index d20b3e4..8e1aa42 100644 --- a/src/periphery/NonfungibleTokenPositionDescriptor.sol +++ b/src/periphery/NonfungibleTokenPositionDescriptor.sol @@ -2,7 +2,7 @@ pragma solidity =0.7.6; pragma abicoder v2; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; import "@uniswap/lib/contracts/libraries/SafeERC20Namer.sol"; import "./libraries/ChainId.sol"; diff --git a/src/periphery/SwapRouter.sol b/src/periphery/SwapRouter.sol index 4d8e4ab..f91fc28 100644 --- a/src/periphery/SwapRouter.sol +++ b/src/periphery/SwapRouter.sol @@ -2,9 +2,9 @@ pragma solidity =0.7.6; pragma abicoder v2; -import "@katana/v3-contracts/core/libraries/SafeCast.sol"; -import "@katana/v3-contracts/core/libraries/TickMath.sol"; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/libraries/SafeCast.sol"; +import "src/core/libraries/TickMath.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; import "./interfaces/ISwapRouter.sol"; import "./base/PeripheryImmutableState.sol"; diff --git a/src/periphery/V3Migrator.sol b/src/periphery/V3Migrator.sol index 96d5569..2ffa3cb 100644 --- a/src/periphery/V3Migrator.sol +++ b/src/periphery/V3Migrator.sol @@ -2,7 +2,7 @@ pragma solidity =0.7.6; pragma abicoder v2; -import "@katana/v3-contracts/core/libraries/LowGasSafeMath.sol"; +import "src/core/libraries/LowGasSafeMath.sol"; import "./interfaces/INonfungiblePositionManager.sol"; diff --git a/src/periphery/base/LiquidityManagement.sol b/src/periphery/base/LiquidityManagement.sol index cb4a0c2..f7a6e48 100644 --- a/src/periphery/base/LiquidityManagement.sol +++ b/src/periphery/base/LiquidityManagement.sol @@ -2,9 +2,9 @@ pragma solidity =0.7.6; pragma abicoder v2; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Factory.sol"; -import "@katana/v3-contracts/core/interfaces/callback/IKatanaV3MintCallback.sol"; -import "@katana/v3-contracts/core/libraries/TickMath.sol"; +import "src/core/interfaces/IKatanaV3Factory.sol"; +import "src/core/interfaces/callback/IKatanaV3MintCallback.sol"; +import "src/core/libraries/TickMath.sol"; import "../libraries/PoolAddress.sol"; import "../libraries/CallbackValidation.sol"; diff --git a/src/periphery/base/PeripheryImmutableState.sol b/src/periphery/base/PeripheryImmutableState.sol index 9c89589..1b62b48 100644 --- a/src/periphery/base/PeripheryImmutableState.sol +++ b/src/periphery/base/PeripheryImmutableState.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity =0.7.6; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Factory.sol"; +import "src/core/interfaces/IKatanaV3Factory.sol"; import "../interfaces/IPeripheryImmutableState.sol"; /// @title Immutable state diff --git a/src/periphery/base/PeripheryPaymentsWithFee.sol b/src/periphery/base/PeripheryPaymentsWithFee.sol index f95cd70..6c4eb01 100644 --- a/src/periphery/base/PeripheryPaymentsWithFee.sol +++ b/src/periphery/base/PeripheryPaymentsWithFee.sol @@ -2,7 +2,7 @@ pragma solidity >=0.7.5; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@katana/v3-contracts/core/libraries/LowGasSafeMath.sol"; +import "src/core/libraries/LowGasSafeMath.sol"; import "./PeripheryPayments.sol"; import "../interfaces/IPeripheryPaymentsWithFee.sol"; diff --git a/src/periphery/base/PoolInitializer.sol b/src/periphery/base/PoolInitializer.sol index 6209efe..3fa64c1 100644 --- a/src/periphery/base/PoolInitializer.sol +++ b/src/periphery/base/PoolInitializer.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity =0.7.6; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Factory.sol"; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/interfaces/IKatanaV3Factory.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; import "./PeripheryImmutableState.sol"; import "../interfaces/IPoolInitializer.sol"; diff --git a/src/periphery/examples/PairFlash.sol b/src/periphery/examples/PairFlash.sol index c377505..647ee31 100644 --- a/src/periphery/examples/PairFlash.sol +++ b/src/periphery/examples/PairFlash.sol @@ -2,8 +2,8 @@ pragma solidity =0.7.6; pragma abicoder v2; -import "@katana/v3-contracts/core/interfaces/callback/IKatanaV3FlashCallback.sol"; -import "@katana/v3-contracts/core/libraries/LowGasSafeMath.sol"; +import "src/core/interfaces/callback/IKatanaV3FlashCallback.sol"; +import "src/core/libraries/LowGasSafeMath.sol"; import "../base/PeripheryPayments.sol"; import "../base/PeripheryImmutableState.sol"; diff --git a/src/periphery/interfaces/ISwapRouter.sol b/src/periphery/interfaces/ISwapRouter.sol index aeeacc3..06dfe15 100644 --- a/src/periphery/interfaces/ISwapRouter.sol +++ b/src/periphery/interfaces/ISwapRouter.sol @@ -2,7 +2,7 @@ pragma solidity >=0.7.5; pragma abicoder v2; -import "@katana/v3-contracts/core/interfaces/callback/IKatanaV3SwapCallback.sol"; +import "src/core/interfaces/callback/IKatanaV3SwapCallback.sol"; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Katana V3 diff --git a/src/periphery/lens/MixedRouteQuoterV1.sol b/src/periphery/lens/MixedRouteQuoterV1.sol index 328246b..7deec85 100644 --- a/src/periphery/lens/MixedRouteQuoterV1.sol +++ b/src/periphery/lens/MixedRouteQuoterV1.sol @@ -2,16 +2,16 @@ pragma solidity =0.7.6; pragma abicoder v2; -import "@katana/v3-contracts/periphery/base/PeripheryImmutableState.sol"; -import "@katana/v3-contracts/core/libraries/SafeCast.sol"; -import "@katana/v3-contracts/core/libraries/TickMath.sol"; -import "@katana/v3-contracts/core/libraries/TickBitmap.sol"; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; -import "@katana/v3-contracts/core/interfaces/callback/IKatanaV3SwapCallback.sol"; -import "@katana/v3-contracts/periphery/libraries/Path.sol"; -import "@katana/v3-contracts/periphery/libraries/PoolAddress.sol"; -import "@katana/v3-contracts/periphery/libraries/CallbackValidation.sol"; - +import "src/core/libraries/SafeCast.sol"; +import "src/core/libraries/TickMath.sol"; +import "src/core/libraries/TickBitmap.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/interfaces/callback/IKatanaV3SwapCallback.sol"; +import "src/periphery/libraries/Path.sol"; +import "src/periphery/libraries/PoolAddress.sol"; +import "src/periphery/libraries/CallbackValidation.sol"; + +import "../base/PeripheryImmutableState.sol"; import "../base/ImmutableState.sol"; import "../interfaces/IMixedRouteQuoterV1.sol"; import "../libraries/PoolTicksCounter.sol"; diff --git a/src/periphery/lens/MixedRouteQuoterV1Testnet.sol b/src/periphery/lens/MixedRouteQuoterV1Testnet.sol index b94159e..becd76d 100644 --- a/src/periphery/lens/MixedRouteQuoterV1Testnet.sol +++ b/src/periphery/lens/MixedRouteQuoterV1Testnet.sol @@ -2,16 +2,16 @@ pragma solidity =0.7.6; pragma abicoder v2; -import "@katana/v3-contracts/periphery/base/PeripheryImmutableState.sol"; -import "@katana/v3-contracts/core/libraries/SafeCast.sol"; -import "@katana/v3-contracts/core/libraries/TickMath.sol"; -import "@katana/v3-contracts/core/libraries/TickBitmap.sol"; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; -import "@katana/v3-contracts/core/interfaces/callback/IKatanaV3SwapCallback.sol"; -import "@katana/v3-contracts/periphery/libraries/Path.sol"; -import "@katana/v3-contracts/periphery/libraries/PoolAddress.sol"; -import "@katana/v3-contracts/periphery/libraries/CallbackValidation.sol"; - +import "src/core/libraries/SafeCast.sol"; +import "src/core/libraries/TickMath.sol"; +import "src/core/libraries/TickBitmap.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/interfaces/callback/IKatanaV3SwapCallback.sol"; +import "src/periphery/libraries/Path.sol"; +import "src/periphery/libraries/PoolAddress.sol"; +import "src/periphery/libraries/CallbackValidation.sol"; + +import "../base/PeripheryImmutableState.sol"; import "../base/ImmutableState.sol"; import "../interfaces/IMixedRouteQuoterV1.sol"; import "../libraries/PoolTicksCounter.sol"; diff --git a/src/periphery/lens/Quoter.sol b/src/periphery/lens/Quoter.sol index 3ff2927..0055f38 100644 --- a/src/periphery/lens/Quoter.sol +++ b/src/periphery/lens/Quoter.sol @@ -2,10 +2,10 @@ pragma solidity =0.7.6; pragma abicoder v2; -import "@katana/v3-contracts/core/libraries/SafeCast.sol"; -import "@katana/v3-contracts/core/libraries/TickMath.sol"; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; -import "@katana/v3-contracts/core/interfaces/callback/IKatanaV3SwapCallback.sol"; +import "src/core/libraries/SafeCast.sol"; +import "src/core/libraries/TickMath.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/interfaces/callback/IKatanaV3SwapCallback.sol"; import "../interfaces/IQuoter.sol"; import "../base/PeripheryImmutableState.sol"; diff --git a/src/periphery/lens/QuoterV2.sol b/src/periphery/lens/QuoterV2.sol index 4f3049b..013832d 100644 --- a/src/periphery/lens/QuoterV2.sol +++ b/src/periphery/lens/QuoterV2.sol @@ -2,11 +2,11 @@ pragma solidity =0.7.6; pragma abicoder v2; -import "@katana/v3-contracts/core/libraries/SafeCast.sol"; -import "@katana/v3-contracts/core/libraries/TickMath.sol"; -import "@katana/v3-contracts/core/libraries/TickBitmap.sol"; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; -import "@katana/v3-contracts/core/interfaces/callback/IKatanaV3SwapCallback.sol"; +import "src/core/libraries/SafeCast.sol"; +import "src/core/libraries/TickMath.sol"; +import "src/core/libraries/TickBitmap.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/interfaces/callback/IKatanaV3SwapCallback.sol"; import "../interfaces/IQuoterV2.sol"; import "../base/PeripheryImmutableState.sol"; diff --git a/src/periphery/lens/TickLens.sol b/src/periphery/lens/TickLens.sol index a95d7af..0602ce0 100644 --- a/src/periphery/lens/TickLens.sol +++ b/src/periphery/lens/TickLens.sol @@ -2,7 +2,7 @@ pragma solidity >=0.5.0; pragma abicoder v2; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; import "../interfaces/ITickLens.sol"; diff --git a/src/periphery/libraries/CallbackValidation.sol b/src/periphery/libraries/CallbackValidation.sol index 001c92e..dda14c5 100644 --- a/src/periphery/libraries/CallbackValidation.sol +++ b/src/periphery/libraries/CallbackValidation.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity =0.7.6; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; import "./PoolAddress.sol"; /// @notice Provides validation for callbacks from Katana V3 Pools diff --git a/src/periphery/libraries/KatanaV2Library.sol b/src/periphery/libraries/KatanaV2Library.sol index e6bb521..9e1c863 100644 --- a/src/periphery/libraries/KatanaV2Library.sol +++ b/src/periphery/libraries/KatanaV2Library.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; -import "@katana/v3-contracts/core/libraries/LowGasSafeMath.sol"; +import "src/core/libraries/LowGasSafeMath.sol"; import "../interfaces/IKatanaV2Pair.sol"; library KatanaV2Library { diff --git a/src/periphery/libraries/KatanaV2LibraryTestnet.sol b/src/periphery/libraries/KatanaV2LibraryTestnet.sol index 8f73262..46a1e9c 100644 --- a/src/periphery/libraries/KatanaV2LibraryTestnet.sol +++ b/src/periphery/libraries/KatanaV2LibraryTestnet.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; -import "@katana/v3-contracts/core/libraries/LowGasSafeMath.sol"; +import "src/core/libraries/LowGasSafeMath.sol"; import "../interfaces/IKatanaV2Pair.sol"; library KatanaV2LibraryTestnet { diff --git a/src/periphery/libraries/LiquidityAmounts.sol b/src/periphery/libraries/LiquidityAmounts.sol index 98e089c..7da4a01 100644 --- a/src/periphery/libraries/LiquidityAmounts.sol +++ b/src/periphery/libraries/LiquidityAmounts.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; -import "@katana/v3-contracts/core/libraries/FullMath.sol"; -import "@katana/v3-contracts/core/libraries/FixedPoint96.sol"; +import "src/core/libraries/FullMath.sol"; +import "src/core/libraries/FixedPoint96.sol"; /// @title Liquidity amount functions /// @notice Provides functions for computing liquidity amounts from token amounts and prices diff --git a/src/periphery/libraries/NFTDescriptor.sol b/src/periphery/libraries/NFTDescriptor.sol index 59a4b38..b5538a6 100644 --- a/src/periphery/libraries/NFTDescriptor.sol +++ b/src/periphery/libraries/NFTDescriptor.sol @@ -2,10 +2,10 @@ pragma solidity >=0.7.0; pragma abicoder v2; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; -import "@katana/v3-contracts/core/libraries/TickMath.sol"; -import "@katana/v3-contracts/core/libraries/BitMath.sol"; -import "@katana/v3-contracts/core/libraries/FullMath.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/libraries/TickMath.sol"; +import "src/core/libraries/BitMath.sol"; +import "src/core/libraries/FullMath.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/math/SignedSafeMath.sol"; diff --git a/src/periphery/libraries/NFTSVG.sol b/src/periphery/libraries/NFTSVG.sol index a9d21c5..c044000 100644 --- a/src/periphery/libraries/NFTSVG.sol +++ b/src/periphery/libraries/NFTSVG.sol @@ -2,7 +2,7 @@ pragma solidity >=0.7.6; import "@openzeppelin/contracts/utils/Strings.sol"; -import "@katana/v3-contracts/core/libraries/BitMath.sol"; +import "src/core/libraries/BitMath.sol"; import "base64-sol/base64.sol"; /// @title NFTSVG diff --git a/src/periphery/libraries/OracleLibrary.sol b/src/periphery/libraries/OracleLibrary.sol index 58bbc24..cdcf8e8 100644 --- a/src/periphery/libraries/OracleLibrary.sol +++ b/src/periphery/libraries/OracleLibrary.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0 <0.8.0; -import "@katana/v3-contracts/core/libraries/FullMath.sol"; -import "@katana/v3-contracts/core/libraries/TickMath.sol"; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/libraries/FullMath.sol"; +import "src/core/libraries/TickMath.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; /// @title Oracle library /// @notice Provides functions to integrate with V3 pool oracle diff --git a/src/periphery/libraries/PoolAddress.sol b/src/periphery/libraries/PoolAddress.sol index 2152476..f439343 100644 --- a/src/periphery/libraries/PoolAddress.sol +++ b/src/periphery/libraries/PoolAddress.sol @@ -4,7 +4,7 @@ pragma solidity >=0.5.0; /// @title Provides functions for deriving a pool address from the factory, tokens, and the fee library PoolAddress { bytes32 internal constant POOL_PROXY_INIT_CODE_HASH = - 0xbdb54666e014e207a2a77148a9e5d7a2216bb84841ff9457ddb3505a58fad1ae; + 0xa1b5e7ab94049a77a9dcd7b20ddad1241d9549a08b0fb1e53cfb5b73c320b483; /// @notice The identifying key of the pool struct PoolKey { diff --git a/src/periphery/libraries/PoolTicksCounter.sol b/src/periphery/libraries/PoolTicksCounter.sol index 2b02f3d..8356b44 100644 --- a/src/periphery/libraries/PoolTicksCounter.sol +++ b/src/periphery/libraries/PoolTicksCounter.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.0; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; library PoolTicksCounter { /// @dev This function counts the number of initialized ticks that would incur a gas cost between tickBefore and tickAfter. diff --git a/src/periphery/libraries/PositionValue.sol b/src/periphery/libraries/PositionValue.sol index ee9dad5..f59a8ef 100644 --- a/src/periphery/libraries/PositionValue.sol +++ b/src/periphery/libraries/PositionValue.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.8 <0.8.0; -import "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; -import "@katana/v3-contracts/core/libraries/FixedPoint128.sol"; -import "@katana/v3-contracts/core/libraries/TickMath.sol"; -import "@katana/v3-contracts/core/libraries/Tick.sol"; +import "src/core/interfaces/IKatanaV3Pool.sol"; +import "src/core/libraries/FixedPoint128.sol"; +import "src/core/libraries/TickMath.sol"; +import "src/core/libraries/Tick.sol"; import "../interfaces/INonfungiblePositionManager.sol"; import "./LiquidityAmounts.sol"; import "./PoolAddress.sol"; diff --git a/src/periphery/libraries/SqrtPriceMathPartial.sol b/src/periphery/libraries/SqrtPriceMathPartial.sol index 72966aa..8ae8d50 100644 --- a/src/periphery/libraries/SqrtPriceMathPartial.sol +++ b/src/periphery/libraries/SqrtPriceMathPartial.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; -import "@katana/v3-contracts/core/libraries/FullMath.sol"; -import "@katana/v3-contracts/core/libraries/UnsafeMath.sol"; -import "@katana/v3-contracts/core/libraries/FixedPoint96.sol"; +import "src/core/libraries/FullMath.sol"; +import "src/core/libraries/UnsafeMath.sol"; +import "src/core/libraries/FixedPoint96.sol"; /// @title Functions based on Q64.96 sqrt price and liquidity -/// @notice Exposes two functions from @katana/v3-contracts/core SqrtPriceMath +/// @notice Exposes two functions from src/core SqrtPriceMath /// that use square root of price as a Q64.96 and liquidity to compute deltas library SqrtPriceMathPartial { /// @notice Gets the amount0 delta between two prices diff --git a/test/core/KatanaV3Factory.t.sol b/test/core/KatanaV3Factory.t.sol index 66ae5e9..52c960c 100644 --- a/test/core/KatanaV3Factory.t.sol +++ b/test/core/KatanaV3Factory.t.sol @@ -4,10 +4,10 @@ pragma abicoder v2; import { Test, console } from "forge-std/Test.sol"; -import { IKatanaV3Pool } from "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; +import { IKatanaV3Pool } from "src/core/interfaces/IKatanaV3Pool.sol"; -import { KatanaV3Factory } from "@katana/v3-contracts/core/KatanaV3Factory.sol"; -import { KatanaGovernanceMock } from "@katana/v3-contracts/external/KatanaGovernanceMock.sol"; +import { KatanaV3Factory } from "src/core/KatanaV3Factory.sol"; +import { KatanaGovernanceMock } from "src/external/KatanaGovernanceMock.sol"; import { DeployKatanaV3Local } from "script/local/DeployKatanaV3Local.s.sol"; diff --git a/test/core/KatanaV3Pool.t.sol b/test/core/KatanaV3Pool.t.sol index 5b2644e..bc15097 100644 --- a/test/core/KatanaV3Pool.t.sol +++ b/test/core/KatanaV3Pool.t.sol @@ -6,16 +6,16 @@ import { Test, console } from "forge-std/Test.sol"; import { ERC20Mock } from "@openzeppelin/contracts/mocks/ERC20Mock.sol"; -import { IKatanaV3Pool } from "@katana/v3-contracts/core/interfaces/IKatanaV3Pool.sol"; -import { INonfungiblePositionManager } from "@katana/v3-contracts/periphery/interfaces/INonfungiblePositionManager.sol"; +import { IKatanaV3Pool } from "src/core/interfaces/IKatanaV3Pool.sol"; +import { INonfungiblePositionManager } from "src/periphery/interfaces/INonfungiblePositionManager.sol"; -import { TickMath } from "@katana/v3-contracts/core/libraries/TickMath.sol"; +import { TickMath } from "src/core/libraries/TickMath.sol"; -import { KatanaV3Pool } from "@katana/v3-contracts/core/KatanaV3Pool.sol"; -import { KatanaV3Factory } from "@katana/v3-contracts/core/KatanaV3Factory.sol"; -import { NonfungiblePositionManager } from "@katana/v3-contracts/periphery/NonfungiblePositionManager.sol"; +import { KatanaV3Pool } from "src/core/KatanaV3Pool.sol"; +import { KatanaV3Factory } from "src/core/KatanaV3Factory.sol"; +import { NonfungiblePositionManager } from "src/periphery/NonfungiblePositionManager.sol"; -import { KatanaGovernanceMock } from "@katana/v3-contracts/external/KatanaGovernanceMock.sol"; +import { KatanaGovernanceMock } from "src/external/KatanaGovernanceMock.sol"; import { DeployKatanaV3Local } from "script/local/DeployKatanaV3Local.s.sol"; diff --git a/test/core/PoolProxyInitCodeHash.t.sol b/test/core/PoolProxyInitCodeHash.t.sol index 3832486..8f1b178 100644 --- a/test/core/PoolProxyInitCodeHash.t.sol +++ b/test/core/PoolProxyInitCodeHash.t.sol @@ -3,8 +3,8 @@ pragma solidity ^0.7.6; pragma abicoder v2; import { Test, console } from "forge-std/Test.sol"; -import { PoolAddress } from "@katana/v3-contracts/periphery/libraries/PoolAddress.sol"; -import { KatanaV3PoolProxy } from "@katana/v3-contracts/core/KatanaV3PoolProxy.sol"; +import { PoolAddress } from "src/periphery/libraries/PoolAddress.sol"; +import { KatanaV3PoolProxy } from "src/core/KatanaV3PoolProxy.sol"; contract PoolProxyInitCodeHashTest is Test { function test_POOL_PROXY_INIT_CODE_HASH() public pure { From b841b153c44e9f30a4971610c2543c4c0a8321ce Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Tue, 27 Aug 2024 14:43:30 +0700 Subject: [PATCH 06/21] chore: resolve comments --- src/core/KatanaV3Factory.sol | 28 +++++++++++++--------- src/external/KatanaGovernanceMock.sol | 8 +++---- src/periphery/V3Migrator.sol | 2 +- src/periphery/interfaces/IKatanaV2Pair.sol | 1 + 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/core/KatanaV3Factory.sol b/src/core/KatanaV3Factory.sol index f940634..40f5888 100644 --- a/src/core/KatanaV3Factory.sol +++ b/src/core/KatanaV3Factory.sol @@ -35,6 +35,15 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { _initialized = true; } + modifier onlyOwner() { + _checkOwner(); + _; + } + + function _checkOwner() internal view virtual { + require(owner == msg.sender, "KatanaV3Factory: FORBIDDEN"); + } + function initialize(address owner_, address treasury_) external { require(!_initialized); @@ -77,34 +86,31 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { } /// @inheritdoc IKatanaV3Factory - function setOwner(address _owner) external override { - require(msg.sender == owner); + function setOwner(address _owner) external override onlyOwner { emit OwnerChanged(owner, _owner); owner = _owner; } - function setTreasury(address _treasury) external override { - require(msg.sender == owner); + function setTreasury(address _treasury) external override onlyOwner { + require(_treasury != address(0), "KatanaV3Factory: INVALID_TREASURY"); emit TreasuryChanged(treasury, _treasury); treasury = _treasury; } - function toggleFlashLoanPermission() external override { - require(msg.sender == owner); + function toggleFlashLoanPermission() external override onlyOwner { flashLoanEnabled = !flashLoanEnabled; emit FlashLoanPermissionUpdated(flashLoanEnabled); } /// @inheritdoc IKatanaV3Factory - function enableFeeAmount(uint24 fee, int24 tickSpacing, uint16 feeProtocol) public override { - require(msg.sender == owner); - require(fee < 1000000); + function enableFeeAmount(uint24 fee, int24 tickSpacing, uint16 feeProtocol) public override onlyOwner { + require(fee < 1000000, "KatanaV3Factory: FEE_TOO_HIGH"); // tick spacing is capped at 16384 to prevent the situation where tickSpacing is so large that // TickBitmap#nextInitializedTickWithinOneWord overflows int24 container from a valid tick // 16384 ticks represents a >5x price change with ticks of 1 bips - require(tickSpacing > 0 && tickSpacing < 16384); + require(tickSpacing > 0 && tickSpacing < 16384, "KatanaV3Factory: INVALID_TICK_SPACING"); require((feeProtocol & 255) < (feeProtocol >> 8)); - require(feeAmountTickSpacing[fee] == 0); + require(feeAmountTickSpacing[fee] == 0, "KatanaV3Factory: FEE_AMOUNT_ALREADY_ENABLED"); _enableFeeAmount(fee, tickSpacing, feeProtocol); } diff --git a/src/external/KatanaGovernanceMock.sol b/src/external/KatanaGovernanceMock.sol index bdecce3..d0e6564 100644 --- a/src/external/KatanaGovernanceMock.sol +++ b/src/external/KatanaGovernanceMock.sol @@ -12,9 +12,9 @@ contract KatanaGovernanceMock is IKatanaGovernance { bool private immutable _defaultPermission; mapping(address => mapping(address => uint256)) private _permission; - constructor(address router, address postionManager, bool defaultPermission) { + constructor(address router, address positionManager, bool defaultPermission) { _router = router; - _positionManager = postionManager; + _positionManager = positionManager; _defaultPermission = defaultPermission; } @@ -37,8 +37,8 @@ contract KatanaGovernanceMock is IKatanaGovernance { _router = router; } - function setPositionManager(address postionManager) external { - _positionManager = postionManager; + function setPositionManager(address positionManager) external { + _positionManager = positionManager; } function getRouter() external view override returns (address) { diff --git a/src/periphery/V3Migrator.sol b/src/periphery/V3Migrator.sol index 2ffa3cb..ab85551 100644 --- a/src/periphery/V3Migrator.sol +++ b/src/periphery/V3Migrator.sol @@ -38,7 +38,7 @@ contract V3Migrator is IV3Migrator, PeripheryImmutableState, Multicall, SelfPerm require(params.percentageToMigrate <= 100, "Percentage too large"); // burn v2 liquidity to this address - IKatanaV2Pair(params.pair).transferFrom(msg.sender, params.pair, params.liquidityToMigrate); + TransferHelper.safeTransferFrom(params.pair, msg.sender, params.pair, params.liquidityToMigrate); (uint256 amount0V2, uint256 amount1V2) = IKatanaV2Pair(params.pair).burn(address(this)); // calculate the amounts to migrate to v3 diff --git a/src/periphery/interfaces/IKatanaV2Pair.sol b/src/periphery/interfaces/IKatanaV2Pair.sol index c1b8b7c..4d83644 100644 --- a/src/periphery/interfaces/IKatanaV2Pair.sol +++ b/src/periphery/interfaces/IKatanaV2Pair.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IKatanaV2Pair { From 4dba1f695bc47616dd0fb8f191e4c45080ce023e Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Tue, 27 Aug 2024 15:10:21 +0700 Subject: [PATCH 07/21] fix: call msg.sender to get beacon when deploy pool proxy for compatible with Uniswap tests --- src/core/KatanaV3Factory.sol | 2 -- src/core/KatanaV3Pool.sol | 3 ++- src/core/KatanaV3PoolProxy.sol | 4 +--- src/periphery/libraries/PoolAddress.sol | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/core/KatanaV3Factory.sol b/src/core/KatanaV3Factory.sol index 40f5888..aeec272 100644 --- a/src/core/KatanaV3Factory.sol +++ b/src/core/KatanaV3Factory.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; -import "@openzeppelin/contracts/proxy/UpgradeableBeacon.sol"; - import "./interfaces/IKatanaV3Factory.sol"; import "./KatanaV3PoolDeployer.sol"; diff --git a/src/core/KatanaV3Pool.sol b/src/core/KatanaV3Pool.sol index 4d1061a..a3ed6d8 100644 --- a/src/core/KatanaV3Pool.sol +++ b/src/core/KatanaV3Pool.sol @@ -131,11 +131,12 @@ contract KatanaV3Pool is IKatanaV3Pool { /// @inheritdoc IKatanaV3PoolImmutablesInitializable function initializeImmutables(address factory_, address token0_, address token1_, uint24 fee_, int24 tickSpacing_) public + virtual override { require(!_immutablesInitialized); - require(factory_ == factory && factory_ == msg.sender, "IF"); + require(factory_ == factory, "IF"); (token0, token1, fee, tickSpacing) = (token0_, token1_, fee_, tickSpacing_); diff --git a/src/core/KatanaV3PoolProxy.sol b/src/core/KatanaV3PoolProxy.sol index f31d230..6e09721 100644 --- a/src/core/KatanaV3PoolProxy.sol +++ b/src/core/KatanaV3PoolProxy.sol @@ -3,8 +3,6 @@ pragma solidity =0.7.6; import "@openzeppelin/contracts/proxy/BeaconProxy.sol"; -import "./interfaces/IKatanaV3PoolDeployer.sol"; -import "./interfaces/IKatanaV3Factory.sol"; import "./interfaces/IKatanaV3PoolDeployer.sol"; import "./interfaces/pool/IKatanaV3PoolImmutablesInitializable.sol"; @@ -17,7 +15,7 @@ contract KatanaV3PoolProxy is BeaconProxy { (address factory, address token0, address token1, uint24 fee, int24 tickSpacing) = IKatanaV3PoolDeployer(msg.sender).parameters(); - beacon = IKatanaV3PoolDeployer(factory).BEACON(); + beacon = IKatanaV3PoolDeployer(msg.sender).BEACON(); data = abi.encodeWithSelector( IKatanaV3PoolImmutablesInitializable.initializeImmutables.selector, factory, token0, token1, fee, tickSpacing ); diff --git a/src/periphery/libraries/PoolAddress.sol b/src/periphery/libraries/PoolAddress.sol index f439343..76b5736 100644 --- a/src/periphery/libraries/PoolAddress.sol +++ b/src/periphery/libraries/PoolAddress.sol @@ -4,7 +4,7 @@ pragma solidity >=0.5.0; /// @title Provides functions for deriving a pool address from the factory, tokens, and the fee library PoolAddress { bytes32 internal constant POOL_PROXY_INIT_CODE_HASH = - 0xa1b5e7ab94049a77a9dcd7b20ddad1241d9549a08b0fb1e53cfb5b73c320b483; + 0x90d38463811f82243daaae5a54acd3ee61bdfb1d1d217b3ddab704257da37936; /// @notice The identifying key of the pool struct PoolKey { From d82d5d2eafb76a1423484ac0303da8068535a3eb Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Wed, 28 Aug 2024 16:42:19 +0700 Subject: [PATCH 08/21] forge install: openzeppelin-contracts v3.4.1-solc-0.7-2 --- lib/openzeppelin-contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 04695ae..1c3d6c9 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 04695aecbd4d17dddfd55de766d10e3805d6f42f +Subproject commit 1c3d6c97f7469721b9c683706c88558d544fc0da From ef1af862e49889a0ac819da6577f60aa07eb1e38 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Thu, 29 Aug 2024 18:26:24 +0700 Subject: [PATCH 09/21] fix: transfer protocol fees at the end of the swap to ensure pools have sufficient balance after the callback --- src/core/KatanaV3Pool.sol | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/KatanaV3Pool.sol b/src/core/KatanaV3Pool.sol index a3ed6d8..816bcd4 100644 --- a/src/core/KatanaV3Pool.sol +++ b/src/core/KatanaV3Pool.sol @@ -69,7 +69,7 @@ contract KatanaV3Pool is IKatanaV3Pool { uint128 token1; } /// @inheritdoc IKatanaV3PoolState - + /// @dev Deprecated. The protocol fees are now transferred to the treasury on every swap. ProtocolFees public override protocolFees; /// @inheritdoc IKatanaV3PoolState @@ -724,10 +724,6 @@ contract KatanaV3Pool is IKatanaV3Pool { // update fee growth global if (zeroForOne) feeGrowthGlobal0X128 = state.feeGrowthGlobalX128; else feeGrowthGlobal1X128 = state.feeGrowthGlobalX128; - // transfer protocol fees to the treasury - if (state.protocolFee > 0) { - TransferHelper.safeTransfer(tokenIn, IKatanaV3Factory(factory).treasury(), state.protocolFee); - } (amount0, amount1) = zeroForOne == exactInput ? (amountSpecified - state.amountSpecifiedRemaining, state.amountCalculated) @@ -748,6 +744,11 @@ contract KatanaV3Pool is IKatanaV3Pool { require(balance1Before.add(uint256(amount1)) <= balance1(), "IIA"); } + // transfer protocol fees to the treasury + if (state.protocolFee > 0) { + TransferHelper.safeTransfer(tokenIn, IKatanaV3Factory(factory).treasury(), state.protocolFee); + } + emit Swap(msg.sender, recipient, amount0, amount1, state.sqrtPriceX96, state.liquidity, state.tick); slot0.unlocked = true; } From 333416fe7d6839ffdc85c82ba058b6473ec831c4 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Fri, 6 Sep 2024 21:53:18 +0700 Subject: [PATCH 10/21] chore: fix typo --- src/core/KatanaV3Pool.sol | 1 + src/periphery/NonfungiblePositionManager.sol | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/KatanaV3Pool.sol b/src/core/KatanaV3Pool.sol index 816bcd4..ff76df6 100644 --- a/src/core/KatanaV3Pool.sol +++ b/src/core/KatanaV3Pool.sol @@ -68,6 +68,7 @@ contract KatanaV3Pool is IKatanaV3Pool { uint128 token0; uint128 token1; } + /// @inheritdoc IKatanaV3PoolState /// @dev Deprecated. The protocol fees are now transferred to the treasury on every swap. ProtocolFees public override protocolFees; diff --git a/src/periphery/NonfungiblePositionManager.sol b/src/periphery/NonfungiblePositionManager.sol index ec2d535..8c1b0b7 100644 --- a/src/periphery/NonfungiblePositionManager.sol +++ b/src/periphery/NonfungiblePositionManager.sol @@ -59,7 +59,7 @@ contract NonfungiblePositionManager is } // position's burned liquidity is owed in token0/token1 units - struct BurnedLiquidtyOwed { + struct BurnedLiquidityOwed { uint128 token0; uint128 token1; } @@ -88,9 +88,9 @@ contract NonfungiblePositionManager is address private immutable _tokenDescriptor; /// @dev How many tokens from burning liquidity are owed to the position - mapping(uint256 => BurnedLiquidtyOwed) private _burnedLiquidityOwed; + mapping(uint256 => BurnedLiquidityOwed) private _burnedLiquidityOwed; - /// @dev How many tokens are collected by the position, as of the last colection + /// @dev How many tokens are collected by the position, as of the last collection mapping(uint256 => CollectedFees) private _collectedFees; /// @dev Whether this contract has been initialized @@ -321,7 +321,7 @@ contract NonfungiblePositionManager is require(amount0 >= params.amount0Min && amount1 >= params.amount1Min, "Price slippage check"); - BurnedLiquidtyOwed storage burnedLiquidityOwed = _burnedLiquidityOwed[params.tokenId]; + BurnedLiquidityOwed storage burnedLiquidityOwed = _burnedLiquidityOwed[params.tokenId]; burnedLiquidityOwed.token0 += uint128(amount0); burnedLiquidityOwed.token1 += uint128(amount1); @@ -403,7 +403,7 @@ contract NonfungiblePositionManager is (amount0, amount1) = pool.collect(recipient, position.tickLower, position.tickUpper, amount0Collect, amount1Collect); CollectedFees storage fees = _collectedFees[params.tokenId]; - BurnedLiquidtyOwed storage burnedLiquidityOwed = _burnedLiquidityOwed[params.tokenId]; + BurnedLiquidityOwed storage burnedLiquidityOwed = _burnedLiquidityOwed[params.tokenId]; // we record only the fees collected, not wholly the tokens owed fees.token0 += amount0 - burnedLiquidityOwed.token0; fees.token1 += amount1 - burnedLiquidityOwed.token1; From f2a69057f04bac0372c3419168ba75fafd0e09eb Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Mon, 16 Sep 2024 11:17:37 +0700 Subject: [PATCH 11/21] feat: use storage variables instead of immutables in logic contracts --- script/DeployKatanaV3Core.s.sol | 10 ++---- src/core/KatanaV3Factory.sol | 22 ++++++------- src/core/KatanaV3Pool.sol | 32 +++++++++---------- src/core/KatanaV3PoolDeployer.sol | 8 ++--- src/core/KatanaV3PoolProxy.sol | 6 ++-- src/core/interfaces/IKatanaV3Pool.sol | 2 -- src/core/interfaces/IKatanaV3PoolDeployer.sol | 3 +- .../pool/IKatanaV3PoolImmutables.sol | 14 ++++++++ .../IKatanaV3PoolImmutablesInitializable.sol | 14 -------- src/external/libraries/AuthorizationLib.sol | 8 ----- src/periphery/NonfungiblePositionManager.sol | 9 +----- src/periphery/libraries/PoolAddress.sol | 2 +- 12 files changed, 51 insertions(+), 79 deletions(-) delete mode 100644 src/core/interfaces/pool/IKatanaV3PoolImmutablesInitializable.sol diff --git a/script/DeployKatanaV3Core.s.sol b/script/DeployKatanaV3Core.s.sol index 2b41951..650410b 100644 --- a/script/DeployKatanaV3Core.s.sol +++ b/script/DeployKatanaV3Core.s.sol @@ -27,21 +27,17 @@ abstract contract DeployKatanaV3Core is Script { function run() public virtual { vm.startBroadcast(); - address predictedFactory = vm.computeCreateAddress(sender, vm.getNonce(sender) + 3); - vm.label(predictedFactory, "PredictedFactory"); - - poolImplementation = address(new KatanaV3Pool(predictedFactory, governance)); + poolImplementation = address(new KatanaV3Pool()); beacon = address(new KatanaV3PoolBeacon(poolImplementation)); - address factoryImplementation = address(new KatanaV3Factory(beacon)); + address factoryImplementation = address(new KatanaV3Factory()); factory = address( new TransparentUpgradeableProxy( factoryImplementation, proxyAdmin, - abi.encodeWithSelector(KatanaV3Factory.initialize.selector, governance, treasury) + abi.encodeWithSelector(KatanaV3Factory.initialize.selector, beacon, governance, treasury) ) ); - require(factory == predictedFactory, "Factory address mismatch"); console.log("KatanaV3Factory deployed:", factory); diff --git a/src/core/KatanaV3Factory.sol b/src/core/KatanaV3Factory.sol index aeec272..fee7719 100644 --- a/src/core/KatanaV3Factory.sol +++ b/src/core/KatanaV3Factory.sol @@ -5,9 +5,7 @@ import "./interfaces/IKatanaV3Factory.sol"; import "./KatanaV3PoolDeployer.sol"; -import "./KatanaV3Pool.sol"; - -import "../external/libraries/AuthorizationLib.sol"; +import "../external/interfaces/IKatanaGovernance.sol"; /// @title Canonical Katana V3 factory /// @notice Deploys Katana V3 pools and manages ownership and control over pool protocol fees @@ -18,8 +16,6 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { address public override treasury; /// @inheritdoc IKatanaV3Factory bool public override flashLoanEnabled; - /// @dev Whether the factory has been initialized - bool private _initialized; /// @inheritdoc IKatanaV3Factory mapping(uint24 => int24) public override feeAmountTickSpacing; @@ -28,9 +24,9 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { /// @inheritdoc IKatanaV3Factory mapping(address => mapping(address => mapping(uint24 => address))) public override getPool; - constructor(address beacon) KatanaV3PoolDeployer(beacon) { + constructor() { // disable initialization - _initialized = true; + beacon = address(1); } modifier onlyOwner() { @@ -42,8 +38,12 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { require(owner == msg.sender, "KatanaV3Factory: FORBIDDEN"); } - function initialize(address owner_, address treasury_) external { - require(!_initialized); + function initialize(address beacon_, address owner_, address treasury_) external { + require(beacon == address(0), "KatanaV3Factory: ALREADY_INITIALIZED"); + + // this beacon is treated as immutable + // so there is no need to emit an event + beacon = beacon_; owner = owner_; emit OwnerChanged(address(0), owner_); @@ -62,13 +62,11 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { // swap fee 1% = 0.85% for LP + 0.15% for protocol // tick spacing of 200, approximately 2.02% between initializable ticks _enableFeeAmount(10000, 200, 15 | (100 << 8)); - - _initialized = true; } /// @inheritdoc IKatanaV3Factory function createPool(address tokenA, address tokenB, uint24 fee) external override returns (address pool) { - AuthorizationLib.checkPositionManager(owner); + require(msg.sender == IKatanaGovernance(owner).getPositionManager(), "KatanaV3Factory: INVALID_POSITION_MANAGER"); require(tokenA != tokenB); (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); diff --git a/src/core/KatanaV3Pool.sol b/src/core/KatanaV3Pool.sol index ff76df6..e52af2f 100644 --- a/src/core/KatanaV3Pool.sol +++ b/src/core/KatanaV3Pool.sol @@ -25,7 +25,7 @@ import "./interfaces/callback/IKatanaV3MintCallback.sol"; import "./interfaces/callback/IKatanaV3SwapCallback.sol"; import "./interfaces/callback/IKatanaV3FlashCallback.sol"; -import "../external/libraries/AuthorizationLib.sol"; +import "../external/interfaces/IKatanaGovernance.sol"; contract KatanaV3Pool is IKatanaV3Pool { using LowGasSafeMath for uint256; @@ -86,9 +86,11 @@ contract KatanaV3Pool is IKatanaV3Pool { Oracle.Observation[65535] public override observations; /// @inheritdoc IKatanaV3PoolImmutables - address public immutable override factory; + address public override factory; /// @inheritdoc IKatanaV3PoolImmutables - address public immutable override governance; + address public override governance; + /// @inheritdoc IKatanaV3PoolImmutables + address public override positionManager; // These below immutable constants are set when deploying the beacon proxy of the pool and // cannot be changed unless upgraded. @@ -103,8 +105,6 @@ contract KatanaV3Pool is IKatanaV3Pool { uint24 public override fee; /// @inheritdoc IKatanaV3PoolImmutables int24 public override tickSpacing; - /// @dev The contract is initialized with the immutable parameters - bool private _immutablesInitialized; /// @dev Mutually exclusive reentrancy protection into the pool to/from a method. This method also prevents entrance /// to a function before the pool is initialized. The reentrancy guard is required throughout the contract because @@ -122,28 +122,26 @@ contract KatanaV3Pool is IKatanaV3Pool { _; } - constructor(address factory_, address governance_) { - factory = factory_; - governance = governance_; + constructor() { // disable immutables initialization - _immutablesInitialized = true; + factory = address(1); } - /// @inheritdoc IKatanaV3PoolImmutablesInitializable + /// @inheritdoc IKatanaV3PoolImmutables function initializeImmutables(address factory_, address token0_, address token1_, uint24 fee_, int24 tickSpacing_) public virtual override { - require(!_immutablesInitialized); + require(factory == address(0), "AII"); - require(factory_ == factory, "IF"); + (factory, token0, token1, fee, tickSpacing) = (factory_, token0_, token1_, fee_, tickSpacing_); - (token0, token1, fee, tickSpacing) = (token0_, token1_, fee_, tickSpacing_); + // cache these immutable addresses for gas savings when swaps, mints, or burns are performed + governance = IKatanaV3Factory(factory_).owner(); + positionManager = IKatanaGovernance(governance).getPositionManager(); maxLiquidityPerTick = Tick.tickSpacingToMaxLiquidityPerTick(tickSpacing_); - - _immutablesInitialized = true; } /// @dev Common checks for valid tick inputs. @@ -427,7 +425,7 @@ contract KatanaV3Pool is IKatanaV3Pool { lock returns (uint256 amount0, uint256 amount1) { - AuthorizationLib.checkPositionManager(governance); + require(msg.sender == positionManager, "IPM"); require(amount > 0); (, int256 amount0Int, int256 amount1Int) = _modifyPosition( @@ -570,7 +568,7 @@ contract KatanaV3Pool is IKatanaV3Pool { ) external override returns (int256 amount0, int256 amount1) { // when quoting, we don't need to check authorization if (tx.origin != address(0)) { - AuthorizationLib.checkRouter(governance); + require(msg.sender == IKatanaGovernance(governance).getRouter(), "IR"); } require(amountSpecified != 0, "AS"); diff --git a/src/core/KatanaV3PoolDeployer.sol b/src/core/KatanaV3PoolDeployer.sol index 0ff15d2..d483be2 100644 --- a/src/core/KatanaV3PoolDeployer.sol +++ b/src/core/KatanaV3PoolDeployer.sol @@ -8,7 +8,7 @@ import "./interfaces/IKatanaV3PoolBeaconImmutables.sol"; abstract contract KatanaV3PoolDeployer is IKatanaV3PoolDeployer { /// @inheritdoc IKatanaV3PoolDeployer - address public immutable override BEACON; + address public override beacon; struct Parameters { address factory; @@ -21,10 +21,6 @@ abstract contract KatanaV3PoolDeployer is IKatanaV3PoolDeployer { /// @inheritdoc IKatanaV3PoolDeployer Parameters public override parameters; - constructor(address beacon) { - BEACON = beacon; - } - /// @dev Deploys a pool with the given parameters by transiently setting the parameters storage slot and then /// clearing it after deploying the pool. /// @param factory The contract address of the Katana V3 factory @@ -37,7 +33,7 @@ abstract contract KatanaV3PoolDeployer is IKatanaV3PoolDeployer { returns (address pool) { parameters = Parameters({ factory: factory, token0: token0, token1: token1, fee: fee, tickSpacing: tickSpacing }); - bytes memory creationCode = IKatanaV3PoolBeaconImmutables(BEACON).POOL_PROXY_INIT_CODE(); + bytes memory creationCode = IKatanaV3PoolBeaconImmutables(beacon).POOL_PROXY_INIT_CODE(); bytes32 salt = keccak256(abi.encode(token0, token1, fee)); pool = Create2.deploy(0, salt, creationCode); delete parameters; diff --git a/src/core/KatanaV3PoolProxy.sol b/src/core/KatanaV3PoolProxy.sol index 6e09721..8e2c2ae 100644 --- a/src/core/KatanaV3PoolProxy.sol +++ b/src/core/KatanaV3PoolProxy.sol @@ -5,7 +5,7 @@ import "@openzeppelin/contracts/proxy/BeaconProxy.sol"; import "./interfaces/IKatanaV3PoolDeployer.sol"; -import "./interfaces/pool/IKatanaV3PoolImmutablesInitializable.sol"; +import "./interfaces/pool/IKatanaV3PoolImmutables.sol"; contract KatanaV3PoolProxy is BeaconProxy { constructor() BeaconProxy(address(0), "") { } @@ -15,9 +15,9 @@ contract KatanaV3PoolProxy is BeaconProxy { (address factory, address token0, address token1, uint24 fee, int24 tickSpacing) = IKatanaV3PoolDeployer(msg.sender).parameters(); - beacon = IKatanaV3PoolDeployer(msg.sender).BEACON(); + beacon = IKatanaV3PoolDeployer(msg.sender).beacon(); data = abi.encodeWithSelector( - IKatanaV3PoolImmutablesInitializable.initializeImmutables.selector, factory, token0, token1, fee, tickSpacing + IKatanaV3PoolImmutables.initializeImmutables.selector, factory, token0, token1, fee, tickSpacing ); super._setBeacon(beacon, data); diff --git a/src/core/interfaces/IKatanaV3Pool.sol b/src/core/interfaces/IKatanaV3Pool.sol index f139b3b..d6a828b 100644 --- a/src/core/interfaces/IKatanaV3Pool.sol +++ b/src/core/interfaces/IKatanaV3Pool.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; -import "./pool/IKatanaV3PoolImmutablesInitializable.sol"; import "./pool/IKatanaV3PoolImmutables.sol"; import "./pool/IKatanaV3PoolState.sol"; import "./pool/IKatanaV3PoolDerivedState.sol"; @@ -14,7 +13,6 @@ import "./pool/IKatanaV3PoolEvents.sol"; /// to the ERC20 specification /// @dev The pool interface is broken up into many smaller pieces interface IKatanaV3Pool is - IKatanaV3PoolImmutablesInitializable, IKatanaV3PoolImmutables, IKatanaV3PoolState, IKatanaV3PoolDerivedState, diff --git a/src/core/interfaces/IKatanaV3PoolDeployer.sol b/src/core/interfaces/IKatanaV3PoolDeployer.sol index e9f21d5..44a53e4 100644 --- a/src/core/interfaces/IKatanaV3PoolDeployer.sol +++ b/src/core/interfaces/IKatanaV3PoolDeployer.sol @@ -7,7 +7,8 @@ pragma solidity >=0.5.0; /// of the pool being constant allowing the CREATE2 address of the pool to be cheaply computed on-chain interface IKatanaV3PoolDeployer { /// @notice Returns the address of the beacon that pool proxies must be deployed with - function BEACON() external view returns (address); + /// @dev This value MUST be immutable after initialization + function beacon() external view returns (address); /// @notice Get the parameters to be used in constructing the pool, set transiently during pool creation. /// @dev Called by the pool constructor to fetch the parameters of the pool diff --git a/src/core/interfaces/pool/IKatanaV3PoolImmutables.sol b/src/core/interfaces/pool/IKatanaV3PoolImmutables.sol index 7d88594..eb31214 100644 --- a/src/core/interfaces/pool/IKatanaV3PoolImmutables.sol +++ b/src/core/interfaces/pool/IKatanaV3PoolImmutables.sol @@ -4,6 +4,16 @@ pragma solidity >=0.5.0; /// @title Pool state that never changes /// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values interface IKatanaV3PoolImmutables { + /// @notice Initializes the pool with immutable-treated parameters + /// @dev This function is only call once during deployment with the pool's immutable parameters + /// @param factory_ The contract that deployed the pool, which must adhere to the IKatanaV3Factory interface + /// @param token0_ The first of the two tokens of the pool, sorted by address + /// @param token1_ The second of the two tokens of the pool, sorted by address + /// @param fee_ The pool's fee in hundredths of a bip, i.e. 1e-6 + /// @param tickSpacing_ The pool tick spacing + function initializeImmutables(address factory_, address token0_, address token1_, uint24 fee_, int24 tickSpacing_) + external; + /// @notice The contract that deployed the pool, which must adhere to the IKatanaV3Factory interface /// @return The contract address function factory() external view returns (address); @@ -12,6 +22,10 @@ interface IKatanaV3PoolImmutables { /// @return The contract address function governance() external view returns (address); + /// @notice The contract that manages the pool's positions + /// @return The contract address + function positionManager() external view returns (address); + /// @notice The first of the two tokens of the pool, sorted by address /// @return The token contract address function token0() external view returns (address); diff --git a/src/core/interfaces/pool/IKatanaV3PoolImmutablesInitializable.sol b/src/core/interfaces/pool/IKatanaV3PoolImmutablesInitializable.sol deleted file mode 100644 index 9edfbef..0000000 --- a/src/core/interfaces/pool/IKatanaV3PoolImmutablesInitializable.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -interface IKatanaV3PoolImmutablesInitializable { - /// @notice Initializes the pool with immutable-treated parameters - /// @dev This function is only call once during deployment with the pool's immutable parameters - /// @param factory The contract that deployed the pool, which must adhere to the IKatanaV3Factory interface - /// @param token0 The first of the two tokens of the pool, sorted by address - /// @param token1 The second of the two tokens of the pool, sorted by address - /// @param fee The pool's fee in hundredths of a bip, i.e. 1e-6 - /// @param tickSpacing The pool tick spacing - function initializeImmutables(address factory, address token0, address token1, uint24 fee, int24 tickSpacing) - external; -} diff --git a/src/external/libraries/AuthorizationLib.sol b/src/external/libraries/AuthorizationLib.sol index df1dec5..ac60d10 100644 --- a/src/external/libraries/AuthorizationLib.sol +++ b/src/external/libraries/AuthorizationLib.sol @@ -4,14 +4,6 @@ pragma solidity >=0.7.6 <0.9.0; import "../interfaces/IKatanaGovernance.sol"; library AuthorizationLib { - function checkRouter(address governance) internal view { - require(msg.sender == IKatanaGovernance(governance).getRouter(), "IR"); - } - - function checkPositionManager(address governance) internal view { - require(msg.sender == IKatanaGovernance(governance).getPositionManager(), "IPM"); - } - function checkPair(address governance, address token0, address token1) internal view { address[] memory tokens = new address[](2); tokens[0] = token0; diff --git a/src/periphery/NonfungiblePositionManager.sol b/src/periphery/NonfungiblePositionManager.sol index 8c1b0b7..10078c3 100644 --- a/src/periphery/NonfungiblePositionManager.sol +++ b/src/periphery/NonfungiblePositionManager.sol @@ -93,25 +93,18 @@ contract NonfungiblePositionManager is /// @dev How many tokens are collected by the position, as of the last collection mapping(uint256 => CollectedFees) private _collectedFees; - /// @dev Whether this contract has been initialized - bool private _initialized; - constructor(address _factory, address _WETH9, address _tokenDescriptor_) ERC721Permit("Katana V3 Positions NFT-V1", "KATANA-V3-POS", "1") PeripheryImmutableState(_factory, _WETH9) { _tokenDescriptor = _tokenDescriptor_; - // disable initialization - _initialized = true; } function initialize() external { - require(!_initialized); + require(_nextId == 0, "Already initialized"); _nextId = 1; _nextPoolId = 1; - - _initialized = true; } /// @inheritdoc IERC165 diff --git a/src/periphery/libraries/PoolAddress.sol b/src/periphery/libraries/PoolAddress.sol index 76b5736..93783ce 100644 --- a/src/periphery/libraries/PoolAddress.sol +++ b/src/periphery/libraries/PoolAddress.sol @@ -4,7 +4,7 @@ pragma solidity >=0.5.0; /// @title Provides functions for deriving a pool address from the factory, tokens, and the fee library PoolAddress { bytes32 internal constant POOL_PROXY_INIT_CODE_HASH = - 0x90d38463811f82243daaae5a54acd3ee61bdfb1d1d217b3ddab704257da37936; + 0xb381dabeb6037396a764deb39e57a4a3f75b641ce3e9944b1e4b18d036e322e1; /// @notice The identifying key of the pool struct PoolKey { From a786f73adfe12349fed817789bb03d71c7e4e62f Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Mon, 16 Sep 2024 11:33:44 +0700 Subject: [PATCH 12/21] feat(KatanaV3Pool): remove setFeeProtocol, collectProtocol functions --- src/core/KatanaV3Pool.sol | 56 ------------------- src/core/interfaces/IKatanaV3Pool.sol | 2 - .../pool/IKatanaV3PoolOwnerActions.sol | 21 ------- .../interfaces/pool/IKatanaV3PoolState.sol | 4 -- test/core/KatanaV3Pool.t.sol | 3 - 5 files changed, 86 deletions(-) delete mode 100644 src/core/interfaces/pool/IKatanaV3PoolOwnerActions.sol diff --git a/src/core/KatanaV3Pool.sol b/src/core/KatanaV3Pool.sol index e52af2f..84441d0 100644 --- a/src/core/KatanaV3Pool.sol +++ b/src/core/KatanaV3Pool.sol @@ -63,16 +63,6 @@ contract KatanaV3Pool is IKatanaV3Pool { /// @inheritdoc IKatanaV3PoolState uint256 public override feeGrowthGlobal1X128; - // accumulated protocol fees in token0/token1 units - struct ProtocolFees { - uint128 token0; - uint128 token1; - } - - /// @inheritdoc IKatanaV3PoolState - /// @dev Deprecated. The protocol fees are now transferred to the treasury on every swap. - ProtocolFees public override protocolFees; - /// @inheritdoc IKatanaV3PoolState uint128 public override liquidity; @@ -116,12 +106,6 @@ contract KatanaV3Pool is IKatanaV3Pool { slot0.unlocked = true; } - /// @dev Prevents calling a function from anyone except the address returned by IKatanaV3Factory#owner() - modifier onlyFactoryOwner() { - require(msg.sender == IKatanaV3Factory(factory).owner()); - _; - } - constructor() { // disable immutables initialization factory = address(1); @@ -801,44 +785,4 @@ contract KatanaV3Pool is IKatanaV3Pool { emit Flash(msg.sender, recipient, amount0, amount1, paid0, paid1); } - - /// @inheritdoc IKatanaV3PoolOwnerActions - function setFeeProtocol(uint8 feeProtocolNumerator, uint8 feeProtocolDenominator) - external - override - lock - onlyFactoryOwner - { - require(feeProtocolNumerator < feeProtocolDenominator); - uint16 feeProtocolOld = slot0.feeProtocol; - slot0.feeProtocol = uint16(feeProtocolNumerator) | (uint16(feeProtocolDenominator) << 8); - emit SetFeeProtocol( - uint8(feeProtocolOld & 255), uint8(feeProtocolOld >> 8), feeProtocolNumerator, feeProtocolDenominator - ); - } - - /// @inheritdoc IKatanaV3PoolOwnerActions - function collectProtocol(address recipient, uint128 amount0Requested, uint128 amount1Requested) - external - override - lock - onlyFactoryOwner - returns (uint128 amount0, uint128 amount1) - { - amount0 = amount0Requested > protocolFees.token0 ? protocolFees.token0 : amount0Requested; - amount1 = amount1Requested > protocolFees.token1 ? protocolFees.token1 : amount1Requested; - - if (amount0 > 0) { - if (amount0 == protocolFees.token0) amount0--; // ensure that the slot is not cleared, for gas savings - protocolFees.token0 -= amount0; - TransferHelper.safeTransfer(token0, recipient, amount0); - } - if (amount1 > 0) { - if (amount1 == protocolFees.token1) amount1--; // ensure that the slot is not cleared, for gas savings - protocolFees.token1 -= amount1; - TransferHelper.safeTransfer(token1, recipient, amount1); - } - - emit CollectProtocol(msg.sender, recipient, amount0, amount1); - } } diff --git a/src/core/interfaces/IKatanaV3Pool.sol b/src/core/interfaces/IKatanaV3Pool.sol index d6a828b..3ad9e2a 100644 --- a/src/core/interfaces/IKatanaV3Pool.sol +++ b/src/core/interfaces/IKatanaV3Pool.sol @@ -5,7 +5,6 @@ import "./pool/IKatanaV3PoolImmutables.sol"; import "./pool/IKatanaV3PoolState.sol"; import "./pool/IKatanaV3PoolDerivedState.sol"; import "./pool/IKatanaV3PoolActions.sol"; -import "./pool/IKatanaV3PoolOwnerActions.sol"; import "./pool/IKatanaV3PoolEvents.sol"; /// @title The interface for a Katana V3 Pool @@ -17,6 +16,5 @@ interface IKatanaV3Pool is IKatanaV3PoolState, IKatanaV3PoolDerivedState, IKatanaV3PoolActions, - IKatanaV3PoolOwnerActions, IKatanaV3PoolEvents { } diff --git a/src/core/interfaces/pool/IKatanaV3PoolOwnerActions.sol b/src/core/interfaces/pool/IKatanaV3PoolOwnerActions.sol deleted file mode 100644 index c96afde..0000000 --- a/src/core/interfaces/pool/IKatanaV3PoolOwnerActions.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title Permissioned pool actions -/// @notice Contains pool methods that may only be called by the factory owner -interface IKatanaV3PoolOwnerActions { - /// @notice Set the protocol fee as a ratio of the swap fees - /// @param feeProtocolNumerator new protocol fee numerator - /// @param feeProtocolDenominator new protocol fee denominator - function setFeeProtocol(uint8 feeProtocolNumerator, uint8 feeProtocolDenominator) external; - - /// @notice Collect the protocol fee accrued to the pool - /// @param recipient The address to which collected protocol fees should be sent - /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1 - /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0 - /// @return amount0 The protocol fee collected in token0 - /// @return amount1 The protocol fee collected in token1 - function collectProtocol(address recipient, uint128 amount0Requested, uint128 amount1Requested) - external - returns (uint128 amount0, uint128 amount1); -} diff --git a/src/core/interfaces/pool/IKatanaV3PoolState.sol b/src/core/interfaces/pool/IKatanaV3PoolState.sol index 46706fa..0219e22 100644 --- a/src/core/interfaces/pool/IKatanaV3PoolState.sol +++ b/src/core/interfaces/pool/IKatanaV3PoolState.sol @@ -38,10 +38,6 @@ interface IKatanaV3PoolState { /// @dev This value can overflow the uint256 function feeGrowthGlobal1X128() external view returns (uint256); - /// @notice The amounts of token0 and token1 that are owed to the protocol - /// @dev Protocol fees will never exceed uint128 max in either token - function protocolFees() external view returns (uint128 token0, uint128 token1); - /// @notice The currently in range liquidity available to the pool /// @dev This value has no relationship to the total liquidity across all ticks function liquidity() external view returns (uint128); diff --git a/test/core/KatanaV3Pool.t.sol b/test/core/KatanaV3Pool.t.sol index bc15097..db7b966 100644 --- a/test/core/KatanaV3Pool.t.sol +++ b/test/core/KatanaV3Pool.t.sol @@ -119,9 +119,6 @@ contract KatanaV3PoolTest is Test { for (uint256 i = 0; i < 3; ++i) { KatanaV3Pool pool = pools[i]; pool.swap(address(this), true, 10_000_000, TickMath.MIN_SQRT_RATIO + 1, ""); - (uint128 protocolFee0, uint128 protocolFee1) = pool.protocolFees(); - assertEq(uint256(protocolFee0), 0); - assertEq(uint256(protocolFee1), 0); console.log(ERC20Mock(token0).balanceOf(treasury), ERC20Mock(token1).balanceOf(treasury)); } } From 84b67dd5ffbdc27347ef53c0cd5857162e7a73c6 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Mon, 16 Sep 2024 13:27:46 +0700 Subject: [PATCH 13/21] feat: split feeProtocol from single variable to 2 variables (numerator & denominator) --- src/core/KatanaV3Factory.sol | 29 ++++++++++++------- src/core/KatanaV3Pool.sol | 25 ++++++++++------ src/core/interfaces/IKatanaV3Factory.sol | 15 ++++++---- .../interfaces/pool/IKatanaV3PoolState.sol | 6 ++-- .../NonfungibleTokenPositionDescriptor.sol | 2 +- src/periphery/base/LiquidityManagement.sol | 2 +- src/periphery/base/PoolInitializer.sol | 2 +- src/periphery/lens/MixedRouteQuoterV1.sol | 4 +-- .../lens/MixedRouteQuoterV1Testnet.sol | 4 +-- src/periphery/lens/QuoterV2.sol | 4 +-- src/periphery/libraries/OracleLibrary.sol | 4 +-- src/periphery/libraries/PositionValue.sol | 2 +- 12 files changed, 60 insertions(+), 39 deletions(-) diff --git a/src/core/KatanaV3Factory.sol b/src/core/KatanaV3Factory.sol index fee7719..0a9a43e 100644 --- a/src/core/KatanaV3Factory.sol +++ b/src/core/KatanaV3Factory.sol @@ -10,6 +10,11 @@ import "../external/interfaces/IKatanaGovernance.sol"; /// @title Canonical Katana V3 factory /// @notice Deploys Katana V3 pools and manages ownership and control over pool protocol fees contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { + struct Fraction { + uint8 numerator; + uint8 denominator; + } + /// @inheritdoc IKatanaV3Factory address public override owner; /// @inheritdoc IKatanaV3Factory @@ -20,7 +25,7 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { /// @inheritdoc IKatanaV3Factory mapping(uint24 => int24) public override feeAmountTickSpacing; /// @inheritdoc IKatanaV3Factory - mapping(uint24 => uint16) public override feeAmountProtocol; + mapping(uint24 => Fraction) public override feeAmountProtocol; /// @inheritdoc IKatanaV3Factory mapping(address => mapping(address => mapping(uint24 => address))) public override getPool; @@ -53,15 +58,15 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { // swap fee 0.01% = 0.005% for LP + 0.005% for protocol // tick spacing of 1, equivalent to 0.01% between initializable ticks - _enableFeeAmount(100, 1, 5 | (10 << 8)); + _enableFeeAmount(100, 1, 5, 10); // swap fee 0.3% = 0.25% for LP + 0.05% for protocol // tick spacing of 60, approximately 0.60% between initializable ticks - _enableFeeAmount(3000, 60, 5 | (30 << 8)); + _enableFeeAmount(3000, 60, 5, 30); // swap fee 1% = 0.85% for LP + 0.15% for protocol // tick spacing of 200, approximately 2.02% between initializable ticks - _enableFeeAmount(10000, 200, 15 | (100 << 8)); + _enableFeeAmount(10000, 200, 15, 100); } /// @inheritdoc IKatanaV3Factory @@ -99,21 +104,25 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { } /// @inheritdoc IKatanaV3Factory - function enableFeeAmount(uint24 fee, int24 tickSpacing, uint16 feeProtocol) public override onlyOwner { + function enableFeeAmount(uint24 fee, int24 tickSpacing, uint8 feeProtocolNum, uint8 feeProtocolDen) + public + override + onlyOwner + { require(fee < 1000000, "KatanaV3Factory: FEE_TOO_HIGH"); // tick spacing is capped at 16384 to prevent the situation where tickSpacing is so large that // TickBitmap#nextInitializedTickWithinOneWord overflows int24 container from a valid tick // 16384 ticks represents a >5x price change with ticks of 1 bips require(tickSpacing > 0 && tickSpacing < 16384, "KatanaV3Factory: INVALID_TICK_SPACING"); - require((feeProtocol & 255) < (feeProtocol >> 8)); + require(feeProtocolNum < feeProtocolDen, "KatanaV3Factory: INVALID_FEE_PROTOCOL"); require(feeAmountTickSpacing[fee] == 0, "KatanaV3Factory: FEE_AMOUNT_ALREADY_ENABLED"); - _enableFeeAmount(fee, tickSpacing, feeProtocol); + _enableFeeAmount(fee, tickSpacing, feeProtocolNum, feeProtocolDen); } - function _enableFeeAmount(uint24 fee, int24 tickSpacing, uint16 feeProtocol) private { + function _enableFeeAmount(uint24 fee, int24 tickSpacing, uint8 feeProtocolNum, uint8 feeProtocolDen) private { feeAmountTickSpacing[fee] = tickSpacing; - feeAmountProtocol[fee] = feeProtocol; - emit FeeAmountEnabled(fee, tickSpacing, feeProtocol); + feeAmountProtocol[fee] = Fraction(feeProtocolNum, feeProtocolDen); + emit FeeAmountEnabled(fee, tickSpacing, feeProtocolNum, feeProtocolDen); } } diff --git a/src/core/KatanaV3Pool.sol b/src/core/KatanaV3Pool.sol index 84441d0..147d353 100644 --- a/src/core/KatanaV3Pool.sol +++ b/src/core/KatanaV3Pool.sol @@ -49,8 +49,10 @@ contract KatanaV3Pool is IKatanaV3Pool { uint16 observationCardinality; // the next maximum number of observations to store, triggered in observations.write uint16 observationCardinalityNext; - // the current protocol fee as a ratio of the swap fee: first byte is numerator, second byte is denominator - uint16 feeProtocol; + // the numerator of the current protocol fee which is a ratio of the swap fee + uint8 feeProtocolNum; + // the denominator of the current protocol fee which is a ratio of the swap fee + uint8 feeProtocolDen; // whether the pool is locked bool unlocked; } @@ -248,13 +250,16 @@ contract KatanaV3Pool is IKatanaV3Pool { (uint16 cardinality, uint16 cardinalityNext) = observations.initialize(_blockTimestamp()); + (uint8 feeProtocolNum, uint8 feeProtocolDen) = IKatanaV3Factory(factory).feeAmountProtocol(fee); + slot0 = Slot0({ sqrtPriceX96: sqrtPriceX96, tick: tick, observationIndex: 0, observationCardinality: cardinality, observationCardinalityNext: cardinalityNext, - feeProtocol: IKatanaV3Factory(factory).feeAmountProtocol(fee), + feeProtocolNum: feeProtocolNum, + feeProtocolDen: feeProtocolDen, unlocked: true }); @@ -492,7 +497,8 @@ contract KatanaV3Pool is IKatanaV3Pool { // the swap fee in hundredths of a bip uint24 fee; // the protocol fee for the input token - uint16 feeProtocol; + uint8 feeProtocolNum; + uint8 feeProtocolDen; // the spacing between usable ticks int24 tickSpacing; // liquidity at the beginning of the swap @@ -573,7 +579,8 @@ contract KatanaV3Pool is IKatanaV3Pool { liquidityStart: liquidity, blockTimestamp: _blockTimestamp(), fee: fee, - feeProtocol: slot0Start.feeProtocol, + feeProtocolNum: slot0Start.feeProtocolNum, + feeProtocolDen: slot0Start.feeProtocolDen, tickSpacing: tickSpacing, secondsPerLiquidityCumulativeX128: 0, tickCumulative: 0, @@ -631,8 +638,8 @@ contract KatanaV3Pool is IKatanaV3Pool { } // if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee - if (cache.feeProtocol > 0) { - uint256 delta = FullMath.mulDiv(step.feeAmount, cache.feeProtocol & 255, cache.feeProtocol >> 8); + if (cache.feeProtocolNum > 0) { + uint256 delta = FullMath.mulDiv(step.feeAmount, cache.feeProtocolNum, cache.feeProtocolDen); step.feeAmount -= delta; state.protocolFee += uint128(delta); } @@ -772,12 +779,12 @@ contract KatanaV3Pool is IKatanaV3Pool { paid1 = balance1After - balance1Before; if (paid0 > 0) { - uint256 fees0 = FullMath.mulDiv(paid0, slot0.feeProtocol & 255, slot0.feeProtocol >> 8); + uint256 fees0 = FullMath.mulDiv(paid0, slot0.feeProtocolNum, slot0.feeProtocolDen); if (fees0 > 0) TransferHelper.safeTransfer(_token0, treasury, fees0); feeGrowthGlobal0X128 += FullMath.mulDiv(paid0 - fees0, FixedPoint128.Q128, _liquidity); } if (paid1 > 0) { - uint256 fees1 = FullMath.mulDiv(paid1, slot0.feeProtocol & 255, slot0.feeProtocol >> 8); + uint256 fees1 = FullMath.mulDiv(paid1, slot0.feeProtocolNum, slot0.feeProtocolDen); if (fees1 > 0) TransferHelper.safeTransfer(_token1, treasury, fees1); feeGrowthGlobal1X128 += FullMath.mulDiv(paid1 - fees1, FixedPoint128.Q128, _liquidity); } diff --git a/src/core/interfaces/IKatanaV3Factory.sol b/src/core/interfaces/IKatanaV3Factory.sol index afd8cf0..e5fbf22 100644 --- a/src/core/interfaces/IKatanaV3Factory.sol +++ b/src/core/interfaces/IKatanaV3Factory.sol @@ -31,8 +31,9 @@ interface IKatanaV3Factory { /// @notice Emitted when a new fee amount is enabled for pool creation via the factory /// @param fee The enabled fee, denominated in hundredths of a bip /// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee - /// @param protocolFee The ratio of the fee amount to be sent to the Ronin treasury. - event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing, uint16 indexed protocolFee); + /// @param protocolFeeNum The numerator of the protocol fee as a ratio of the fee amount that sent to the treasury + /// @param protocolFeeDen The denominator of the protocol fee as a ratio of the fee amount that sent to the treasury + event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing, uint8 protocolFeeNum, uint8 protocolFeeDen); /// @notice Returns the current owner of the factory /// @dev Can be changed by the current owner via setOwner @@ -58,8 +59,9 @@ interface IKatanaV3Factory { /// @notice Returns the default protocol fee ratio for a given fee amount, if enabled, or 0 if not enabled /// @dev This protocol fee can be changed by the factory owner in each pool later /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee - /// @return The protocol fee as a ratio of the fee amount: first byte is numerator, second byte is denominator - function feeAmountProtocol(uint24 fee) external view returns (uint16); + /// return numerator The numerator of the protocol fee as a ratio of the fee amount + /// return denominator The denominator of the protocol fee as a ratio of the fee amount + function feeAmountProtocol(uint24 fee) external view returns (uint8 numerator, uint8 denominator); /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order @@ -97,6 +99,7 @@ interface IKatanaV3Factory { /// @dev Fee amounts may never be removed once enabled /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6) /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount - /// @param feeProtocol The protocol fee as a ratio of the fee amount: first byte is numerator, second byte is denominator - function enableFeeAmount(uint24 fee, int24 tickSpacing, uint16 feeProtocol) external; + /// @param feeProtocolNum The numerator of the protocol fee as a ratio of the fee amount + /// @param feeProtocolDen The denominator of the protocol fee as a ratio of the fee amount + function enableFeeAmount(uint24 fee, int24 tickSpacing, uint8 feeProtocolNum, uint8 feeProtocolDen) external; } diff --git a/src/core/interfaces/pool/IKatanaV3PoolState.sol b/src/core/interfaces/pool/IKatanaV3PoolState.sol index 0219e22..2cdeb38 100644 --- a/src/core/interfaces/pool/IKatanaV3PoolState.sol +++ b/src/core/interfaces/pool/IKatanaV3PoolState.sol @@ -14,7 +14,8 @@ interface IKatanaV3PoolState { /// observationIndex The index of the last oracle observation that was written, /// observationCardinality The current maximum number of observations stored in the pool, /// observationCardinalityNext The next maximum number of observations, to be updated when the observation. - /// feeProtocol The protocol fee as a ratio of the swap fee. + /// feeProtocolNum the numerator of the current protocol fee which is a ratio (fraction < 1) of the swap fee + /// feeProtocolDen the denominator of the current protocol fee which is a ratio (fraction < 1) of the swap fee /// Encoded as a fraction, where first byte (8 bit value) is the numerator and the second byte is the denominator. /// unlocked Whether the pool is currently locked to reentrancy function slot0() @@ -26,7 +27,8 @@ interface IKatanaV3PoolState { uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, - uint16 feeProtocol, + uint8 feeProtocolNum, + uint8 feeProtocolDen, bool unlocked ); diff --git a/src/periphery/NonfungibleTokenPositionDescriptor.sol b/src/periphery/NonfungibleTokenPositionDescriptor.sol index 8e1aa42..d3a0361 100644 --- a/src/periphery/NonfungibleTokenPositionDescriptor.sol +++ b/src/periphery/NonfungibleTokenPositionDescriptor.sol @@ -63,7 +63,7 @@ contract NonfungibleTokenPositionDescriptor is INonfungibleTokenPositionDescript bool _flipRatio = flipRatio(token0, token1, ChainId.get()); address quoteTokenAddress = !_flipRatio ? token1 : token0; address baseTokenAddress = !_flipRatio ? token0 : token1; - (, int24 tick,,,,,) = pool.slot0(); + (, int24 tick,,,,,,) = pool.slot0(); return NFTDescriptor.constructTokenURI( NFTDescriptor.ConstructTokenURIParams({ diff --git a/src/periphery/base/LiquidityManagement.sol b/src/periphery/base/LiquidityManagement.sol index f7a6e48..3fc2dd3 100644 --- a/src/periphery/base/LiquidityManagement.sol +++ b/src/periphery/base/LiquidityManagement.sol @@ -55,7 +55,7 @@ abstract contract LiquidityManagement is IKatanaV3MintCallback, PeripheryImmutab // compute the liquidity amount { - (uint160 sqrtPriceX96,,,,,,) = pool.slot0(); + (uint160 sqrtPriceX96,,,,,,,) = pool.slot0(); uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(params.tickLower); uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(params.tickUpper); diff --git a/src/periphery/base/PoolInitializer.sol b/src/periphery/base/PoolInitializer.sol index 3fa64c1..8f76cd4 100644 --- a/src/periphery/base/PoolInitializer.sol +++ b/src/periphery/base/PoolInitializer.sol @@ -27,7 +27,7 @@ abstract contract PoolInitializer is IPoolInitializer, PeripheryImmutableState { pool = IKatanaV3Factory(factory).createPool(token0, token1, fee); IKatanaV3Pool(pool).initialize(sqrtPriceX96); } else { - (uint160 sqrtPriceX96Existing,,,,,,) = IKatanaV3Pool(pool).slot0(); + (uint160 sqrtPriceX96Existing,,,,,,,) = IKatanaV3Pool(pool).slot0(); if (sqrtPriceX96Existing == 0) { IKatanaV3Pool(pool).initialize(sqrtPriceX96); } diff --git a/src/periphery/lens/MixedRouteQuoterV1.sol b/src/periphery/lens/MixedRouteQuoterV1.sol index 7deec85..995b90b 100644 --- a/src/periphery/lens/MixedRouteQuoterV1.sol +++ b/src/periphery/lens/MixedRouteQuoterV1.sol @@ -60,7 +60,7 @@ contract MixedRouteQuoterV1 is IMixedRouteQuoterV1, IKatanaV3SwapCallback, Perip amount0Delta > 0 ? (tokenIn < tokenOut, uint256(-amount1Delta)) : (tokenOut < tokenIn, uint256(-amount0Delta)); IKatanaV3Pool pool = getPool(tokenIn, tokenOut, fee); - (uint160 v3SqrtPriceX96After, int24 tickAfter,,,,,) = pool.slot0(); + (uint160 v3SqrtPriceX96After, int24 tickAfter,,,,,,) = pool.slot0(); if (isExactInput) { assembly { @@ -99,7 +99,7 @@ contract MixedRouteQuoterV1 is IMixedRouteQuoterV1, IKatanaV3SwapCallback, Perip { int24 tickBefore; int24 tickAfter; - (, tickBefore,,,,,) = pool.slot0(); + (, tickBefore,,,,,,) = pool.slot0(); (amount, sqrtPriceX96After, tickAfter) = parseRevertReason(reason); initializedTicksCrossed = pool.countInitializedTicksCrossed(tickBefore, tickAfter); diff --git a/src/periphery/lens/MixedRouteQuoterV1Testnet.sol b/src/periphery/lens/MixedRouteQuoterV1Testnet.sol index becd76d..f9e29f2 100644 --- a/src/periphery/lens/MixedRouteQuoterV1Testnet.sol +++ b/src/periphery/lens/MixedRouteQuoterV1Testnet.sol @@ -60,7 +60,7 @@ contract MixedRouteQuoterV1Testnet is IMixedRouteQuoterV1, IKatanaV3SwapCallback amount0Delta > 0 ? (tokenIn < tokenOut, uint256(-amount1Delta)) : (tokenOut < tokenIn, uint256(-amount0Delta)); IKatanaV3Pool pool = getPool(tokenIn, tokenOut, fee); - (uint160 v3SqrtPriceX96After, int24 tickAfter,,,,,) = pool.slot0(); + (uint160 v3SqrtPriceX96After, int24 tickAfter,,,,,,) = pool.slot0(); if (isExactInput) { assembly { @@ -99,7 +99,7 @@ contract MixedRouteQuoterV1Testnet is IMixedRouteQuoterV1, IKatanaV3SwapCallback { int24 tickBefore; int24 tickAfter; - (, tickBefore,,,,,) = pool.slot0(); + (, tickBefore,,,,,,) = pool.slot0(); (amount, sqrtPriceX96After, tickAfter) = parseRevertReason(reason); initializedTicksCrossed = pool.countInitializedTicksCrossed(tickBefore, tickAfter); diff --git a/src/periphery/lens/QuoterV2.sol b/src/periphery/lens/QuoterV2.sol index 013832d..98537a5 100644 --- a/src/periphery/lens/QuoterV2.sol +++ b/src/periphery/lens/QuoterV2.sol @@ -44,7 +44,7 @@ contract QuoterV2 is IQuoterV2, IKatanaV3SwapCallback, PeripheryImmutableState { : (tokenOut < tokenIn, uint256(amount1Delta), uint256(-amount0Delta)); IKatanaV3Pool pool = getPool(tokenIn, tokenOut, fee); - (uint160 sqrtPriceX96After, int24 tickAfter,,,,,) = pool.slot0(); + (uint160 sqrtPriceX96After, int24 tickAfter,,,,,,) = pool.slot0(); if (isExactInput) { assembly { @@ -90,7 +90,7 @@ contract QuoterV2 is IQuoterV2, IKatanaV3SwapCallback, PeripheryImmutableState { { int24 tickBefore; int24 tickAfter; - (, tickBefore,,,,,) = pool.slot0(); + (, tickBefore,,,,,,) = pool.slot0(); (amount, sqrtPriceX96After, tickAfter) = parseRevertReason(reason); initializedTicksCrossed = pool.countInitializedTicksCrossed(tickBefore, tickAfter); diff --git a/src/periphery/libraries/OracleLibrary.sol b/src/periphery/libraries/OracleLibrary.sol index cdcf8e8..220be9e 100644 --- a/src/periphery/libraries/OracleLibrary.sol +++ b/src/periphery/libraries/OracleLibrary.sol @@ -71,7 +71,7 @@ library OracleLibrary { /// @param pool Address of Katana V3 pool that we want to observe /// @return secondsAgo The number of seconds ago of the oldest observation stored for the pool function getOldestObservationSecondsAgo(address pool) internal view returns (uint32 secondsAgo) { - (,, uint16 observationIndex, uint16 observationCardinality,,,) = IKatanaV3Pool(pool).slot0(); + (,, uint16 observationIndex, uint16 observationCardinality,,,,) = IKatanaV3Pool(pool).slot0(); require(observationCardinality > 0, "NI"); (uint32 observationTimestamp,,, bool initialized) = @@ -90,7 +90,7 @@ library OracleLibrary { /// @param pool Address of Katana V3 pool /// @return The tick that the pool was in at the start of the current block function getBlockStartingTickAndLiquidity(address pool) internal view returns (int24, uint128) { - (, int24 tick, uint16 observationIndex, uint16 observationCardinality,,,) = IKatanaV3Pool(pool).slot0(); + (, int24 tick, uint16 observationIndex, uint16 observationCardinality,,,,) = IKatanaV3Pool(pool).slot0(); // 2 observations are needed to reliably calculate the block starting tick require(observationCardinality > 1, "NEO"); diff --git a/src/periphery/libraries/PositionValue.sol b/src/periphery/libraries/PositionValue.sol index f59a8ef..3e88461 100644 --- a/src/periphery/libraries/PositionValue.sol +++ b/src/periphery/libraries/PositionValue.sol @@ -133,7 +133,7 @@ library PositionValue { view returns (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) { - (, int24 tickCurrent,,,,,) = pool.slot0(); + (, int24 tickCurrent,,,,,,) = pool.slot0(); (,, uint256 lowerFeeGrowthOutside0X128, uint256 lowerFeeGrowthOutside1X128,,,,) = pool.ticks(tickLower); (,, uint256 upperFeeGrowthOutside0X128, uint256 upperFeeGrowthOutside1X128,,,,) = pool.ticks(tickUpper); From c8d18832948d2650e7202a49fd2d050fab944fcd Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Mon, 16 Sep 2024 15:20:02 +0700 Subject: [PATCH 14/21] chore: storage layout --- logs/contract-code-sizes.log | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/logs/contract-code-sizes.log b/logs/contract-code-sizes.log index 16977c8..3c86900 100644 --- a/logs/contract-code-sizes.log +++ b/logs/contract-code-sizes.log @@ -9,7 +9,8 @@ | BytesLib | 86 | 24,490 | | CallbackValidation | 86 | 24,490 | | ChainId | 86 | 24,490 | -| ERC20 | 2,578 | 21,998 | +| Create2 | 86 | 24,490 | +| ERC20 | 2,546 | 22,030 | | ERC20Mock | 3,518 | 21,058 | | ERC721 | 6,557 | 18,019 | | EnumerableMap | 86 | 24,490 | @@ -18,25 +19,23 @@ | FixedPoint96 | 86 | 24,490 | | FullMath | 86 | 24,490 | | HexStrings | 86 | 24,490 | -| KatanaGovernanceMock | 2,310 | 22,266 | +| KatanaGovernanceMock | 3,403 | 21,173 | | KatanaInterfaceMulticall | 1,295 | 23,281 | | KatanaV2Library | 86 | 24,490 | | KatanaV2LibraryTestnet | 86 | 24,490 | -| KatanaV3Factory | 2,945 | 21,631 | -| KatanaV3FactoryProxy | 5,541 | 19,035 | -| KatanaV3Pool | 22,864 | 1,712 | -| KatanaV3PoolDeployer | 288 | 24,288 | -| KatanaV3PoolProxy | 1,248 | 23,328 | -| KatanaV3PoolProxyBytecode | 2,931 | 21,645 | +| KatanaV3Factory | 4,106 | 20,470 | +| KatanaV3Pool | 21,545 | 3,031 | +| KatanaV3PoolBeacon | 4,246 | 20,330 | +| KatanaV3PoolProxy | 1,209 | 23,367 | | LiquidityAmounts | 86 | 24,490 | | LiquidityMath | 86 | 24,490 | | LowGasSafeMath | 86 | 24,490 | -| MixedRouteQuoterV1 | 7,182 | 17,394 | -| MixedRouteQuoterV1Testnet | 7,182 | 17,394 | +| MixedRouteQuoterV1 | 7,220 | 17,356 | +| MixedRouteQuoterV1Testnet | 7,220 | 17,356 | | NFTDescriptor | 23,372 | 1,204 | | NFTSVG | 86 | 24,490 | -| NonfungiblePositionManager | 24,361 | 215 | -| NonfungibleTokenPositionDescriptor | 5,158 | 19,418 | +| NonfungiblePositionManager | 24,452 | 124 | +| NonfungibleTokenPositionDescriptor | 5,187 | 19,389 | | Oracle | 86 | 24,490 | | OracleLibrary | 86 | 24,490 | | PairFlash | 5,428 | 19,148 | @@ -47,7 +46,7 @@ | PositionKey | 86 | 24,490 | | PositionValue | 86 | 24,490 | | Quoter | 3,822 | 20,754 | -| QuoterV2 | 6,981 | 17,595 | +| QuoterV2 | 7,019 | 17,557 | | SafeCast | 86 | 24,490 | | SafeERC20Namer | 86 | 24,490 | | SafeMath | 86 | 24,490 | @@ -67,5 +66,5 @@ | UnsafeMath | 86 | 24,490 | | UpgradeableBeacon | 1,153 | 23,423 | | UpgradeableProxy | 738 | 23,838 | -| V3Migrator | 6,084 | 18,492 | +| V3Migrator | 6,529 | 18,047 | From d86c4cfd20667253cd6aa9b1e13031b274720300 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Mon, 16 Sep 2024 17:28:37 +0700 Subject: [PATCH 15/21] chore(NonfungibleTokenPositionDescriptor): prioritized display of well-known tokens on the Ronin network --- .../NonfungibleTokenPositionDescriptor.sol | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/periphery/NonfungibleTokenPositionDescriptor.sol b/src/periphery/NonfungibleTokenPositionDescriptor.sol index d3a0361..40c0e1b 100644 --- a/src/periphery/NonfungibleTokenPositionDescriptor.sol +++ b/src/periphery/NonfungibleTokenPositionDescriptor.sol @@ -16,18 +16,16 @@ import "./libraries/TokenRatioSortOrder.sol"; /// @title Describes NFT token positions /// @notice Produces a string containing the data URI for a JSON metadata string contract NonfungibleTokenPositionDescriptor is INonfungibleTokenPositionDescriptor { - address private constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; - address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; - address private constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; - address private constant TBTC = 0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa; - address private constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599; + address private constant USDC = 0x0B7007c13325C48911F73A2daD5FA5dCBf808aDc; + address private constant WETH = 0xc99a6A985eD2Cac1ef41640596C5A5f9F4E19Ef5; + address private constant WBTC = 0x7E73630F81647bCFD7B1F2C04c1C662D17d4577e; - address public immutable WETH9; + address public immutable WRON; /// @dev A null-terminated string bytes32 public immutable nativeCurrencyLabelBytes; - constructor(address _WETH9, bytes32 _nativeCurrencyLabelBytes) { - WETH9 = _WETH9; + constructor(address _WRON, bytes32 _nativeCurrencyLabelBytes) { + WRON = _WRON; nativeCurrencyLabelBytes = _nativeCurrencyLabelBytes; } @@ -70,10 +68,10 @@ contract NonfungibleTokenPositionDescriptor is INonfungibleTokenPositionDescript tokenId: tokenId, quoteTokenAddress: quoteTokenAddress, baseTokenAddress: baseTokenAddress, - quoteTokenSymbol: quoteTokenAddress == WETH9 + quoteTokenSymbol: quoteTokenAddress == WRON ? nativeCurrencyLabel() : SafeERC20Namer.tokenSymbol(quoteTokenAddress), - baseTokenSymbol: baseTokenAddress == WETH9 ? nativeCurrencyLabel() : SafeERC20Namer.tokenSymbol(baseTokenAddress), + baseTokenSymbol: baseTokenAddress == WRON ? nativeCurrencyLabel() : SafeERC20Namer.tokenSymbol(baseTokenAddress), quoteTokenDecimals: IERC20Metadata(quoteTokenAddress).decimals(), baseTokenDecimals: IERC20Metadata(baseTokenAddress).decimals(), flipRatio: _flipRatio, @@ -92,18 +90,14 @@ contract NonfungibleTokenPositionDescriptor is INonfungibleTokenPositionDescript } function tokenRatioPriority(address token, uint256 chainId) public view returns (int256) { - if (token == WETH9) { + if (token == WRON) { return TokenRatioSortOrder.DENOMINATOR; } - if (chainId == 1) { + if (chainId == 2020) { if (token == USDC) { return TokenRatioSortOrder.NUMERATOR_MOST; - } else if (token == USDT) { + } else if (token == WETH) { return TokenRatioSortOrder.NUMERATOR_MORE; - } else if (token == DAI) { - return TokenRatioSortOrder.NUMERATOR; - } else if (token == TBTC) { - return TokenRatioSortOrder.DENOMINATOR_MORE; } else if (token == WBTC) { return TokenRatioSortOrder.DENOMINATOR_MOST; } else { From c60307b067c764229b43be7447141bc809720d99 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Mon, 16 Sep 2024 17:29:07 +0700 Subject: [PATCH 16/21] chore: storage layout --- logs/contract-code-sizes.log | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/contract-code-sizes.log b/logs/contract-code-sizes.log index 3c86900..dcd5f8e 100644 --- a/logs/contract-code-sizes.log +++ b/logs/contract-code-sizes.log @@ -35,7 +35,7 @@ | NFTDescriptor | 23,372 | 1,204 | | NFTSVG | 86 | 24,490 | | NonfungiblePositionManager | 24,452 | 124 | -| NonfungibleTokenPositionDescriptor | 5,187 | 19,389 | +| NonfungibleTokenPositionDescriptor | 5,097 | 19,479 | | Oracle | 86 | 24,490 | | OracleLibrary | 86 | 24,490 | | PairFlash | 5,428 | 19,148 | From 54107fd2d242af6189e6daa0302ee2579cc383a5 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Tue, 17 Sep 2024 14:35:41 +0700 Subject: [PATCH 17/21] feat: update IKatanaGovernance --- script/local/DeployKatanaV3Local.s.sol | 2 +- src/external/KatanaGovernanceMock.sol | 10 ++++--- src/external/interfaces/IKatanaGovernance.sol | 30 +++++++++++++------ 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/script/local/DeployKatanaV3Local.s.sol b/script/local/DeployKatanaV3Local.s.sol index 5543cb0..2153a40 100644 --- a/script/local/DeployKatanaV3Local.s.sol +++ b/script/local/DeployKatanaV3Local.s.sol @@ -13,7 +13,7 @@ contract DeployKatanaV3Local is DeployKatanaV3Periphery { function setUp() public override { proxyAdmin = makeAddr("ProxyAdmin"); - governance = address(new KatanaGovernanceMock(address(0), address(0), true)); + governance = address(new KatanaGovernanceMock(true)); treasury = makeAddr("RoninTreasury"); wron = address(new ERC20Mock("Wrapped Ronin", "WRON", address(this), 10 ** 9 * 10 ** 9)); factoryV2 = makeAddr("KatanaV2Factory"); diff --git a/src/external/KatanaGovernanceMock.sol b/src/external/KatanaGovernanceMock.sol index d0e6564..ed4c1f6 100644 --- a/src/external/KatanaGovernanceMock.sol +++ b/src/external/KatanaGovernanceMock.sol @@ -12,9 +12,7 @@ contract KatanaGovernanceMock is IKatanaGovernance { bool private immutable _defaultPermission; mapping(address => mapping(address => uint256)) private _permission; - constructor(address router, address positionManager, bool defaultPermission) { - _router = router; - _positionManager = positionManager; + constructor(bool defaultPermission) { _defaultPermission = defaultPermission; } @@ -53,6 +51,10 @@ contract KatanaGovernanceMock is IKatanaGovernance { return _positionManager; } + function isAllowedActor(address) external pure override returns (bool) { + revert("not implemented"); + } + function isAuthorized(address[] memory tokens, address account) external view override returns (bool) { for (uint256 i = 0; i < tokens.length; ++i) { if (!isAuthorized(tokens[i], account)) { @@ -70,7 +72,7 @@ contract KatanaGovernanceMock is IKatanaGovernance { _v3Factory = factory; } - function setFactory(address) external pure override { + function setAllowedActor(address, bool) external pure override { revert("not implemented"); } diff --git a/src/external/interfaces/IKatanaGovernance.sol b/src/external/interfaces/IKatanaGovernance.sol index 9a9bb53..efa785f 100644 --- a/src/external/interfaces/IKatanaGovernance.sol +++ b/src/external/interfaces/IKatanaGovernance.sol @@ -19,10 +19,14 @@ interface IKatanaGovernance { event PermissionUpdated( address indexed by, address indexed token, uint40 whitelistUntil, address[] allowed, bool[] statuses ); + /// @dev Emitted when allowed actor list is updated. + event AllowedActorUpdated(address indexed actor, bool allowed); /** * @dev Executes calls to the Katana V3 factory. * + * - Requirements: Caller must be the owner. + * * @param data The array of encoded function calls. * @return results The array of encoded results. */ @@ -37,6 +41,17 @@ interface IKatanaGovernance { */ function setRouter(address router) external; + /** + * @dev Sets an address is allowed/disallowed to skip authorization checks. + * To check if an address is allowed, see `isAllowedActor` function. + * + * - Requirements: Caller must be the owner. + * + * @param actor The address to be allowed/disallowed. + * @param allowed True if the address is allowed, otherwise false. + */ + function setAllowedActor(address actor, bool allowed) external; + /** * @dev Sets the permission of a token. * @@ -50,15 +65,6 @@ interface IKatanaGovernance { function setPermission(address token, uint40 whitelistUntil, address[] calldata alloweds, bool[] calldata statuses) external; - /** - * @dev Sets the factory address. - * - * - Requirements: Caller must be the owner. - * - * @param factory The address of the factory. - */ - function setFactory(address factory) external; - /** * @dev Creates a pair of tokens and sets the permission. * @@ -89,6 +95,12 @@ interface IKatanaGovernance { */ function getPositionManager() external view returns (address); + /** + * @notice Whether the account is always skipped from authorization checks. + * @dev See `isAuthorized` function. + */ + function isAllowedActor(address account) external view returns (bool); + /** * @notice Checks if an account is authorized to interact with a token. * From ecee4fb54260b13d8b2d2067f479a5a88ee9fd2c Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Tue, 17 Sep 2024 14:36:19 +0700 Subject: [PATCH 18/21] chore: storage layout --- logs/contract-code-sizes.log | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/contract-code-sizes.log b/logs/contract-code-sizes.log index dcd5f8e..1dfd2c6 100644 --- a/logs/contract-code-sizes.log +++ b/logs/contract-code-sizes.log @@ -19,7 +19,7 @@ | FixedPoint96 | 86 | 24,490 | | FullMath | 86 | 24,490 | | HexStrings | 86 | 24,490 | -| KatanaGovernanceMock | 3,403 | 21,173 | +| KatanaGovernanceMock | 3,479 | 21,097 | | KatanaInterfaceMulticall | 1,295 | 23,281 | | KatanaV2Library | 86 | 24,490 | | KatanaV2LibraryTestnet | 86 | 24,490 | From 3ffd56300ced6ec42c5dcbe28d4420c5011e49e2 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Wed, 18 Sep 2024 13:32:12 +0700 Subject: [PATCH 19/21] feat(KatanaV3Factory): remove setOwner function --- src/core/KatanaV3Factory.sol | 12 +++++------- src/core/interfaces/IKatanaV3Factory.sol | 10 ---------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/core/KatanaV3Factory.sol b/src/core/KatanaV3Factory.sol index 0a9a43e..2846448 100644 --- a/src/core/KatanaV3Factory.sol +++ b/src/core/KatanaV3Factory.sol @@ -46,12 +46,16 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { function initialize(address beacon_, address owner_, address treasury_) external { require(beacon == address(0), "KatanaV3Factory: ALREADY_INITIALIZED"); + require(beacon_ != address(0), "KatanaV3Factory: INVALID_BEACON"); + require(owner_ != address(0), "KatanaV3Factory: INVALID_OWNER"); + require(treasury_ != address(0), "KatanaV3Factory: INVALID_TREASURY"); + // this beacon is treated as immutable // so there is no need to emit an event beacon = beacon_; + // owner is also treated as immutable owner = owner_; - emit OwnerChanged(address(0), owner_); treasury = treasury_; emit TreasuryChanged(address(0), treasury_); @@ -86,12 +90,6 @@ contract KatanaV3Factory is IKatanaV3Factory, KatanaV3PoolDeployer { emit PoolCreated(token0, token1, fee, tickSpacing, pool); } - /// @inheritdoc IKatanaV3Factory - function setOwner(address _owner) external override onlyOwner { - emit OwnerChanged(owner, _owner); - owner = _owner; - } - function setTreasury(address _treasury) external override onlyOwner { require(_treasury != address(0), "KatanaV3Factory: INVALID_TREASURY"); emit TreasuryChanged(treasury, _treasury); diff --git a/src/core/interfaces/IKatanaV3Factory.sol b/src/core/interfaces/IKatanaV3Factory.sol index e5fbf22..e1ef789 100644 --- a/src/core/interfaces/IKatanaV3Factory.sol +++ b/src/core/interfaces/IKatanaV3Factory.sol @@ -4,11 +4,6 @@ pragma solidity >=0.5.0; /// @title The interface for the Katana V3 Factory /// @notice The Katana V3 Factory facilitates creation of Katana V3 pools and control over the protocol fees interface IKatanaV3Factory { - /// @notice Emitted when the owner of the factory is changed - /// @param oldOwner The owner before the owner was changed - /// @param newOwner The owner after the owner was changed - event OwnerChanged(address indexed oldOwner, address indexed newOwner); - /// @notice Emitted when the treasury address is changed /// @param oldTreasury The treasury address before the treasury was changed /// @param newTreasury The treasury address after the treasury was changed @@ -81,11 +76,6 @@ interface IKatanaV3Factory { /// @return pool The address of the newly created pool function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool); - /// @notice Updates the owner of the factory - /// @dev Must be called by the current owner - /// @param _owner The new owner of the factory - function setOwner(address _owner) external; - /// @notice Updates the treasury address /// @dev Must be called by the current owner /// @param _treasury The new treasury address From d7723376af74f717ec4046db6204316792894c3e Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Wed, 18 Sep 2024 14:12:15 +0700 Subject: [PATCH 20/21] feat: update IKatanaGovernance --- src/external/KatanaGovernanceMock.sol | 25 ++++++++-------- src/external/interfaces/IKatanaGovernance.sol | 30 ++++++++++++------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/external/KatanaGovernanceMock.sol b/src/external/KatanaGovernanceMock.sol index ed4c1f6..4526547 100644 --- a/src/external/KatanaGovernanceMock.sol +++ b/src/external/KatanaGovernanceMock.sol @@ -24,13 +24,6 @@ contract KatanaGovernanceMock is IKatanaGovernance { _permission[token][account] = 2; } - function v3FactoryMulticall(bytes[] calldata data) external override returns (bytes[] memory results) { - results = new bytes[](data.length); - for (uint256 i = 0; i < data.length; ++i) { - results[i] = Address.functionCall(_v3Factory, data[i]); - } - } - function setRouter(address router) external override { _router = router; } @@ -51,10 +44,6 @@ contract KatanaGovernanceMock is IKatanaGovernance { return _positionManager; } - function isAllowedActor(address) external pure override returns (bool) { - revert("not implemented"); - } - function isAuthorized(address[] memory tokens, address account) external view override returns (bool) { for (uint256 i = 0; i < tokens.length; ++i) { if (!isAuthorized(tokens[i], account)) { @@ -89,7 +78,19 @@ contract KatanaGovernanceMock is IKatanaGovernance { revert("not implemented"); } - function getFactory() external pure override returns (address) { + function toggleFlashLoanPermission() external pure override { + revert("not implemented"); + } + + function enableFeeAmount(uint24, int24, uint8, uint8) external pure override { + revert("not implemented"); + } + + function isAllowedActor(address) external pure override returns (bool) { + revert("not implemented"); + } + + function getV2Factory() external pure override returns (address) { revert("not implemented"); } diff --git a/src/external/interfaces/IKatanaGovernance.sol b/src/external/interfaces/IKatanaGovernance.sol index efa785f..d2d82cf 100644 --- a/src/external/interfaces/IKatanaGovernance.sol +++ b/src/external/interfaces/IKatanaGovernance.sol @@ -22,16 +22,6 @@ interface IKatanaGovernance { /// @dev Emitted when allowed actor list is updated. event AllowedActorUpdated(address indexed actor, bool allowed); - /** - * @dev Executes calls to the Katana V3 factory. - * - * - Requirements: Caller must be the owner. - * - * @param data The array of encoded function calls. - * @return results The array of encoded results. - */ - function v3FactoryMulticall(bytes[] calldata data) external returns (bytes[] memory results); - /** * @dev Sets the router address. * @@ -52,6 +42,24 @@ interface IKatanaGovernance { */ function setAllowedActor(address actor, bool allowed) external; + /** + * @notice Toggles the ability to call the `flash` function on KatanaV3Pool + * + * - Requirements: Caller must be the owner. + */ + function toggleFlashLoanPermission() external; + + /** + * @notice Enables a fee amount with the given tickSpacing for KatanaV3Factory + * @dev Fee amounts may never be removed once enabled. Caller must be the owner. + * + * @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6) + * @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount + * @param feeProtocolNum The numerator of the protocol fee as a ratio of the fee amount + * @param feeProtocolDen The denominator of the protocol fee as a ratio of the fee amount + */ + function enableFeeAmount(uint24 fee, int24 tickSpacing, uint8 feeProtocolNum, uint8 feeProtocolDen) external; + /** * @dev Sets the permission of a token. * @@ -118,7 +126,7 @@ interface IKatanaGovernance { /** * @dev Gets the Katana V2 factory address. */ - function getFactory() external view returns (address); + function getV2Factory() external view returns (address); /** * @notice Gets the whitelist duration of a token. From 39a6e9d31103387c96ef9502cf997dff41170ef7 Mon Sep 17 00:00:00 2001 From: Thai Xuan Dang Date: Wed, 18 Sep 2024 14:12:26 +0700 Subject: [PATCH 21/21] chore: storage layout --- logs/contract-code-sizes.log | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logs/contract-code-sizes.log b/logs/contract-code-sizes.log index 1dfd2c6..11eb38e 100644 --- a/logs/contract-code-sizes.log +++ b/logs/contract-code-sizes.log @@ -19,11 +19,11 @@ | FixedPoint96 | 86 | 24,490 | | FullMath | 86 | 24,490 | | HexStrings | 86 | 24,490 | -| KatanaGovernanceMock | 3,479 | 21,097 | +| KatanaGovernanceMock | 2,388 | 22,188 | | KatanaInterfaceMulticall | 1,295 | 23,281 | | KatanaV2Library | 86 | 24,490 | | KatanaV2LibraryTestnet | 86 | 24,490 | -| KatanaV3Factory | 4,106 | 20,470 | +| KatanaV3Factory | 4,132 | 20,444 | | KatanaV3Pool | 21,545 | 3,031 | | KatanaV3PoolBeacon | 4,246 | 20,330 | | KatanaV3PoolProxy | 1,209 | 23,367 |