{"ok":true,"contract":{"address":"0x238a358808379702088667322f80ac48bad5e6c4","contract_name":"Vault","deployed":null,"fund":"0","fund_usd":"0.00000000","native_balance":"0","network":"base","first_seen":"1771430402","verified":true,"is_proxy":false,"implementation_address":null,"proxy_contract_name":"Vault","implementation_contract_name":null,"deploy_tx_hash":null,"deployer_address":null,"deploy_block_number":null,"deployed_at_timestamp":null,"deployed_at":null,"confidence":"heuristic","fetched_at":"2026-02-18T17:02:57.156Z","source_code":"// File: src/Vault.sol\n// SPDX-License-Identifier: GPL-2.0-or-later\n// Copyright (C) 2024 PancakeSwap\npragma solidity 0.8.26;\n\nimport {Ownable, Ownable2Step} from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\nimport {IVault, IVaultToken} from \"./interfaces/IVault.sol\";\nimport {SettlementGuard} from \"./libraries/SettlementGuard.sol\";\nimport {Currency, CurrencyLibrary} from \"./types/Currency.sol\";\nimport {BalanceDelta} from \"./types/BalanceDelta.sol\";\nimport {ILockCallback} from \"./interfaces/ILockCallback.sol\";\nimport {SafeCast} from \"./libraries/SafeCast.sol\";\nimport {VaultReserve} from \"./libraries/VaultReserve.sol\";\nimport {VaultToken} from \"./VaultToken.sol\";\n\ncontract Vault is IVault, VaultToken, Ownable2Step {\n    using SafeCast for *;\n    using CurrencyLibrary for Currency;\n\n    constructor() Ownable(msg.sender) {}\n\n    mapping(address app => bool isRegistered) public override isAppRegistered;\n\n    /// @dev keep track of each app's reserves\n    mapping(address app => mapping(Currency currency => uint256 reserve)) public reservesOfApp;\n\n    /// @notice only registered app is allowed to perform accounting\n    modifier onlyRegisteredApp() {\n        if (!isAppRegistered[msg.sender]) revert AppUnregistered();\n\n        _;\n    }\n\n    /// @notice revert if no locker is set\n    modifier isLocked() {\n        if (SettlementGuard.getLocker() == address(0)) revert NoLocker();\n        _;\n    }\n\n    /// @inheritdoc IVault\n    function registerApp(address app) external override onlyOwner {\n        isAppRegistered[app] = true;\n\n        emit AppRegistered(app);\n    }\n\n    /// @inheritdoc IVault\n    function getLocker() external view override returns (address) {\n        return SettlementGuard.getLocker();\n    }\n\n    /// @inheritdoc IVault\n    function getUnsettledDeltasCount() external view override returns (uint256) {\n        return SettlementGuard.getUnsettledDeltasCount();\n    }\n\n    /// @inheritdoc IVault\n    function currencyDelta(address settler, Currency currency) external view override returns (int256) {\n        return SettlementGuard.getCurrencyDelta(settler, currency);\n    }\n\n    /// @dev interaction must start from lock\n    /// @inheritdoc IVault\n    function lock(bytes calldata data) external override returns (bytes memory result) {\n        /// @dev only one locker at a time\n        SettlementGuard.setLocker(msg.sender);\n\n        result = ILockCallback(msg.sender).lockAcquired(data);\n        /// @notice the caller can do anything in this callback as long as all deltas are offset after this\n        if (SettlementGuard.getUnsettledDeltasCount() != 0) revert CurrencyNotSettled();\n\n        /// @dev release the lock\n        SettlementGuard.setLocker(address(0));\n    }\n\n    /// @inheritdoc IVault\n    function accountAppBalanceDelta(\n        Currency currency0,\n        Currency currency1,\n        BalanceDelta delta,\n        address settler,\n        BalanceDelta hookDelta,\n        address hook\n    ) external override isLocked onlyRegisteredApp {\n        (int128 delta0, int128 delta1) = (delta.amount0(), delta.amount1());\n        (int128 hookDelta0, int128 hookDelta1) = (hookDelta.amount0(), hookDelta.amount1());\n\n        /// @dev call _accountDeltaForApp once with both delta/hookDelta to save gas and prevent\n        /// reservesOfApp from underflow when it deduct before addition\n        _accountDeltaForApp(currency0, delta0 + hookDelta0);\n        _accountDeltaForApp(currency1, delta1 + hookDelta1);\n\n        // keep track of the balance on vault level\n        SettlementGuard.accountDelta(settler, currency0, delta0);\n        SettlementGuard.accountDelta(settler, currency1, delta1);\n        SettlementGuard.accountDelta(hook, currency0, hookDelta0);\n        SettlementGuard.accountDelta(hook, currency1, hookDelta1);\n    }\n\n    /// @inheritdoc IVault\n    function accountAppBalanceDelta(Currency currency0, Currency currency1, BalanceDelta delta, address settler)\n        external\n        override\n        isLocked\n        onlyRegisteredApp\n    {\n        int128 delta0 = delta.amount0();\n        int128 delta1 = delta.amount1();\n\n        // keep track of the balance on app level\n        _accountDeltaForApp(currency0, delta0);\n        _accountDeltaForApp(currency1, delta1);\n\n        // keep track of the balance on vault level\n        SettlementGuard.accountDelta(settler, currency0, delta0);\n        SettlementGuard.accountDelta(settler, currency1, delta1);\n    }\n\n    /// @inheritdoc IVault\n    function accountAppBalanceDelta(Currency currency, int128 delta, address settler)\n        external\n        override\n        isLocked\n        onlyRegisteredApp\n    {\n        _accountDeltaForApp(currency, delta);\n        SettlementGuard.accountDelta(settler, currency, delta);\n    }\n\n    /// @inheritdoc IVault\n    function take(Currency currency, address to, uint256 amount) external override isLocked {\n        unchecked {\n            SettlementGuard.accountDelta(msg.sender, currency, -(amount.toInt128()));\n            currency.transfer(to, amount);\n        }\n    }\n\n    /// @inheritdoc IVault\n    function mint(address to, Currency currency, uint256 amount) external override isLocked {\n        unchecked {\n            SettlementGuard.accountDelta(msg.sender, currency, -(amount.toInt128()));\n            _mint(to, currency, amount);\n        }\n    }\n\n    function sync(Currency currency) public override {\n        if (currency.isNative()) {\n            VaultReserve.setVaultReserve(CurrencyLibrary.NATIVE, 0);\n        } else {\n            uint256 balance = currency.balanceOfSelf();\n            VaultReserve.setVaultReserve(currency, balance);\n        }\n    }\n\n    /// @inheritdoc IVault\n    function settle() external payable override isLocked returns (uint256) {\n        return _settle(msg.sender);\n    }\n\n    /// @inheritdoc IVault\n    function settleFor(address recipient) external payable override isLocked returns (uint256) {\n        return _settle(recipient);\n    }\n\n    /// @inheritdoc IVault\n    function clear(Currency currency, uint256 amount) external isLocked {\n        int256 existingDelta = SettlementGuard.getCurrencyDelta(msg.sender, currency);\n        int128 amountDelta = amount.toInt128();\n        /// @dev since amount is uint256, existingDelta must be positive otherwise revert\n        if (amountDelta != existingDelta) revert MustClearExactPositiveDelta();\n        unchecked {\n            SettlementGuard.accountDelta(msg.sender, currency, -amountDelta);\n        }\n    }\n\n    /// @inheritdoc IVault\n    function burn(address from, Currency currency, uint256 amount) external override isLocked {\n        SettlementGuard.accountDelta(msg.sender, currency, amount.toInt128());\n        _burnFrom(from, currency, amount);\n    }\n\n    /// @inheritdoc IVault\n    function collectFee(Currency currency, uint256 amount, address recipient) external onlyRegisteredApp {\n        // prevent transfer between the sync and settle balanceOfs (native settle uses msg.value)\n        (Currency syncedCurrency,) = VaultReserve.getVaultReserve();\n        if (!currency.isNative() && syncedCurrency == currency) revert FeeCurrencySynced();\n        reservesOfApp[msg.sender][currency] -= amount;\n        currency.transfer(recipient, amount);\n    }\n\n    /// @inheritdoc IVault\n    function getVaultReserve() external view returns (Currency, uint256) {\n        return VaultReserve.getVaultReserve();\n    }\n\n    function _accountDeltaForApp(Currency currency, int128 delta) internal {\n        if (delta == 0) return;\n\n        /// @dev optimization: msg.sender will always be app address, verification should be done on caller address\n        if (delta >= 0) {\n            /// @dev arithmetic underflow make sure trader can't withdraw too much from app\n            reservesOfApp[msg.sender][currency] -= uint128(delta);\n        } else {\n            /// @dev arithmetic overflow make sure trader won't deposit too much into app\n            reservesOfApp[msg.sender][currency] += uint128(-delta);\n        }\n    }\n\n    // if settling native, integrators should still call `sync` first to avoid DoS attack vectors\n    function _settle(address recipient) internal returns (uint256 paid) {\n        (Currency currency, uint256 reservesBefore) = VaultReserve.getVaultReserve();\n        if (!currency.isNative()) {\n            if (msg.value > 0) revert SettleNonNativeCurrencyWithValue();\n            uint256 reservesNow = currency.balanceOfSelf();\n            paid = reservesNow - reservesBefore;\n\n            /// @dev reset the reserve after settled\n            VaultReserve.setVaultReserve(CurrencyLibrary.NATIVE, 0);\n        } else {\n            // NATIVE token does not require sync call before settle\n            paid = msg.value;\n        }\n\n        SettlementGuard.accountDelta(recipient, currency, paid.toInt128());\n    }\n}\n\n\n// File: lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.20;\n\nimport {Ownable} from \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This extension of the {Ownable} contract includes a two-step mechanism to transfer\n * ownership, where the new owner must call {acceptOwnership} in order to replace the\n * old one. This can help prevent common mistakes, such as transfers of ownership to\n * incorrect accounts, or to contracts that are unable to interact with the\n * permission system.\n *\n * The initial owner is specified at deployment time in the constructor for `Ownable`. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n    address private _pendingOwner;\n\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Returns the address of the pending owner.\n     */\n    function pendingOwner() public view virtual returns (address) {\n        return _pendingOwner;\n    }\n\n    /**\n     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual override onlyOwner {\n        _pendingOwner = newOwner;\n        emit OwnershipTransferStarted(owner(), newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual override {\n        delete _pendingOwner;\n        super._transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev The new owner accepts the ownership transfer.\n     */\n    function acceptOwnership() public virtual {\n        address sender = _msgSender();\n        if (pendingOwner() != sender) {\n            revert OwnableUnauthorizedAccount(sender);\n        }\n        _transferOwnership(sender);\n    }\n}\n\n\n// File: src/interfaces/IVault.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Currency} from \"../types/Currency.sol\";\nimport {BalanceDelta} from \"../types/BalanceDelta.sol\";\nimport {IVaultToken} from \"./IVaultToken.sol\";\n\ninterface IVault is IVaultToken {\n    event AppRegistered(address indexed app);\n\n    /// @notice Thrown when a app is not registered\n    error AppUnregistered();\n\n    /// @notice Thrown when a currency is not netted out after a lock\n    error CurrencyNotSettled();\n\n    /// @notice Thrown when there is already a locker\n    /// @param locker The address of the current locker\n    error LockerAlreadySet(address locker);\n\n    /// @notice Thrown when passing in msg.value for non-native currency\n    error SettleNonNativeCurrencyWithValue();\n\n    /// @notice Thrown when `clear` is called with an amount that is not exactly equal to the open currency delta.\n    error MustClearExactPositiveDelta();\n\n    /// @notice Thrown when there is no locker\n    error NoLocker();\n\n    /// @notice Thrown when collectFee is attempted on a token that is synced.\n    error FeeCurrencySynced();\n\n    function isAppRegistered(address app) external returns (bool);\n\n    /// @notice Returns the reserves for a a given pool type and currency\n    function reservesOfApp(address app, Currency currency) external view returns (uint256);\n\n    /// @notice register an app so that it can perform accounting base on vault\n    function registerApp(address app) external;\n\n    /// @notice Returns the locker who is locking the vault\n    function getLocker() external view returns (address locker);\n\n    /// @notice Returns the reserve and its amount that is currently being stored in trnasient storage\n    function getVaultReserve() external view returns (Currency, uint256);\n\n    /// @notice Returns lock data\n    function getUnsettledDeltasCount() external view returns (uint256 count);\n\n    /// @notice Get the current delta for a locker in the given currency\n    /// @param currency The currency for which to lookup the delta\n    function currencyDelta(address settler, Currency currency) external view returns (int256);\n\n    /// @notice All operations go through this function\n    /// @param data Any data to pass to the callback, via `ILockCallback(msg.sender).lockCallback(data)`\n    /// @return The data returned by the call to `ILockCallback(msg.sender).lockCallback(data)`\n    function lock(bytes calldata data) external returns (bytes memory);\n\n    /// @notice Called by registered app to account for a change in the pool balance,\n    /// convenient for AMM pool manager, typically after modifyLiquidity, swap, donate,\n    /// include the case where hookDelta is involved\n    /// @param currency0 The PoolKey currency0 to update\n    /// @param currency1 The PoolKey currency1 to update\n    /// @param delta The change in the pool's balance\n    /// @param settler The address whose delta will be updated\n    /// @param hookDelta The change in the pool's balance from hook\n    /// @param hook The address whose hookDelta will be updated\n    function accountAppBalanceDelta(\n        Currency currency0,\n        Currency currency1,\n        BalanceDelta delta,\n        address settler,\n        BalanceDelta hookDelta,\n        address hook\n    ) external;\n\n    /// @notice Called by registered app to account for a change in the pool balance,\n    /// convenient for AMM pool manager, typically after modifyLiquidity, swap, donate\n    /// @param currency0 The PoolKey currency0 to update\n    /// @param currency1 The PoolKey currency1 to update\n    /// @param delta The change in the pool's balance\n    /// @param settler The address whose delta will be updated\n    function accountAppBalanceDelta(Currency currency0, Currency currency1, BalanceDelta delta, address settler)\n        external;\n\n    /// @notice This works as a general accounting mechanism for non-dex app\n    /// @param currency The currency to update\n    /// @param delta The change in the balance\n    /// @param settler The address whose delta will be updated\n    function accountAppBalanceDelta(Currency currency, int128 delta, address settler) external;\n\n    /// @notice Called by the user to net out some value owed to the user\n    /// @dev Will revert if the requested amount is not available, consider using `mint` instead\n    /// @dev Can also be used as a mechanism for free flash loans\n    function take(Currency currency, address to, uint256 amount) external;\n\n    /// @notice Writes the current ERC20 balance of the specified currency to transient storage\n    /// This is used to checkpoint balances for the manager and derive deltas for the caller.\n    /// @dev This MUST be called before any ERC20 tokens are sent into the contract, but can be skipped\n    /// for native tokens because the amount to settle is determined by the sent value.\n    /// However, if an ERC20 token has been synced and not settled, and the caller instead wants to settle\n    /// native funds, this function can be called with the native currency to then be able to settle the native currency\n    function sync(Currency token0) external;\n\n    /// @notice Called by the user to pay what is owed\n    function settle() external payable returns (uint256 paid);\n\n    /// @notice Called by the user to pay on behalf of another address\n    /// @param recipient The address to credit for the payment\n    /// @return paid The amount of currency settled\n    function settleFor(address recipient) external payable returns (uint256 paid);\n\n    /// @notice WARNING - Any currency that is cleared, will be non-retreivable, and locked in the contract permanently.\n    /// A call to clear will zero out a positive balance WITHOUT a corresponding transfer.\n    /// @dev This could be used to clear a balance that is considered dust.\n    /// Additionally, the amount must be the exact positive balance. This is to enforce that the caller is aware of the amount being cleared.\n    function clear(Currency currency, uint256 amount) external;\n\n    /// @notice Called by app to collect any fee related\n    /// @dev no restriction on caller, underflow happen if caller collect more than the reserve\n    function collectFee(Currency currency, uint256 amount, address recipient) external;\n\n    /// @notice Called by the user to store surplus tokens in the vault\n    function mint(address to, Currency currency, uint256 amount) external;\n\n    /// @notice Called by the user to use surplus tokens for payment settlement\n    function burn(address from, Currency currency, uint256 amount) external;\n}\n\n\n// File: src/libraries/SettlementGuard.sol\n// SPDX-License-Identifier: GPL-2.0-or-later\n// Copyright (C) 2024 PancakeSwap\npragma solidity ^0.8.24;\n\nimport {Currency} from \"../types/Currency.sol\";\nimport {IVault} from \"../interfaces/IVault.sol\";\n\n/// @notice This is a workaround when transient keyword is absent. It manages:\n///  - 0: address locker\n///  - 1: uint256 unsettledDeltasCount\n///  - 2: mapping(address, mapping(Currency => int256)) currencyDelta\nlibrary SettlementGuard {\n    /// @dev uint256 internal constant LOCKER_SLOT = uint256(keccak256(\"SETTLEMENT_LOCKER\")) - 1;\n    uint256 internal constant LOCKER_SLOT = 0xedda7c051899c54dd66eaf5e13c031326ab4729812a579bed198ab93fd313d70;\n\n    /// @dev uint256 internal constant UNSETTLED_DELTAS_COUNT = uint256(keccak256(\"SETTLEMENT_UNSETTLEMENTD_DELTAS_COUNT\")) - 1;\n    uint256 internal constant UNSETTLED_DELTAS_COUNT =\n        0xa88ffc6a483ae852b901fb1c3a0df606e2e4461b493434e6643ebdc3ffabd151;\n\n    /// @dev uint256 internal constant CURRENCY_DELTA = uint256(keccak256(\"SETTLEMENT_CURRENCY_DELTA\")) - 1;\n    uint256 internal constant CURRENCY_DELTA = 0x6dc13502b9ba2a9e8e42c53a1856d632b29d5aab3bcb4a2476bfec06cbd9cf22;\n\n    /// @notice Update the locker address stored in the transient store\n    /// @param newLocker The new locker address\n    function setLocker(address newLocker) internal {\n        address currentLocker = getLocker();\n\n        // either set from non-zero to zero (set) or from zero to non-zero (reset)\n        if (currentLocker != address(0) && newLocker != address(0)) revert IVault.LockerAlreadySet(currentLocker);\n\n        assembly (\"memory-safe\") {\n            tstore(LOCKER_SLOT, and(newLocker, 0xffffffffffffffffffffffffffffffffffffffff))\n        }\n    }\n\n    /// @notice Get the locker address stored in the transient store\n    /// @return locker The locker address\n    function getLocker() internal view returns (address locker) {\n        assembly (\"memory-safe\") {\n            locker := tload(LOCKER_SLOT)\n        }\n    }\n\n    /// @notice Get the count of non-zero (unsettled) deltas stored in the transient store\n    /// @return count The count of non-zero deltas\n    function getUnsettledDeltasCount() internal view returns (uint256 count) {\n        assembly (\"memory-safe\") {\n            count := tload(UNSETTLED_DELTAS_COUNT)\n        }\n    }\n\n    /// @notice Create or update the delta record for a settler and currency\n    /// if a new record is added then increment the count of non-zero deltas\n    /// if an existing record is updated to zero then decrement the count of non-zero deltas\n    /// @param settler The address of who is responsible for the settlement\n    /// @param currency The currency of the settlement\n    /// @param newlyAddedDelta The delta to be added to the existing delta\n    function accountDelta(address settler, Currency currency, int256 newlyAddedDelta) internal {\n        if (newlyAddedDelta == 0) return;\n\n        /// @dev update the count of non-zero deltas if necessary\n        int256 currentDelta = getCurrencyDelta(settler, currency);\n        int256 nextDelta = currentDelta + newlyAddedDelta;\n        unchecked {\n            if (nextDelta == 0) {\n                assembly (\"memory-safe\") {\n                    tstore(UNSETTLED_DELTAS_COUNT, sub(tload(UNSETTLED_DELTAS_COUNT), 1))\n                }\n            } else if (currentDelta == 0) {\n                assembly (\"memory-safe\") {\n                    tstore(UNSETTLED_DELTAS_COUNT, add(tload(UNSETTLED_DELTAS_COUNT), 1))\n                }\n            }\n        }\n\n        /// @dev ref: https://docs.soliditylang.org/en/v0.8.24/internals/layout_in_storage.html#mappings-and-dynamic-arrays\n        /// simulating mapping index but with a single hash\n        /// save one keccak256 hash compared to built-in nested mapping\n        uint256 elementSlot = uint256(keccak256(abi.encode(settler, currency, CURRENCY_DELTA)));\n        assembly (\"memory-safe\") {\n            tstore(elementSlot, nextDelta)\n        }\n    }\n\n    /// @notice Get the current delta record for a given settler and currency\n    /// @param settler The address of who is responsible for the settlement\n    /// @param currency The currency of the settlement\n    /// @return delta The delta value\n    function getCurrencyDelta(address settler, Currency currency) internal view returns (int256 delta) {\n        uint256 elementSlot = uint256(keccak256(abi.encode(settler, currency, CURRENCY_DELTA)));\n        assembly (\"memory-safe\") {\n            delta := tload(elementSlot)\n        }\n    }\n}\n\n\n// File: src/types/Currency.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC20Minimal} from \"../interfaces/IERC20Minimal.sol\";\nimport {CustomRevert} from \"../libraries/CustomRevert.sol\";\n\ntype Currency is address;\n\nusing {greaterThan as >, lessThan as <, greaterThanOrEqualTo as >=, equals as ==} for Currency global;\nusing CurrencyLibrary for Currency global;\n\nfunction equals(Currency currency, Currency other) pure returns (bool) {\n    return Currency.unwrap(currency) == Currency.unwrap(other);\n}\n\nfunction greaterThan(Currency currency, Currency other) pure returns (bool) {\n    return Currency.unwrap(currency) > Currency.unwrap(other);\n}\n\nfunction lessThan(Currency currency, Currency other) pure returns (bool) {\n    return Currency.unwrap(currency) < Currency.unwrap(other);\n}\n\nfunction greaterThanOrEqualTo(Currency currency, Currency other) pure returns (bool) {\n    return Currency.unwrap(currency) >= Currency.unwrap(other);\n}\n\n/// @title CurrencyLibrary\n/// @dev This library allows for transferring and holding native tokens and ERC20 tokens\nlibrary CurrencyLibrary {\n    using CurrencyLibrary for Currency;\n\n    /// @notice Additional context for ERC-7751 wrapped error when a native transfer fails\n    error NativeTransferFailed();\n\n    /// @notice Additional context for ERC-7751 wrapped error when an ERC20 transfer fails\n    error ERC20TransferFailed();\n\n    /// @notice A constant to represent the native currency\n    Currency public constant NATIVE = Currency.wrap(address(0));\n\n    function transfer(Currency currency, address to, uint256 amount) internal {\n        // altered from https://github.com/transmissions11/solmate/blob/44a9963d4c78111f77caa0e65d677b8b46d6f2e6/src/utils/SafeTransferLib.sol\n        // modified custom error selectors\n\n        bool success;\n        if (currency.isNative()) {\n            assembly (\"memory-safe\") {\n                // Transfer the ETH and revert if it fails.\n                success := call(gas(), to, amount, 0, 0, 0, 0)\n            }\n            // revert with NativeTransferFailed, containing the bubbled up error as an argument\n            if (!success) CustomRevert.bubbleUpAndRevertWith(to, bytes4(0), NativeTransferFailed.selector);\n        } else {\n            assembly (\"memory-safe\") {\n                // Get a pointer to some free memory.\n                let fmp := mload(0x40)\n\n                // Write the abi-encoded calldata into memory, beginning with the function selector.\n                mstore(fmp, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n                mstore(add(fmp, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"to\" argument.\n                mstore(add(fmp, 36), amount) // Append the \"amount\" argument. Masking not required as it's a full 32 byte type.\n\n                success :=\n                    and(\n                        // Set success to whether the call reverted, if not we check it either\n                        // returned exactly 1 (can't just be non-zero data), or had no return data.\n                        or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                        // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n                        // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                        // Counterintuitively, this call must be positioned second to the or() call in the\n                        // surrounding and() call or else returndatasize() will be zero during the computation.\n                        call(gas(), currency, 0, fmp, 68, 0, 32)\n                    )\n\n                // Now clean the memory we used\n                mstore(fmp, 0) // 4 byte `selector` and 28 bytes of `to` were stored here\n                mstore(add(fmp, 0x20), 0) // 4 bytes of `to` and 28 bytes of `amount` were stored here\n                mstore(add(fmp, 0x40), 0) // 4 bytes of `amount` were stored here\n            }\n            // revert with ERC20TransferFailed, containing the bubbled up error as an argument\n            if (!success) {\n                CustomRevert.bubbleUpAndRevertWith(\n                    Currency.unwrap(currency), IERC20Minimal.transfer.selector, ERC20TransferFailed.selector\n                );\n            }\n        }\n    }\n\n    function balanceOfSelf(Currency currency) internal view returns (uint256) {\n        if (currency.isNative()) {\n            return address(this).balance;\n        } else {\n            return IERC20Minimal(Currency.unwrap(currency)).balanceOf(address(this));\n        }\n    }\n\n    function balanceOf(Currency currency, address owner) internal view returns (uint256) {\n        if (currency.isNative()) {\n            return owner.balance;\n        } else {\n            return IERC20Minimal(Currency.unwrap(currency)).balanceOf(owner);\n        }\n    }\n\n    function isNative(Currency currency) internal pure returns (bool) {\n        return Currency.unwrap(currency) == Currency.unwrap(NATIVE);\n    }\n\n    function toId(Currency currency) internal pure returns (uint256) {\n        return uint160(Currency.unwrap(currency));\n    }\n\n    function fromId(uint256 id) internal pure returns (Currency) {\n        return Currency.wrap(address(uint160(id)));\n    }\n}\n\n\n// File: src/types/BalanceDelta.sol\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {SafeCast} from \"../libraries/SafeCast.sol\";\n\n/// @dev Two `int128` values packed into a single `int256` where the upper 128 bits represent the amount0\n/// and the lower 128 bits represent the amount1.\ntype BalanceDelta is int256;\n\nusing {add as +, sub as -, eq as ==, neq as !=} for BalanceDelta global;\nusing BalanceDeltaLibrary for BalanceDelta global;\nusing SafeCast for int256;\n\nfunction toBalanceDelta(int128 _amount0, int128 _amount1) pure returns (BalanceDelta balanceDelta) {\n    assembly (\"memory-safe\") {\n        balanceDelta := or(shl(128, _amount0), and(sub(shl(128, 1), 1), _amount1))\n    }\n}\n\nfunction add(BalanceDelta a, BalanceDelta b) pure returns (BalanceDelta) {\n    int256 res0;\n    int256 res1;\n    assembly (\"memory-safe\") {\n        let a0 := sar(128, a)\n        let a1 := signextend(15, a)\n        let b0 := sar(128, b)\n        let b1 := signextend(15, b)\n        res0 := add(a0, b0)\n        res1 := add(a1, b1)\n    }\n    return toBalanceDelta(res0.toInt128(), res1.toInt128());\n}\n\nfunction sub(BalanceDelta a, BalanceDelta b) pure returns (BalanceDelta) {\n    int256 res0;\n    int256 res1;\n    assembly (\"memory-safe\") {\n        let a0 := sar(128, a)\n        let a1 := signextend(15, a)\n        let b0 := sar(128, b)\n        let b1 := signextend(15, b)\n        res0 := sub(a0, b0)\n        res1 := sub(a1, b1)\n    }\n    return toBalanceDelta(res0.toInt128(), res1.toInt128());\n}\n\nfunction eq(BalanceDelta a, BalanceDelta b) pure returns (bool) {\n    return BalanceDelta.unwrap(a) == BalanceDelta.unwrap(b);\n}\n\nfunction neq(BalanceDelta a, BalanceDelta b) pure returns (bool) {\n    return BalanceDelta.unwrap(a) != BalanceDelta.unwrap(b);\n}\n\n/// @notice Library for getting the amount0 and amount1 deltas from the BalanceDelta type\nlibrary BalanceDeltaLibrary {\n    /// @notice Constant for a BalanceDelta of zero value\n    BalanceDelta public constant ZERO_DELTA = BalanceDelta.wrap(0);\n\n    function amount0(BalanceDelta balanceDelta) internal pure returns (int128 _amount0) {\n        assembly (\"memory-safe\") {\n            _amount0 := sar(128, balanceDelta)\n        }\n    }\n\n    function amount1(BalanceDelta balanceDelta) internal pure returns (int128 _amount1) {\n        assembly (\"memory-safe\") {\n            _amount1 := signextend(15, balanceDelta)\n        }\n    }\n}\n\n\n// File: src/interfaces/ILockCallback.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice Interface for the callback executed when an address locks the vault\ninterface ILockCallback {\n    /// @notice Called by the pool manager on `msg.sender` when a lock is acquired\n    /// @param data The data that was passed to the call to lock\n    /// @return Any data that you want to be returned from the lock call\n    function lockAcquired(bytes calldata data) external returns (bytes memory);\n}\n\n\n// File: src/libraries/SafeCast.sol\n// SPDX-License-Identifier: GPL-2.0-or-later\n// Copyright (C) 2024 PancakeSwap\npragma solidity ^0.8.0;\n\n/// @title Safe casting methods\n/// @notice Contains methods for safely casting between types\nlibrary SafeCast {\n    error SafeCastOverflow();\n\n    function _revertOverflow() private pure {\n        assembly (\"memory-safe\") {\n            // Store the function selector of `SafeCastOverflow()`.\n            mstore(0x00, 0x93dafdf1)\n            // Revert with (offset, size).\n            revert(0x1c, 0x04)\n        }\n    }\n\n    /// @notice Cast a uint256 to a uint160, revert on overflow\n    /// @param x The uint256 to be downcasted\n    /// @return y The downcasted integer, now type uint160\n    function toUint160(uint256 x) internal pure returns (uint160 y) {\n        y = uint160(x);\n        if (y != x) _revertOverflow();\n    }\n\n    /// @notice Cast a int256 to a int128, revert on overflow or underflow\n    /// @param x The int256 to be downcasted\n    /// @return y The downcasted integer, now type int128\n    function toInt128(int256 x) internal pure returns (int128 y) {\n        y = int128(x);\n        if (y != x) _revertOverflow();\n    }\n\n    /// @notice Cast a uint256 to a int256, revert on overflow\n    /// @param x The uint256 to be casted\n    /// @return y The casted integer, now type int256\n    function toInt256(uint256 x) internal pure returns (int256 y) {\n        y = int256(x);\n        if (y < 0) _revertOverflow();\n    }\n\n    /// @notice Cast a int256 to a uint256, revert on overflow\n    /// @param x The int256 to be casted\n    /// @return y The casted integer, now type uint256\n    function toUint256(int256 x) internal pure returns (uint256 y) {\n        if (x < 0) _revertOverflow();\n        y = uint256(x);\n    }\n\n    /// @notice Cast a uint256 to a int128, revert on overflow\n    /// @param x The uint256 to be downcasted\n    /// @return The downcasted integer, now type int128\n    function toInt128(uint256 x) internal pure returns (int128) {\n        if (x >= 1 << 127) _revertOverflow();\n        return int128(int256(x));\n    }\n}\n\n\n// File: src/libraries/VaultReserve.sol\n// SPDX-License-Identifier: GPL-2.0-or-later\n// Copyright (C) 2024 PancakeSwap\npragma solidity ^0.8.24;\n\nimport {Currency} from \"../types/Currency.sol\";\n\n/// @notice This is a workaround when transient keyword is absent.\n/// It records a single reserve for a currency each time, this is helpful for\n/// calculating how many tokens has been transferred to the vault right after the sync\nlibrary VaultReserve {\n    // uint256 constant RESERVE_TYPE_SLOT = uint256(keccak256(\"reserveType\")) - 1;\n    uint256 internal constant RESERVE_TYPE_SLOT = 0x52a1be34b47478d7c75e2b6c3eea1e05dcb8dbb8c6a42c6482d0dca0df53cb27;\n\n    // uint256 constant RESERVE_AMOUNT_SLOT = uint256(keccak256(\"reserveAmount\")) - 1;\n    uint256 internal constant RESERVE_AMOUNT_SLOT = 0xb0879d96d58bcff08d1fd45590200072d5a8c380da0b5aa1052b48b84e115207;\n\n    /// @notice Transient store the currency reserve\n    /// @param currency The currency to be saved\n    /// @param amount The amount of the currency to be saved\n    function setVaultReserve(Currency currency, uint256 amount) internal {\n        assembly (\"memory-safe\") {\n            // record <currency, amount> in transient storage\n            tstore(RESERVE_TYPE_SLOT, and(currency, 0xffffffffffffffffffffffffffffffffffffffff))\n            tstore(RESERVE_AMOUNT_SLOT, amount)\n        }\n    }\n\n    /// @notice Transient load the currency reserve\n    /// @return currency The currency that was most recently saved\n    /// @return amount The amount of the currency that was most recently saved\n    function getVaultReserve() internal view returns (Currency currency, uint256 amount) {\n        assembly (\"memory-safe\") {\n            currency := tload(RESERVE_TYPE_SLOT)\n            amount := tload(RESERVE_AMOUNT_SLOT)\n        }\n    }\n}\n\n\n// File: src/VaultToken.sol\n// SPDX-License-Identifier: GPL-2.0-or-later\n// Copyright (C) 2024 PancakeSwap\npragma solidity ^0.8.0;\n\nimport {Currency} from \"./types/Currency.sol\";\nimport {IVaultToken} from \"./interfaces/IVaultToken.sol\";\n\n/// @dev This contract is a modified version of the ERC6909 implementation:\n/// 1. totalSupply is removed\n/// 2. tokenId is changed to Currency to fit our use case\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC6909.sol)\n\n/// @notice Users are allowed to store their surplus tokens i.e. unsettled balance that the pool\n/// owed to user in the vault, and they will be able to withdraw them or use them to settle future\n/// transactions. VaultToken is designed as a minimum implementation to achieve this goal. It keeps\n/// track of users' surplus tokens and allows users to approve others to spend their tokens.\nabstract contract VaultToken is IVaultToken {\n    /*//////////////////////////////////////////////////////////////\n                             ERC6909 STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    mapping(address owner => mapping(address operator => bool isOperator)) public isOperator;\n\n    mapping(address owner => mapping(Currency currency => uint256 balance)) public balanceOf;\n\n    mapping(address owner => mapping(address spender => mapping(Currency currency => uint256 amount))) public allowance;\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC6909 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function transfer(address receiver, Currency currency, uint256 amount) public virtual returns (bool) {\n        balanceOf[msg.sender][currency] -= amount;\n\n        balanceOf[receiver][currency] += amount;\n\n        emit Transfer(msg.sender, msg.sender, receiver, currency, amount);\n\n        return true;\n    }\n\n    function transferFrom(address sender, address receiver, Currency currency, uint256 amount)\n        public\n        virtual\n        returns (bool)\n    {\n        if (msg.sender != sender && !isOperator[sender][msg.sender]) {\n            uint256 allowed = allowance[sender][msg.sender][currency];\n            if (allowed != type(uint256).max) allowance[sender][msg.sender][currency] -= amount;\n        }\n\n        balanceOf[sender][currency] -= amount;\n\n        balanceOf[receiver][currency] += amount;\n\n        emit Transfer(msg.sender, sender, receiver, currency, amount);\n\n        return true;\n    }\n\n    function approve(address spender, Currency currency, uint256 amount) public virtual returns (bool) {\n        allowance[msg.sender][spender][currency] = amount;\n\n        emit Approval(msg.sender, spender, currency, amount);\n\n        return true;\n    }\n\n    function setOperator(address operator, bool approved) public virtual returns (bool) {\n        isOperator[msg.sender][operator] = approved;\n\n        emit OperatorSet(msg.sender, operator, approved);\n\n        return true;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC165 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == 0x01ffc9a7 // ERC165 Interface ID for ERC165\n            || interfaceId == 0xb2e69f8a; // ERC165 Interface ID for ERC6909\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        INTERNAL MINT/BURN LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function _mint(address receiver, Currency currency, uint256 amount) internal virtual {\n        balanceOf[receiver][currency] += amount;\n\n        emit Transfer(msg.sender, address(0), receiver, currency, amount);\n    }\n\n    function _burn(address sender, Currency currency, uint256 amount) internal virtual {\n        balanceOf[sender][currency] -= amount;\n\n        emit Transfer(msg.sender, sender, address(0), currency, amount);\n    }\n\n    function _burnFrom(address from, Currency currency, uint256 amount) internal virtual {\n        if (msg.sender != from && !isOperator[from][msg.sender]) {\n            uint256 allowed = allowance[from][msg.sender][currency];\n            if (allowed != type(uint256).max) allowance[from][msg.sender][currency] -= amount;\n        }\n\n        _burn(from, currency, amount);\n    }\n}\n\n\n// File: lib/openzeppelin-contracts/contracts/access/Ownable.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n\n// File: src/interfaces/IVaultToken.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {PoolId} from \"../types/PoolId.sol\";\nimport {PoolKey} from \"../types/PoolKey.sol\";\nimport {BalanceDelta} from \"../types/BalanceDelta.sol\";\nimport {IPoolManager} from \"./IPoolManager.sol\";\nimport {Currency} from \"../types/Currency.sol\";\n\ninterface IVaultToken {\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event OperatorSet(address indexed owner, address indexed operator, bool approved);\n\n    event Approval(address indexed owner, address indexed spender, Currency indexed currency, uint256 amount);\n\n    event Transfer(address caller, address indexed from, address indexed to, Currency indexed currency, uint256 amount);\n\n    /// @notice get the amount of owner's surplus token in vault\n    /// @param owner The address you want to query the balance of\n    /// @param currency The currency you want to query the balance of\n    /// @return balance The balance of the specified address\n    function balanceOf(address owner, Currency currency) external view returns (uint256 balance);\n\n    /// @notice get the amount that owner has authorized for spender to use\n    /// @param owner The address of the owner\n    /// @param spender The address who is allowed to spend the owner's token\n    /// @param currency The currency the spender is allowed to spend\n    /// @return amount The amount of token the spender is allowed to spend\n    function allowance(address owner, address spender, Currency currency) external view returns (uint256 amount);\n\n    /// @notice approve spender for using user's token\n    /// @param spender The address msg.sender is approving to spend the his token\n    /// @param currency The currency the spender is allowed to spend\n    /// @param amount The amount of token the spender is allowed to spend\n    /// @return bool Whether the approval was successful or not\n    function approve(address spender, Currency currency, uint256 amount) external returns (bool);\n\n    /// @notice transfer msg.sender's token to someone else\n    /// @param to The address to transfer the token to\n    /// @param currency The currency to transfer\n    /// @param amount The amount of token to transfer\n    /// @return bool Whether the transfer was successful or not\n    function transfer(address to, Currency currency, uint256 amount) external returns (bool);\n\n    /// @notice transfer from address's token on behalf of him\n    /// @param from The address to transfer the token from\n    /// @param to The address to transfer the token to\n    /// @param currency The currency to transfer\n    /// @param amount The amount of token to transfer\n    /// @return bool Whether the transfer was successful or not\n    function transferFrom(address from, address to, Currency currency, uint256 amount) external returns (bool);\n}\n\n\n// File: src/interfaces/IERC20Minimal.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Minimal ERC20 interface for PancakeSwap\n/// @notice Contains a subset of the full ERC20 interface that is used in PancakeSwap V3\ninterface IERC20Minimal {\n    /// @notice Returns the balance of a token\n    /// @param account The account for which to look up the number of tokens it has, i.e. its balance\n    /// @return The number of tokens held by the account\n    function balanceOf(address account) external view returns (uint256);\n\n    /// @notice Transfers the amount of token from the `msg.sender` to the recipient\n    /// @param recipient The account that will receive the amount transferred\n    /// @param amount The number of tokens to send from the sender to the recipient\n    /// @return Returns true for a successful transfer, false for an unsuccessful transfer\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /// @notice Returns the current allowance given to a spender by an owner\n    /// @param owner The account of the token owner\n    /// @param spender The account of the token spender\n    /// @return The current allowance granted by `owner` to `spender`\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount`\n    /// @param spender The account which will be allowed to spend a given amount of the owners tokens\n    /// @param amount The amount of tokens allowed to be used by `spender`\n    /// @return Returns true for a successful approval, false for unsuccessful\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender`\n    /// @param sender The account from which the transfer will be initiated\n    /// @param recipient The recipient of the transfer\n    /// @param amount The amount of the transfer\n    /// @return Returns true for a successful transfer, false for unsuccessful\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`.\n    /// @param from The account from which the tokens were sent, i.e. the balance decreased\n    /// @param to The account to which the tokens were sent, i.e. the balance increased\n    /// @param value The amount of tokens that were transferred\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes.\n    /// @param owner The account that approved spending of its tokens\n    /// @param spender The account for which the spending allowance was modified\n    /// @param value The new allowance from the owner to the spender\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n\n\n// File: src/libraries/CustomRevert.sol\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title Library for reverting with custom errors efficiently\n/// @notice Contains functions for reverting with custom errors with different argument types efficiently\n/// @dev The functions may tamper with the free memory pointer but it is fine since the call context is exited immediately\nlibrary CustomRevert {\n    /// @dev ERC-7751 error for wrapping bubbled up reverts\n    error WrappedError(address target, bytes4 selector, bytes reason, bytes details);\n\n    /// @notice bubble up the revert message returned by a call and revert with a wrapped ERC-7751 error\n    /// @dev this method can be vulnerable to revert data bombs\n    function bubbleUpAndRevertWith(\n        address revertingContract,\n        bytes4 revertingFunctionSelector,\n        bytes4 additionalContext\n    ) internal pure {\n        bytes4 wrappedErrorSelector = WrappedError.selector;\n        assembly (\"memory-safe\") {\n            // Ensure the size of the revert data is a multiple of 32 bytes\n            let encodedDataSize := mul(div(add(returndatasize(), 31), 32), 32)\n\n            let fmp := mload(0x40)\n\n            // Encode wrapped error selector, address, function selector, offset, additional context, size, revert reason\n            mstore(fmp, wrappedErrorSelector)\n            mstore(add(fmp, 0x04), and(revertingContract, 0xffffffffffffffffffffffffffffffffffffffff))\n            mstore(\n                add(fmp, 0x24),\n                and(revertingFunctionSelector, 0xffffffff00000000000000000000000000000000000000000000000000000000)\n            )\n            // offset revert reason\n            mstore(add(fmp, 0x44), 0x80)\n            // offset additional context\n            mstore(add(fmp, 0x64), add(0xa0, encodedDataSize))\n            // size revert reason\n            mstore(add(fmp, 0x84), returndatasize())\n            // revert reason\n            returndatacopy(add(fmp, 0xa4), 0, returndatasize())\n            // size additional context\n            mstore(add(fmp, add(0xa4, encodedDataSize)), 0x04)\n            // additional context\n            mstore(\n                add(fmp, add(0xc4, encodedDataSize)),\n                and(additionalContext, 0xffffffff00000000000000000000000000000000000000000000000000000000)\n            )\n            revert(fmp, add(0xe4, encodedDataSize))\n        }\n    }\n}\n\n\n// File: lib/openzeppelin-contracts/contracts/utils/Context.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n\n\n// File: src/types/PoolId.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {PoolKey} from \"./PoolKey.sol\";\n\ntype PoolId is bytes32;\n\n/// @notice Library for computing the ID of a pool\nlibrary PoolIdLibrary {\n    function toId(PoolKey memory poolKey) internal pure returns (PoolId poolId) {\n        assembly (\"memory-safe\") {\n            // 0xc0 represents the total size of the poolKey struct (6 slots of 32 bytes)\n            poolId := keccak256(poolKey, 0xc0)\n        }\n    }\n}\n\n\n// File: src/types/PoolKey.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Currency} from \"./Currency.sol\";\nimport {IPoolManager} from \"../interfaces/IPoolManager.sol\";\nimport {IHooks} from \"../interfaces/IHooks.sol\";\nimport {PoolIdLibrary} from \"./PoolId.sol\";\n\nusing PoolIdLibrary for PoolKey global;\n\n/// @notice Returns the key for identifying a pool\nstruct PoolKey {\n    /// @notice The lower currency of the pool, sorted numerically\n    Currency currency0;\n    /// @notice The higher currency of the pool, sorted numerically\n    Currency currency1;\n    /// @notice The hooks of the pool, won't have a general interface because hooks interface vary on pool type\n    IHooks hooks;\n    /// @notice The pool manager of the pool\n    IPoolManager poolManager;\n    /// @notice The pool lp fee, capped at 1_000_000. If the pool has a dynamic fee then it must be exactly equal to 0x800000\n    uint24 fee;\n    /// @notice Hooks callback and pool specific parameters, i.e. tickSpacing for CL, binStep for bin\n    bytes32 parameters;\n}\n\n\n// File: src/interfaces/IPoolManager.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IHooks} from \"./IHooks.sol\";\nimport {PoolKey} from \"../types/PoolKey.sol\";\nimport {PoolId} from \"../types/PoolId.sol\";\nimport {Currency} from \"../types/Currency.sol\";\n\ninterface IPoolManager {\n    /// @notice Thrown when trying to interact with a non-initialized pool\n    error PoolNotInitialized();\n\n    /// @notice PoolKey must have currencies where address(currency0) < address(currency1)\n    error CurrenciesInitializedOutOfOrder(address currency0, address currency1);\n\n    /// @notice Thrown when a call to updateDynamicLPFee is made by an address that is not the hook,\n    /// or on a pool is not a dynamic fee pool.\n    error UnauthorizedDynamicLPFeeUpdate();\n\n    /// @notice Emitted when lp fee is updated\n    /// @dev The event is emitted even if the updated fee value is the same as previous one\n    event DynamicLPFeeUpdated(PoolId indexed id, uint24 dynamicLPFee);\n\n    /// @notice Updates lp fee for a dyanmic fee pool\n    /// @dev Some of the use case could be:\n    ///   1) when hook#beforeSwap() is called and hook call this function to update the lp fee\n    ///   2) For BinPool only, when hook#beforeMint() is called and hook call this function to update the lp fee\n    ///   3) other use case where the hook might want to on an ad-hoc basis increase/reduce lp fee\n    function updateDynamicLPFee(PoolKey memory key, uint24 newDynamicLPFee) external;\n\n    /// @notice Return PoolKey for a given PoolId\n    function poolIdToPoolKey(PoolId id)\n        external\n        view\n        returns (\n            Currency currency0,\n            Currency currency1,\n            IHooks hooks,\n            IPoolManager poolManager,\n            uint24 fee,\n            bytes32 parameters\n        );\n}\n\n\n// File: src/interfaces/IHooks.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IHooks {\n    function getHooksRegistrationBitmap() external view returns (uint16);\n}\n","source_code_hash":null,"compiler_version":"v0.8.26+commit.8a97fa7a","optimization_used":"1","runs":25666,"abi":"[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AppUnregistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CurrencyNotSettled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeCurrencySynced\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"locker\",\"type\":\"address\"}],\"name\":\"LockerAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustClearExactPositiveDelta\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoLocker\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SettleNonNativeCurrencyWithValue\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"app\",\"type\":\"address\"}],\"name\":\"AppRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"OperatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Currency\",\"name\":\"currency0\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency1\",\"type\":\"address\"},{\"internalType\":\"BalanceDelta\",\"name\":\"delta\",\"type\":\"int256\"},{\"internalType\":\"address\",\"name\":\"settler\",\"type\":\"address\"},{\"internalType\":\"BalanceDelta\",\"name\":\"hookDelta\",\"type\":\"int256\"},{\"internalType\":\"address\",\"name\":\"hook\",\"type\":\"address\"}],\"name\":\"accountAppBalanceDelta\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"internalType\":\"int128\",\"name\":\"delta\",\"type\":\"int128\"},{\"internalType\":\"address\",\"name\":\"settler\",\"type\":\"address\"}],\"name\":\"accountAppBalanceDelta\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Currency\",\"name\":\"currency0\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency1\",\"type\":\"address\"},{\"internalType\":\"BalanceDelta\",\"name\":\"delta\",\"type\":\"int256\"},{\"internalType\":\"address\",\"name\":\"settler\",\"type\":\"address\"}],\"name\":\"accountAppBalanceDelta\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"clear\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"collectFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"settler\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"}],\"name\":\"currencyDelta\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLocker\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUnsettledDeltasCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getVaultReserve\",\"outputs\":[{\"internalType\":\"Currency\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"app\",\"type\":\"address\"}],\"name\":\"isAppRegistered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isRegistered\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isOperator\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isOperator\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"lock\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"result\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"app\",\"type\":\"address\"}],\"name\":\"registerApp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"app\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"}],\"name\":\"reservesOfApp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"reserve\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setOperator\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"settle\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"settleFor\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"}],\"name\":\"sync\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"take\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"Currency\",\"name\":\"currency\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]","contract_file_name":"src/Vault.sol","compiler_type":"solc-j","evm_version":"cancun","constructor_arguments":null,"library":null,"license_type":null,"critical_count":0,"high_count":0,"medium_count":0,"low_count":2,"informational_count":0,"audit_status":"completed","audit_completed_at":"1783011207643","erc20_balances":[]}}