Source Code
Overview
S Balance
0 S
More Info
ContractCreator
Loading...
Loading
Contract Name:
LBHooksMCRewarder
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 600 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IERC20Metadata, IERC20} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import {LBHooksBaseParentRewarder, LBHooksBaseRewarder} from "lb-rewarder/LBHooksBaseParentRewarder.sol"; import {TokenHelper} from "lb-rewarder/library/TokenHelper.sol"; import {ILBHooksMCRewarder} from "./interfaces/ILBHooksMCRewarder.sol"; import {IMasterChef, IMasterChefRewarder} from "./interfaces/IMasterChef_flat.sol"; /** * @title LB Hooks MagicSea MasterChef Rewarder * @dev Main contract for the LB Hooks Rewarder * This contract will be used as a sink on the masterchef to receive METRO rewards and distribute them to the LPs * It can also have an extra rewarder to distribute a second token to the LPs * It will reward the LPs that are inside the range set in this contract */ contract LBHooksMCRewarder is LBHooksBaseParentRewarder, ERC20Upgradeable, ILBHooksMCRewarder { IMasterChef internal immutable _masterChef; IERC20 internal immutable _metro; /** * @dev Constructor of the contract * @param lbHooksManager The address of the LBHooksManager contract * @param masterChef The address of the MasterChef contract * @param metro The address of the METRO token */ constructor(address lbHooksManager, IMasterChef masterChef, IERC20 metro) LBHooksBaseRewarder(lbHooksManager) { _masterChef = masterChef; _metro = metro; } /** * @dev Returns the pool id used to reward the LPs * @return pid The pool id */ function getPid() external view virtual override returns (uint256 pid) { return _getPid(); } /** * @dev Returns the MasterChef contract * @return masterChef The MasterChef contract */ function getMasterChef() external view virtual override returns (IMasterChef masterChef) { return _masterChef; } /** * @dev Internal function to get the pool id used to reward the LPs * @return pid The pool id */ function _getPid() internal pure virtual returns (uint256 pid) { return _getArgUint256(20); } /** * @dev Override the internal function to get the reward token as it's always the MOE token * @return rewardToken The moe token */ function _getRewardToken() internal view virtual override returns (IERC20 rewardToken) { return _metro; } /** * @dev Override the internal function to get the pending total rewards * Will call the MasterChef's getPendingRewards function to get the pending MOE rewards * @return pendingTotalRewards The pending total rewards */ function _getPendingTotalRewards() internal view virtual override returns (uint256 pendingTotalRewards) { uint256[] memory pids = new uint256[](1); pids[0] = _getPid(); (uint256[] memory metroRewards,,) = _masterChef.getPendingRewards(address(this), pids); uint256 remainingBalance = TokenHelper.safeBalanceOf(_getRewardToken(), address(this)) - _totalUnclaimedRewards; return metroRewards[0] + remainingBalance; } /** * @dev Override the internal function to update the rewards * Will call the MasterChef's deposit function to update the rewards * @return pendingTotalRewards The pending total rewards */ function _updateRewards() internal virtual override returns (uint256 pendingTotalRewards) { uint256[] memory pids = new uint[](1); pids[0] = _getPid(); _masterChef.claim(pids); uint256 balance = TokenHelper.safeBalanceOf(_getRewardToken(), address(this)); pendingTotalRewards = balance - _totalUnclaimedRewards; return pendingTotalRewards; } /** * @dev Override the internal function that is called when the hooks are set * Will set the symbol and name of this contract, while also minting 1 token * and depositing it on the MasterChef * @param data The data to be used on the hooks set */ function _onHooksSet(bytes calldata data) internal virtual override { (, IERC20Metadata tokenX, IERC20Metadata tokenY, uint16 binStep) = abi.decode(data, (address, IERC20Metadata, IERC20Metadata, uint16)); string memory symbolX = tokenX.symbol(); string memory symbolY = tokenY.symbol(); string memory symbol = string(abi.encodePacked("Vote LB ", symbolX, "-", symbolY, ":", Strings.toString(binStep))); string memory name = "LB Hooks Metro Rewarder"; __ERC20_init(name, symbol); _mint(address(this), 1); _approve(address(this), address(_masterChef), 1); _masterChef.deposit(_getPid(), 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC-20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol"; import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC-20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the ERC may not emit * these events, as it isn't required by the specification. */ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors { /// @custom:storage-location erc7201:openzeppelin.storage.ERC20 struct ERC20Storage { mapping(address account => uint256) _balances; mapping(address account => mapping(address spender => uint256)) _allowances; uint256 _totalSupply; string _name; string _symbol; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00; function _getERC20Storage() private pure returns (ERC20Storage storage $) { assembly { $.slot := ERC20StorageLocation } } /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { ERC20Storage storage $ = _getERC20Storage(); $._name = name_; $._symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); return $._name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); return $._symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `value`. */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the ERC. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `value`. * - the caller must have allowance for ``from``'s tokens of at least * `value`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, value); _transfer(from, to, value); return true; } /** * @dev Moves a `value` amount of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _transfer(address from, address to, uint256 value) internal { if (from == address(0)) { revert ERC20InvalidSender(address(0)); } if (to == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(from, to, value); } /** * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding * this function. * * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { ERC20Storage storage $ = _getERC20Storage(); if (from == address(0)) { // Overflow check required: The rest of the code assumes that totalSupply never overflows $._totalSupply += value; } else { uint256 fromBalance = $._balances[from]; if (fromBalance < value) { revert ERC20InsufficientBalance(from, fromBalance, value); } unchecked { // Overflow not possible: value <= fromBalance <= totalSupply. $._balances[from] = fromBalance - value; } } if (to == address(0)) { unchecked { // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. $._totalSupply -= value; } } else { unchecked { // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. $._balances[to] += value; } } emit Transfer(from, to, value); } /** * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(address(0), account, value); } /** * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead */ function _burn(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidSender(address(0)); } _update(account, address(0), value); } /** * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address owner, address spender, uint256 value) internal { _approve(owner, spender, value, true); } /** * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. * * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any * `Approval` event during `transferFrom` operations. * * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to * true using the following override: * ``` * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { ERC20Storage storage $ = _getERC20Storage(); if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } $._allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Hooks} from "@lb-protocol/src/libraries/Hooks.sol"; import {LBHooksBaseRewarder, ILBHooksBaseRewarder} from "./LBHooksBaseRewarder.sol"; import {ILBHooksBaseParentRewarder} from "./interfaces/ILBHooksBaseParentRewarder.sol"; import {ILBHooksExtraRewarder} from "./interfaces/ILBHooksExtraRewarder.sol"; /** * @title LB Hooks Base Parent Rewarder * @dev This contract allows to set a second rewarder that will be used to distribute a second token to the LPs */ abstract contract LBHooksBaseParentRewarder is LBHooksBaseRewarder, ILBHooksBaseParentRewarder { bytes32 internal _extraHooksParameters; /** * @dev Returns the extra hooks parameters * @return extraHooksParameters The extra hooks parameters */ function getExtraHooksParameters() external view virtual override returns (bytes32 extraHooksParameters) { return _extraHooksParameters; } /** * @dev Sets the LB Hooks Extra Rewarder * @param lbHooksExtraRewarder The address of the LB Hooks Extra Rewarder * @param extraRewarderData The data to be used on the LB Hooks Extra Rewarder */ function setLBHooksExtraRewarder(address lbHooksExtraRewarder, bytes calldata extraRewarderData) external virtual override { if (msg.sender != _lbHooksManager) _checkOwner(); if (lbHooksExtraRewarder != address(0)) { bytes32 extraHooksParameters = Hooks.setHooks(FLAGS, lbHooksExtraRewarder); _extraHooksParameters = extraHooksParameters; if ( ILBHooksExtraRewarder(lbHooksExtraRewarder).getLBPair() != _getLBPair() || address(ILBHooksExtraRewarder(lbHooksExtraRewarder).getParentRewarder()) != address(this) ) { revert LBHooksRewarder__InvalidLBHooksExtraRewarder(); } Hooks.onHooksSet(extraHooksParameters, extraRewarderData); } else { _extraHooksParameters = 0; } emit LBHooksExtraRewarderSet(lbHooksExtraRewarder); } /** * @dev Override the internal function that is called when the rewards are claimed * Will call the extra rewarder's claim function if the extra rewarder is set * @param user The address of the user * @param ids The ids of the LP tokens */ function _onClaim(address user, uint256[] memory ids) internal virtual override { bytes32 extraHooksParameters = _extraHooksParameters; if (extraHooksParameters != 0) ILBHooksBaseRewarder(Hooks.getHooks(extraHooksParameters)).claim(user, ids); } /** * @dev Override the internal function that is called before a swap on the LB pair * Will call the extra rewarder's beforeSwap function if the extra rewarder is set * @param sender The address of the sender * @param to The address of the receiver * @param swapForY Whether the swap is for token Y * @param amountsIn The amounts in */ function _beforeSwap(address sender, address to, bool swapForY, bytes32 amountsIn) internal virtual override { super._beforeSwap(sender, to, swapForY, amountsIn); Hooks.beforeSwap(_extraHooksParameters, sender, to, swapForY, amountsIn); } /** * @dev Override the internal function that is called before a mint on the LB pair * Will call the extra rewarder's beforeMint function if the extra rewarder is set * @param from The address of the sender * @param to The address of the receiver * @param liquidityConfigs The liquidity configs * @param amountsReceived The amounts received */ function _beforeMint(address from, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsReceived) internal virtual override { super._beforeMint(from, to, liquidityConfigs, amountsReceived); Hooks.beforeMint(_extraHooksParameters, from, to, liquidityConfigs, amountsReceived); } /** * @dev Override the internal function that is called before a burn on the LB pair * Will call the extra rewarder's beforeBurn function if the extra rewarder is set * @param sender The address of the sender * @param from The address of the sender * @param to The address of the receiver * @param ids The ids of the LP tokens * @param amountsToBurn The amounts to burn */ function _beforeBurn( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn ) internal virtual override { super._beforeBurn(sender, from, to, ids, amountsToBurn); Hooks.beforeBurn(_extraHooksParameters, sender, from, to, ids, amountsToBurn); } /** * @dev Override the internal function that is called before a transfer on the LB pair * Will call the extra rewarder's beforeBatchTransferFrom function if the extra rewarder is set * @param sender The address of the sender * @param from The address of the sender * @param to The address of the receiver * @param ids The list of ids * @param amounts The list of amounts */ function _beforeBatchTransferFrom( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amounts ) internal virtual override { super._beforeBatchTransferFrom(sender, from, to, ids, amounts); Hooks.beforeBatchTransferFrom(_extraHooksParameters, sender, from, to, ids, amounts); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title Token Helper * @dev Helper library to handle ERC20 and native tokens */ library TokenHelper { using SafeERC20 for IERC20; error TokenHelper__NativeTransferFailed(); /** * @dev Helper function to return the balance of an account for the given token * address(0) is used for native tokens * @param token The address of the token * @param account The address of the account * @return The balance of this contract for the given token */ function safeBalanceOf(IERC20 token, address account) internal view returns (uint256) { return address(token) == address(0) ? address(account).balance : token.balanceOf(account); } /** * @dev Helper function to transfer the given amount of tokens to the given address * address(0) is used for native tokens * @param token The address of the token * @param to The address of the recipient * @param amount The amount of tokens */ function safeTransfer(IERC20 token, address to, uint256 amount) internal { if (amount > 0) { if (address(token) == address(0)) { (bool s,) = to.call{value: amount}(""); if (!s) revert TokenHelper__NativeTransferFailed(); } else { token.safeTransfer(to, amount); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IMasterChef} from "./IMasterChef_flat.sol"; import {LBHooksBaseParentRewarder, LBHooksBaseRewarder} from "lb-rewarder/LBHooksBaseParentRewarder.sol"; import {ILBHooksBaseRewarder} from "lb-rewarder/interfaces/ILBHooksBaseRewarder.sol"; import {ILBHooksExtraRewarder} from "lb-rewarder/interfaces/ILBHooksExtraRewarder.sol"; /** * @title LB Hooks Rewarder Interface * @dev Interface for the LB Hooks Rewarder */ interface ILBHooksMCRewarder is ILBHooksBaseRewarder { function getPid() external view returns (uint256 pid); function getMasterChef() external view returns (IMasterChef masterChef); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // src/libraries/Constants.sol /** * @title Constants Library * @dev A library that defines various constants used throughout the codebase. */ library Constants { uint256 internal constant ACC_PRECISION_BITS = 64; uint256 internal constant PRECISION = 1e18; uint256 internal constant MAX_NUMBER_OF_FARMS = 32; uint256 internal constant MAX_NUMBER_OF_REWARDS = 32; uint256 internal constant MAX_LUM_PER_SECOND = 10e18; uint256 internal constant MAX_BRIBES_PER_POOL = 5; } // src/libraries/Math.sol /** * @title Math * @dev Library for mathematical operations with overflow and underflow checks. */ library Math { error Math__UnderOverflow(); uint256 internal constant MAX_INT256 = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; /** * @dev Adds a signed integer to an unsigned integer with overflow check. * The result must be greater than or equal to 0 and less than or equal to MAX_INT256. * @param x Unsigned integer to add to. * @param delta Signed integer to add. * @return y The result of the addition. */ function addDelta(uint256 x, int256 delta) internal pure returns (uint256 y) { uint256 success; assembly { y := add(x, delta) success := iszero(or(gt(x, MAX_INT256), gt(y, MAX_INT256))) } if (success == 0) revert Math__UnderOverflow(); } /** * @dev Safely converts an unsigned integer to a signed integer. * @param x Unsigned integer to convert. * @return y Signed integer result. */ function toInt256(uint256 x) internal pure returns (int256 y) { if (x > MAX_INT256) revert Math__UnderOverflow(); return int256(x); } } // src/interfaces/IMetro.sol interface IMetro is IERC20 { function mint(address account, uint256 amount) external returns (uint256); } // src/interfaces/IRewarder.sol interface IRewarder { function getToken() external view returns (IERC20); function getCaller() external view returns (address); function initialize(address initialOwner) external; } // src/libraries/Amounts.sol /** * @title Amounts Library * @dev A library that defines various functions for manipulating amounts of a key and a total. * The key can be bytes32, address, or uint256. */ library Amounts { using Math for uint256; struct Parameter { uint256 totalAmount; mapping(bytes32 => uint256) amounts; } /** * @dev Returns the amount of a key. * @param amounts The storage pointer to the amounts. * @param key The key of the amount. * @return The amount of the key. */ function getAmountOf(Parameter storage amounts, bytes32 key) internal view returns (uint256) { return amounts.amounts[key]; } /** * @dev Returns the amount of an address. * @param amounts The storage pointer to the amounts. * @param account The address of the amount. * @return The amount of the address. */ function getAmountOf(Parameter storage amounts, address account) internal view returns (uint256) { return getAmountOf(amounts, bytes32(uint256(uint160(account)))); } /** * @dev Returns the amount of an id. * @param amounts The storage pointer to the amounts. * @param id The id of the amount. * @return The amount of the id. */ function getAmountOf(Parameter storage amounts, uint256 id) internal view returns (uint256) { return getAmountOf(amounts, bytes32(id)); } /** * @dev Returns the total amount. * @param amounts The storage pointer to the amounts. * @return The total amount. */ function getTotalAmount(Parameter storage amounts) internal view returns (uint256) { return amounts.totalAmount; } /** * @dev Updates the amount of a key. The delta is added to the key amount and the total amount. * @param amounts The storage pointer to the amounts. * @param key The key of the amount. * @param deltaAmount The delta amount to update. * @return oldAmount The old amount of the key. * @return newAmount The new amount of the key. * @return oldTotalAmount The old total amount. * @return newTotalAmount The new total amount. */ function update(Parameter storage amounts, bytes32 key, int256 deltaAmount) internal returns (uint256 oldAmount, uint256 newAmount, uint256 oldTotalAmount, uint256 newTotalAmount) { oldAmount = amounts.amounts[key]; oldTotalAmount = amounts.totalAmount; if (deltaAmount == 0) { newAmount = oldAmount; newTotalAmount = oldTotalAmount; } else { newAmount = oldAmount.addDelta(deltaAmount); newTotalAmount = oldTotalAmount.addDelta(deltaAmount); amounts.amounts[key] = newAmount; amounts.totalAmount = newTotalAmount; } } /** * @dev Updates the amount of an address. The delta is added to the address amount and the total amount. * @param amounts The storage pointer to the amounts. * @param account The address of the amount. * @param deltaAmount The delta amount to update. * @return oldAmount The old amount of the key. * @return newAmount The new amount of the key. * @return oldTotalAmount The old total amount. * @return newTotalAmount The new total amount. */ function update(Parameter storage amounts, address account, int256 deltaAmount) internal returns (uint256 oldAmount, uint256 newAmount, uint256 oldTotalAmount, uint256 newTotalAmount) { return update(amounts, bytes32(uint256(uint160(account))), deltaAmount); } /** * @dev Updates the amount of an id. The delta is added to the id amount and the total amount. * @param amounts The storage pointer to the amounts. * @param id The id of the amount. * @param deltaAmount The delta amount to update. * @return oldAmount The old amount of the key. * @return newAmount The new amount of the key. * @return oldTotalAmount The old total amount. * @return newTotalAmount The new total amount. */ function update(Parameter storage amounts, uint256 id, int256 deltaAmount) internal returns (uint256 oldAmount, uint256 newAmount, uint256 oldTotalAmount, uint256 newTotalAmount) { return update(amounts, bytes32(id), deltaAmount); } } // src/interfaces/IBaseRewarder.sol interface IBaseRewarder is IRewarder { error BaseRewarder__NativeTransferFailed(); error BaseRewarder__InvalidCaller(); error BaseRewarder__Stopped(); error BaseRewarder__AlreadyStopped(); error BaseRewarder__NotNativeRewarder(); error BaseRewarder__ZeroAmount(); error BaseRewarder__ZeroReward(); error BaseRewarder__InvalidDuration(); error BaseRewarder__InvalidPid(uint256 pid); error BaseRewarder__InvalidStartTimestamp(uint256 startTimestamp); error BaseRewarder__CannotRenounceOwnership(); event Claim(address indexed account, IERC20 indexed token, uint256 reward); event RewardParameterUpdated(uint256 rewardPerSecond, uint256 startTimestamp, uint256 endTimestamp); event Stopped(); event Swept(IERC20 indexed token, address indexed account, uint256 amount); function getToken() external view returns (IERC20); function getCaller() external view returns (address); function getPid() external view returns (uint256); function getRewarderParameter() external view returns (IERC20 token, uint256 rewardPerSecond, uint256 lastUpdateTimestamp, uint256 endTimestamp); function getRemainingReward() external view returns (uint256); function getPendingReward(address account, uint256 balance, uint256 totalSupply) external view returns (IERC20 token, uint256 pendingReward); function isStopped() external view returns (bool); function initialize(address initialOwner) external; function setRewardPerSecond(uint256 maxRewardPerSecond, uint256 expectedDuration) external returns (uint256 rewardPerSecond); function setRewarderParameters(uint256 maxRewardPerSecond, uint256 startTimestamp, uint256 expectedDuration) external returns (uint256 rewardPerSecond); function stop() external; function sweep(IERC20 token, address account) external; function onModify(address account, uint256 pid, uint256 oldBalance, uint256 newBalance, uint256 totalSupply) external returns (uint256); } // src/interfaces/IBribeRewarder.sol interface IBribeRewarder is IRewarder { error BribeRewarder__OnlyVoter(); error BribeRewarder__InsufficientFunds(); error BribeRewarder__WrongStartId(); error BribeRewarder__WrongEndId(); error BribeRewarder__ZeroReward(); error BribeRewarder__NativeTransferFailed(); error BribeRewarder__NotOwner(); error BribeRewarder__CannotRenounceOwnership(); error BribeRewarder__NotNativeRewarder(); error BribeRewarder__AlreadyInitialized(); error BribeRewarder__PeriodNotFound(); event Claimed(uint256 indexed tokenId, address indexed pool, uint256 amount); event Deposited(uint256 indexed periodId, uint256 indexed tokenId, address indexed pool, uint256 amount); event BribeInit(uint256 indexed startId, uint256 indexed lastId, uint256 amountPerPeriod); function bribe(uint256 startId, uint256 lastId, uint256 amountPerPeriod) external; function claim(uint256 tokenId) external; function deposit(uint256 periodId, uint256 tokenId, uint256 deltaAmount) external; function getPool() external view returns (address); function getPendingReward(uint256 tokenId) external view returns (uint256); function getBribePeriods() external view returns (address pool, uint256[] memory); function getStartVotingPeriodId() external view returns (uint256); function getLastVotingPeriodId() external view returns (uint256); function getAmountPerPeriod() external view returns (uint256); } // src/interfaces/IMasterChefRewarder.sol interface IMasterChefRewarder is IBaseRewarder { error MasterChefRewarder__AlreadyLinked(); error MasterChefRewarder__NotLinked(); error MasterChefRewarder__UseUnlink(); enum Status { Unlinked, Linked, Stopped } function link(uint256 pid) external; function unlink(uint256 pid) external; } // src/libraries/Rewarder.sol /** * @title Rewarder Library * @dev A library that defines various functions for calculating rewards. * It takes care about the reward debt and the accumulated debt per share. */ library Rewarder { using Amounts for Amounts.Parameter; struct Parameter { uint256 lastUpdateTimestamp; uint256 accDebtPerShare; mapping(address => uint256) debt; } /** * @dev Returns the debt associated with an amount. * @param accDebtPerShare The accumulated debt per share. * @param deposit The amount. * @return The debt associated with the amount. */ function getDebt(uint256 accDebtPerShare, uint256 deposit) internal pure returns (uint256) { return (deposit * accDebtPerShare) >> Constants.ACC_PRECISION_BITS; } /** * @dev Returns the debt per share associated with a total deposit and total rewards. * @param totalDeposit The total deposit. * @param totalRewards The total rewards. * @return The debt per share associated with the total deposit and total rewards. */ function getDebtPerShare(uint256 totalDeposit, uint256 totalRewards) internal pure returns (uint256) { return totalDeposit == 0 ? 0 : (totalRewards << Constants.ACC_PRECISION_BITS) / totalDeposit; } /** * @dev Returns the total rewards to emit. * If the end timestamp is in the past, the rewards are calculated up to the end timestamp. * If the last update timestamp is in the future, it will return 0. * @param rewarder The storage pointer to the rewarder. * @param rewardPerSecond The reward per second. * @param endTimestamp The end timestamp. * @param totalSupply The total supply. * @return The total rewards. */ function getTotalRewards( Parameter storage rewarder, uint256 rewardPerSecond, uint256 endTimestamp, uint256 totalSupply ) internal view returns (uint256) { if (totalSupply == 0) return 0; uint256 lastUpdateTimestamp = rewarder.lastUpdateTimestamp; uint256 timestamp = block.timestamp > endTimestamp ? endTimestamp : block.timestamp; return timestamp > lastUpdateTimestamp ? (timestamp - lastUpdateTimestamp) * rewardPerSecond : 0; } /** * @dev Returns the total rewards to emit. * @param rewarder The storage pointer to the rewarder. * @param rewardPerSecond The reward per second. * @param totalSupply The total supply. * @return The total rewards. */ function getTotalRewards(Parameter storage rewarder, uint256 rewardPerSecond, uint256 totalSupply) internal view returns (uint256) { return getTotalRewards(rewarder, rewardPerSecond, block.timestamp, totalSupply); } /** * @dev Returns the pending reward of an account. * @param rewarder The storage pointer to the rewarder. * @param amounts The storage pointer to the amounts. * @param account The address of the account. * @param totalRewards The total rewards. * @return The pending reward of the account. */ function getPendingReward( Parameter storage rewarder, Amounts.Parameter storage amounts, address account, uint256 totalRewards ) internal view returns (uint256) { return getPendingReward(rewarder, account, amounts.getAmountOf(account), amounts.getTotalAmount(), totalRewards); } /** * @dev Returns the pending reward of an account. * If the balance of the account is 0, it will always return 0. * @param rewarder The storage pointer to the rewarder. * @param account The address of the account. * @param balance The balance of the account. * @param totalSupply The total supply. * @param totalRewards The total rewards. * @return The pending reward of the account. */ function getPendingReward( Parameter storage rewarder, address account, uint256 balance, uint256 totalSupply, uint256 totalRewards ) internal view returns (uint256) { uint256 accDebtPerShare = rewarder.accDebtPerShare + getDebtPerShare(totalSupply, totalRewards); return balance == 0 ? 0 : getDebt(accDebtPerShare, balance) - rewarder.debt[account]; } /** * @dev Updates the rewarder. * If the balance of the account is 0, it will always return 0. * @param rewarder The storage pointer to the rewarder. * @param account The address of the account. * @param oldBalance The old balance of the account. * @param newBalance The new balance of the account. * @param totalSupply The total supply. * @param totalRewards The total rewards. * @return rewards The rewards of the account. */ function update( Parameter storage rewarder, address account, uint256 oldBalance, uint256 newBalance, uint256 totalSupply, uint256 totalRewards ) internal returns (uint256 rewards) { uint256 accDebtPerShare = updateAccDebtPerShare(rewarder, totalSupply, totalRewards); rewards = oldBalance == 0 ? 0 : getDebt(accDebtPerShare, oldBalance) - rewarder.debt[account]; rewarder.debt[account] = getDebt(accDebtPerShare, newBalance); } /** * @dev Updates the accumulated debt per share. * If the last update timestamp is in the future, it will not update the last update timestamp. * @param rewarder The storage pointer to the rewarder. * @param totalSupply The total supply. * @param totalRewards The total rewards. * @return The accumulated debt per share. */ function updateAccDebtPerShare(Parameter storage rewarder, uint256 totalSupply, uint256 totalRewards) internal returns (uint256) { uint256 debtPerShare = getDebtPerShare(totalSupply, totalRewards); if (block.timestamp > rewarder.lastUpdateTimestamp) rewarder.lastUpdateTimestamp = block.timestamp; return debtPerShare == 0 ? rewarder.accDebtPerShare : rewarder.accDebtPerShare += debtPerShare; } } // src/interfaces/IRewarderFactory.sol interface IRewarderFactory { error RewarderFactory__ZeroAddress(); error RewarderFactory__InvalidRewarderType(); error RewarderFactory__InvalidPid(); enum RewarderType { InvalidRewarder, MasterChefRewarder, VeMoeRewarder, JoeStakingRewarder, BribeRewarder } event RewarderCreated( RewarderType indexed rewarderType, IERC20 indexed token, uint256 indexed pid, IBaseRewarder rewarder ); event BribeRewarderCreated( RewarderType indexed rewarderType, IERC20 indexed token, address indexed pool, IBribeRewarder rewarder ); event RewarderImplementationSet(RewarderType indexed rewarderType, IRewarder indexed implementation); function getRewarderImplementation(RewarderType rewarderType) external view returns (IRewarder); function getRewarderCount(RewarderType rewarderType) external view returns (uint256); function getRewarderAt(RewarderType rewarderType, uint256 index) external view returns (IRewarder); function getRewarderType(IRewarder rewarder) external view returns (RewarderType); function setRewarderImplementation(RewarderType rewarderType, IRewarder implementation) external; function createRewarder(RewarderType rewarderType, IERC20 token, uint256 pid) external returns (IBaseRewarder); function createBribeRewarder(IERC20 token, address pool) external returns (IBribeRewarder); } // src/interfaces/IVoter.sol interface IVoter { error IVoter__InvalidLength(); error IVoter_VotingPeriodNotStarted(); error IVoter_VotingPeriodEnded(); error IVoter__AlreadyVoted(); error IVoter__NotOwner(); error IVoter__InsufficientVotingPower(); error IVoter__TooManyPoolIds(); error IVoter__DuplicatePoolId(uint256 pid); error IVoter__InsufficientLockTime(); error Voter__InvalidRegisterCaller(); error Voter__PoolNotVotable(); error IVoter__NoFinishedPeriod(); error IVoter_ZeroValue(); event VotingPeriodStarted(); event Voted(uint256 indexed tokenId, uint256 votingPeriod, address[] votedPools, uint256[] votesDeltaAmounts); event TopPoolIdsWithWeightsSet(uint256[] poolIds, uint256[] pidWeights); event VoterPoolValidatorUpdated(address indexed validator); event VotingDurationUpdated(uint256 duration); event MinimumLockTimeUpdated(uint256 lockTime); event MinimumVotesPerPoolUpdated(uint256 minimum); event OperatorUpdated(address indexed operator); struct VotingPeriod { uint256 startTime; uint256 endTime; } function getMasterChef() external view returns (IMasterChef); function getTotalWeight() external view returns (uint256); function getTopPoolIds() external view returns (uint256[] memory); function getWeight(uint256 pid) external view returns (uint256); function hasVoted(uint256 period, uint256 tokenId) external view returns (bool); function getCurrentVotingPeriod() external view returns (uint256); function getLatestFinishedPeriod() external view returns (uint256); function getPeriodStartTime() external view returns (uint256); function getPeriodStartEndtime(uint256 periodId) external view returns (uint256, uint256); function getVotesPerPeriod(uint256 periodId, address pool) external view returns (uint256); function getVotedPools() external view returns (address[] memory); function getVotedPoolsLength() external view returns (uint256); function getVotedPoolsAtIndex(uint256 index) external view returns (address, uint256); function getTotalVotes() external view returns (uint256); function getUserVotes(uint256 tokenId, address pool) external view returns (uint256); function getPoolVotesPerPeriod(uint256 periodId, address pool) external view returns (uint256); function getUserBribeRewaderAt(uint256 period, uint256 tokenId, uint256 index) external view returns (IBribeRewarder); function getUserBribeRewarderLength(uint256 period, uint256 tokenId) external view returns (uint256); function getBribeRewarderAt(uint256 period, address pool, uint256 index) external view returns (IBribeRewarder); function getBribeRewarderLength(uint256 period, address pool) external view returns (uint256); function ownerOf(uint256 tokenId, address account) external view returns (bool); function onRegister() external; } // src/interfaces/IMasterChef.sol interface IMasterChef { error MasterChef__InvalidShares(); error MasterChef__InvalidMetroPerSecond(); error MasterChef__ZeroAddress(); error MasterChef__NotMasterchefRewarder(); error MasterChef__CannotRenounceOwnership(); error MasterChef__MintFailed(); error MasterChef__TrusteeNotSet(); error MasterChef__NotTrustedCaller(); struct Farm { Amounts.Parameter amounts; Rewarder.Parameter rewarder; IERC20 token; IMasterChefRewarder extraRewarder; } // bool depositOnBehalf; // true if v2 pool zap in should be possible // uint256 startTime; event PositionModified(uint256 indexed pid, address indexed account, int256 deltaAmount, uint256 metroReward); event MetroPerSecondSet(uint256 metroPerSecond); event FarmAdded(uint256 indexed pid, IERC20 indexed token); event ExtraRewarderSet(uint256 indexed pid, IMasterChefRewarder extraRewarder); event TreasurySet(address indexed treasury); event VoterSet(IVoter indexed newVoter); event TrusteeSet(address indexed trustee); event MintMetroSet(bool mintMetro); event OperatorUpdated(address indexed operator); function add(IERC20 token, IMasterChefRewarder extraRewarder) external; function claim(uint256[] memory pids) external; function deposit(uint256 pid, uint256 amount) external; function depositOnBehalf(uint256 pid, uint256 amount, address account) external; function emergencyWithdraw(uint256 pid) external; function getDeposit(uint256 pid, address account) external view returns (uint256); function getLastUpdateTimestamp(uint256 pid) external view returns (uint256); function getPendingRewards(address account, uint256[] memory pids) external view returns (uint256[] memory metroRewards, IERC20[] memory extraTokens, uint256[] memory extraRewards); function getExtraRewarder(uint256 pid) external view returns (IMasterChefRewarder); function getMetro() external view returns (IMetro); function getMetroPerSecond() external view returns (uint256); function getMetroPerSecondForPid(uint256 pid) external view returns (uint256); function getNumberOfFarms() external view returns (uint256); function getToken(uint256 pid) external view returns (IERC20); function getTotalDeposit(uint256 pid) external view returns (uint256); function getTreasury() external view returns (address); function getTreasuryShare() external view returns (uint256); function getRewarderFactory() external view returns (IRewarderFactory); function getLBHooksManager() external view returns (address); function getVoter() external view returns (IVoter); function setExtraRewarder(uint256 pid, IMasterChefRewarder extraRewarder) external; function setMetroPerSecond(uint96 metroPerSecond) external; function setTreasury(address treasury) external; function setVoter(IVoter voter) external; function setTrustee(address trustee) external; function updateAll(uint256[] calldata pids) external; function withdraw(uint256 pid, uint256 amount) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; import {Panic} from "../Panic.sol"; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an success flag (no overflow). */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow). */ function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow). */ function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). */ function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. Panic.panic(Panic.DIVISION_BY_ZERO); } // The following calculation ensures accurate ceiling division without overflow. // Since a is non-zero, (a - 1) / b will not overflow. // The largest possible result occurs when (a - 1) / b is type(uint256).max, // but the largest value we can obtain is type(uint256).max - 1, which happens // when a = type(uint256).max and b = 1. unchecked { return a == 0 ? 0 : (a - 1) / b + 1; } } /** * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2²⁵⁶ + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. if (denominator <= prod1) { Panic.panic(denominator == 0 ? Panic.DIVISION_BY_ZERO : Panic.UNDER_OVERFLOW); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv ≡ 1 mod 2⁴. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2⁸ inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ inverse *= 2 - denominator * inverse; // inverse mod 2³² inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @dev Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); } /** * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. * * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, expect 0. * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. * * If the input value is not inversible, 0 is returned. * * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Ferma's little theorem and get the * inverse using `Math.modExp(a, n - 2, n)`. */ function invMod(uint256 a, uint256 n) internal pure returns (uint256) { unchecked { if (n == 0) return 0; // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) // Used to compute integers x and y such that: ax + ny = gcd(a, n). // When the gcd is 1, then the inverse of a modulo n exists and it's x. // ax + ny = 1 // ax = 1 + (-y)n // ax ≡ 1 (mod n) # x is the inverse of a modulo n // If the remainder is 0 the gcd is n right away. uint256 remainder = a % n; uint256 gcd = n; // Therefore the initial coefficients are: // ax + ny = gcd(a, n) = n // 0a + 1n = n int256 x = 0; int256 y = 1; while (remainder != 0) { uint256 quotient = gcd / remainder; (gcd, remainder) = ( // The old remainder is the next gcd to try. remainder, // Compute the next remainder. // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd // where gcd is at most n (capped to type(uint256).max) gcd - remainder * quotient ); (x, y) = ( // Increment the coefficient of a. y, // Decrement the coefficient of n. // Can overflow, but the result is casted to uint256 so that the // next value of y is "wrapped around" to a value between 0 and n - 1. x - y * int256(quotient) ); } if (gcd != 1) return 0; // No inverse exists. return x < 0 ? (n - uint256(-x)) : uint256(x); // Wrap the result if it's negative. } } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) * * Requirements: * - modulus can't be zero * - underlying staticcall to precompile must succeed * * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make * sure the chain you're using it on supports the precompiled contract for modular exponentiation * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, * the underlying function will succeed given the lack of a revert, but the result may be incorrectly * interpreted as 0. */ function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { (bool success, uint256 result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). * It includes a success flag indicating if the operation succeeded. Operation will be marked has failed if trying * to operate modulo 0 or if the underlying precompile reverted. * * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack * of a revert, but the result may be incorrectly interpreted as 0. */ function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { if (m == 0) return (false, 0); /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) // | Offset | Content | Content (Hex) | // |-----------|------------|--------------------------------------------------------------------| // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x60:0x7f | value of b | 0x<.............................................................b> | // | 0x80:0x9f | value of e | 0x<.............................................................e> | // | 0xa0:0xbf | value of m | 0x<.............................................................m> | mstore(ptr, 0x20) mstore(add(ptr, 0x20), 0x20) mstore(add(ptr, 0x40), 0x20) mstore(add(ptr, 0x60), b) mstore(add(ptr, 0x80), e) mstore(add(ptr, 0xa0), m) // Given the result < m, it's guaranteed to fit in 32 bytes, // so we can use the memory scratch space located at offset 0. success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) result := mload(0x00) } } /** * @dev Variant of {modExp} that supports inputs of arbitrary length. */ function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { (bool success, bytes memory result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Variant of {tryModExp} that supports inputs of arbitrary length. */ function tryModExp( bytes memory b, bytes memory e, bytes memory m ) internal view returns (bool success, bytes memory result) { if (_zeroBytes(m)) return (false, new bytes(0)); uint256 mLen = m.length; // Encode call args in result and move the free memory pointer result = abi.encodePacked(b.length, e.length, mLen, b, e, m); /// @solidity memory-safe-assembly assembly { let dataPtr := add(result, 0x20) // Write result on top of args to avoid allocating extra memory. success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) // Overwrite the length. // result.length > returndatasize() is guaranteed because returndatasize() == m.length mstore(result, mLen) // Set the memory pointer after the returned data. mstore(0x40, add(dataPtr, mLen)) } } /** * @dev Returns whether the provided byte array is zero. */ function _zeroBytes(bytes memory byteArray) private pure returns (bool) { for (uint256 i = 0; i < byteArray.length; ++i) { if (byteArray[i] != 0) { return false; } } return true; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * This method is based on Newton's method for computing square roots; the algorithm is restricted to only * using integer operations. */ function sqrt(uint256 a) internal pure returns (uint256) { unchecked { // Take care of easy edge cases when a == 0 or a == 1 if (a <= 1) { return a; } // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between // the current value as `ε_n = | x_n - sqrt(a) |`. // // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is // bigger than any uint256. // // By noticing that // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar // to the msb function. uint256 aa = a; uint256 xn = 1; if (aa >= (1 << 128)) { aa >>= 128; xn <<= 64; } if (aa >= (1 << 64)) { aa >>= 64; xn <<= 32; } if (aa >= (1 << 32)) { aa >>= 32; xn <<= 16; } if (aa >= (1 << 16)) { aa >>= 16; xn <<= 8; } if (aa >= (1 << 8)) { aa >>= 8; xn <<= 4; } if (aa >= (1 << 4)) { aa >>= 4; xn <<= 2; } if (aa >= (1 << 2)) { xn <<= 1; } // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). // // We can refine our estimation by noticing that the the middle of that interval minimizes the error. // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). // This is going to be our x_0 (and ε_0) xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) // From here, Newton's method give us: // x_{n+1} = (x_n + a / x_n) / 2 // // One should note that: // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a // = ((x_n² + a) / (2 * x_n))² - a // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) // = (x_n² - a)² / (2 * x_n)² // = ((x_n² - a) / (2 * x_n))² // ≥ 0 // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n // // This gives us the proof of quadratic convergence of the sequence: // ε_{n+1} = | x_{n+1} - sqrt(a) | // = | (x_n + a / x_n) / 2 - sqrt(a) | // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | // = | (x_n - sqrt(a))² / (2 * x_n) | // = | ε_n² / (2 * x_n) | // = ε_n² / | (2 * x_n) | // // For the first iteration, we have a special case where x_0 is known: // ε_1 = ε_0² / | (2 * x_0) | // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) // ≤ 2**(2*e-4) / (3 * 2**(e-1)) // ≤ 2**(e-3) / 3 // ≤ 2**(e-3-log2(3)) // ≤ 2**(e-4.5) // // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: // ε_{n+1} = ε_n² / | (2 * x_n) | // ≤ (2**(e-k))² / (2 * 2**(e-1)) // ≤ 2**(2*e-2*k) / 2**e // ≤ 2**(e-2*k) xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either // sqrt(a) or sqrt(a) + 1. return xn - SafeCast.toUint(xn > a / xn); } } /** * @dev Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 exp; unchecked { exp = 128 * SafeCast.toUint(value > (1 << 128) - 1); value >>= exp; result += exp; exp = 64 * SafeCast.toUint(value > (1 << 64) - 1); value >>= exp; result += exp; exp = 32 * SafeCast.toUint(value > (1 << 32) - 1); value >>= exp; result += exp; exp = 16 * SafeCast.toUint(value > (1 << 16) - 1); value >>= exp; result += exp; exp = 8 * SafeCast.toUint(value > (1 << 8) - 1); value >>= exp; result += exp; exp = 4 * SafeCast.toUint(value > (1 << 4) - 1); value >>= exp; result += exp; exp = 2 * SafeCast.toUint(value > (1 << 2) - 1); value >>= exp; result += exp; result += SafeCast.toUint(value > 1); } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 isGt; unchecked { isGt = SafeCast.toUint(value > (1 << 128) - 1); value >>= isGt * 128; result += isGt * 16; isGt = SafeCast.toUint(value > (1 << 64) - 1); value >>= isGt * 64; result += isGt * 8; isGt = SafeCast.toUint(value > (1 << 32) - 1); value >>= isGt * 32; result += isGt * 4; isGt = SafeCast.toUint(value > (1 << 16) - 1); value >>= isGt * 16; result += isGt * 2; result += SafeCast.toUint(value > (1 << 8) - 1); } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson. // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift, // taking advantage of the most significant (or "sign" bit) in two's complement representation. // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result, // the mask will either be `bytes(0)` (if n is positive) or `~bytes32(0)` (if n is negative). int256 mask = n >> 255; // A `bytes(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it. return uint256((n + mask) ^ mask); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC-20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC-721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC-1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {ILBHooks} from "../interfaces/ILBHooks.sol"; /** * @title Hooks library * @notice This library contains functions that should be used to interact with hooks */ library Hooks { error Hooks__CallFailed(); bytes32 internal constant BEFORE_SWAP_FLAG = bytes32(uint256(1 << 160)); bytes32 internal constant AFTER_SWAP_FLAG = bytes32(uint256(1 << 161)); bytes32 internal constant BEFORE_FLASH_LOAN_FLAG = bytes32(uint256(1 << 162)); bytes32 internal constant AFTER_FLASH_LOAN_FLAG = bytes32(uint256(1 << 163)); bytes32 internal constant BEFORE_MINT_FLAG = bytes32(uint256(1 << 164)); bytes32 internal constant AFTER_MINT_FLAG = bytes32(uint256(1 << 165)); bytes32 internal constant BEFORE_BURN_FLAG = bytes32(uint256(1 << 166)); bytes32 internal constant AFTER_BURN_FLAG = bytes32(uint256(1 << 167)); bytes32 internal constant BEFORE_TRANSFER_FLAG = bytes32(uint256(1 << 168)); bytes32 internal constant AFTER_TRANSFER_FLAG = bytes32(uint256(1 << 169)); struct Parameters { address hooks; bool beforeSwap; bool afterSwap; bool beforeFlashLoan; bool afterFlashLoan; bool beforeMint; bool afterMint; bool beforeBurn; bool afterBurn; bool beforeBatchTransferFrom; bool afterBatchTransferFrom; } /** * @dev Helper function to encode the hooks parameters to a single bytes32 value * @param parameters The hooks parameters * @return hooksParameters The encoded hooks parameters */ function encode(Parameters memory parameters) internal pure returns (bytes32 hooksParameters) { hooksParameters = bytes32(uint256(uint160(address(parameters.hooks)))); if (parameters.beforeSwap) hooksParameters |= BEFORE_SWAP_FLAG; if (parameters.afterSwap) hooksParameters |= AFTER_SWAP_FLAG; if (parameters.beforeFlashLoan) hooksParameters |= BEFORE_FLASH_LOAN_FLAG; if (parameters.afterFlashLoan) hooksParameters |= AFTER_FLASH_LOAN_FLAG; if (parameters.beforeMint) hooksParameters |= BEFORE_MINT_FLAG; if (parameters.afterMint) hooksParameters |= AFTER_MINT_FLAG; if (parameters.beforeBurn) hooksParameters |= BEFORE_BURN_FLAG; if (parameters.afterBurn) hooksParameters |= AFTER_BURN_FLAG; if (parameters.beforeBatchTransferFrom) hooksParameters |= BEFORE_TRANSFER_FLAG; if (parameters.afterBatchTransferFrom) hooksParameters |= AFTER_TRANSFER_FLAG; } /** * @dev Helper function to decode the hooks parameters from a single bytes32 value * @param hooksParameters The encoded hooks parameters * @return parameters The hooks parameters */ function decode(bytes32 hooksParameters) internal pure returns (Parameters memory parameters) { parameters.hooks = getHooks(hooksParameters); parameters.beforeSwap = (hooksParameters & BEFORE_SWAP_FLAG) != 0; parameters.afterSwap = (hooksParameters & AFTER_SWAP_FLAG) != 0; parameters.beforeFlashLoan = (hooksParameters & BEFORE_FLASH_LOAN_FLAG) != 0; parameters.afterFlashLoan = (hooksParameters & AFTER_FLASH_LOAN_FLAG) != 0; parameters.beforeMint = (hooksParameters & BEFORE_MINT_FLAG) != 0; parameters.afterMint = (hooksParameters & AFTER_MINT_FLAG) != 0; parameters.beforeBurn = (hooksParameters & BEFORE_BURN_FLAG) != 0; parameters.afterBurn = (hooksParameters & AFTER_BURN_FLAG) != 0; parameters.beforeBatchTransferFrom = (hooksParameters & BEFORE_TRANSFER_FLAG) != 0; parameters.afterBatchTransferFrom = (hooksParameters & AFTER_TRANSFER_FLAG) != 0; } /** * @dev Helper function to get the hooks address from the encoded hooks parameters * @param hooksParameters The encoded hooks parameters * @return hooks The hooks address */ function getHooks(bytes32 hooksParameters) internal pure returns (address hooks) { hooks = address(uint160(uint256(hooksParameters))); } /** * @dev Helper function to set the hooks address in the encoded hooks parameters * @param hooksParameters The encoded hooks parameters * @param newHooks The new hooks address * @return hooksParameters The updated hooks parameters */ function setHooks(bytes32 hooksParameters, address newHooks) internal pure returns (bytes32) { return bytes32(bytes12(hooksParameters)) | bytes32(uint256(uint160(newHooks))); } /** * @dev Helper function to get the flags from the encoded hooks parameters * @param hooksParameters The encoded hooks parameters * @return flags The flags */ function getFlags(bytes32 hooksParameters) internal pure returns (bytes12 flags) { flags = bytes12(hooksParameters); } /** * @dev Helper function call the onHooksSet function on the hooks contract, only if the * hooksParameters is not 0 * @param hooksParameters The encoded hooks parameters * @param onHooksSetData The data to pass to the onHooksSet function */ function onHooksSet(bytes32 hooksParameters, bytes calldata onHooksSetData) internal { if (hooksParameters != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.onHooksSet.selector, hooksParameters, onHooksSetData) ); } } /** * @dev Helper function to call the beforeSwap function on the hooks contract, only if the * BEFORE_SWAP_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param to The recipient * @param swapForY Whether the swap is for Y * @param amountsIn The amounts in */ function beforeSwap(bytes32 hooksParameters, address sender, address to, bool swapForY, bytes32 amountsIn) internal { if ((hooksParameters & BEFORE_SWAP_FLAG) != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.beforeSwap.selector, sender, to, swapForY, amountsIn) ); } } /** * @dev Helper function to call the afterSwap function on the hooks contract, only if the * AFTER_SWAP_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param to The recipient * @param swapForY Whether the swap is for Y * @param amountsOut The amounts out */ function afterSwap(bytes32 hooksParameters, address sender, address to, bool swapForY, bytes32 amountsOut) internal { if ((hooksParameters & AFTER_SWAP_FLAG) != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.afterSwap.selector, sender, to, swapForY, amountsOut) ); } } /** * @dev Helper function to call the beforeFlashLoan function on the hooks contract, only if the * BEFORE_FLASH_LOAN_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param to The recipient * @param amounts The amounts */ function beforeFlashLoan(bytes32 hooksParameters, address sender, address to, bytes32 amounts) internal { if ((hooksParameters & BEFORE_FLASH_LOAN_FLAG) != 0) { _safeCall(hooksParameters, abi.encodeWithSelector(ILBHooks.beforeFlashLoan.selector, sender, to, amounts)); } } /** * @dev Helper function to call the afterFlashLoan function on the hooks contract, only if the * AFTER_FLASH_LOAN_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param to The recipient * @param fees The fees * @param feesReceived The fees received */ function afterFlashLoan(bytes32 hooksParameters, address sender, address to, bytes32 fees, bytes32 feesReceived) internal { if ((hooksParameters & AFTER_FLASH_LOAN_FLAG) != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.afterFlashLoan.selector, sender, to, fees, feesReceived) ); } } /** * @dev Helper function to call the beforeMint function on the hooks contract, only if the * BEFORE_MINT_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param to The recipient * @param liquidityConfigs The liquidity configs * @param amountsReceived The amounts received */ function beforeMint( bytes32 hooksParameters, address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsReceived ) internal { if ((hooksParameters & BEFORE_MINT_FLAG) != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.beforeMint.selector, sender, to, liquidityConfigs, amountsReceived) ); } } /** * @dev Helper function to call the afterMint function on the hooks contract, only if the * AFTER_MINT_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param to The recipient * @param liquidityConfigs The liquidity configs * @param amountsIn The amounts in */ function afterMint( bytes32 hooksParameters, address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsIn ) internal { if ((hooksParameters & AFTER_MINT_FLAG) != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.afterMint.selector, sender, to, liquidityConfigs, amountsIn) ); } } /** * @dev Helper function to call the beforeBurn function on the hooks contract, only if the * BEFORE_BURN_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param from The sender * @param to The recipient * @param ids The ids * @param amountsToBurn The amounts to burn */ function beforeBurn( bytes32 hooksParameters, address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn ) internal { if ((hooksParameters & BEFORE_BURN_FLAG) != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.beforeBurn.selector, sender, from, to, ids, amountsToBurn) ); } } /** * @dev Helper function to call the afterBurn function on the hooks contract, only if the * AFTER_BURN_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param from The sender * @param to The recipient * @param ids The ids * @param amountsToBurn The amounts to burn */ function afterBurn( bytes32 hooksParameters, address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn ) internal { if ((hooksParameters & AFTER_BURN_FLAG) != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.afterBurn.selector, sender, from, to, ids, amountsToBurn) ); } } /** * @dev Helper function to call the beforeTransferFrom function on the hooks contract, only if the * BEFORE_TRANSFER_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param from The sender * @param to The recipient * @param ids The list of ids * @param amounts The list of amounts */ function beforeBatchTransferFrom( bytes32 hooksParameters, address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amounts ) internal { if ((hooksParameters & BEFORE_TRANSFER_FLAG) != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.beforeBatchTransferFrom.selector, sender, from, to, ids, amounts) ); } } /** * @dev Helper function to call the afterTransferFrom function on the hooks contract, only if the * AFTER_TRANSFER_FLAG is set in the hooksParameters * @param hooksParameters The encoded hooks parameters * @param sender The sender * @param from The sender * @param to The recipient * @param ids The list of ids * @param amounts The list of amounts */ function afterBatchTransferFrom( bytes32 hooksParameters, address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amounts ) internal { if ((hooksParameters & AFTER_TRANSFER_FLAG) != 0) { _safeCall( hooksParameters, abi.encodeWithSelector(ILBHooks.afterBatchTransferFrom.selector, sender, from, to, ids, amounts) ); } } /** * @dev Helper function to call the hooks contract and verify the call was successful * by matching the expected selector with the returned data * @param hooksParameters The encoded hooks parameters * @param data The data to pass to the hooks contract */ function _safeCall(bytes32 hooksParameters, bytes memory data) private { bool success; address hooks = getHooks(hooksParameters); assembly { let expectedSelector := shr(224, mload(add(data, 0x20))) success := call(gas(), hooks, 0, add(data, 0x20), mload(data), 0, 0x20) if and(iszero(success), iszero(iszero(returndatasize()))) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } success := and(success, and(gt(returndatasize(), 0x1f), eq(shr(224, mload(0)), expectedSelector))) } if (!success) revert Hooks__CallFailed(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { Ownable2StepUpgradeable, OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import {LBBaseHooks} from "@lb-protocol/src/LBBaseHooks.sol"; import {Uint256x256Math} from "@lb-protocol/src/libraries/math/Uint256x256Math.sol"; import {Clone} from "@lb-protocol/src/libraries/Clone.sol"; import {ILBPair} from "@lb-protocol/src/interfaces/ILBPair.sol"; import {PriceHelper} from "@lb-protocol/src/libraries/PriceHelper.sol"; import {BinHelper} from "@lb-protocol/src/libraries/BinHelper.sol"; import {Hooks} from "@lb-protocol/src/libraries/Hooks.sol"; import {SafeCast} from "@lb-protocol/src/libraries/math/SafeCast.sol"; import {ILBHooksBaseRewarder} from "./interfaces/ILBHooksBaseRewarder.sol"; import {TokenHelper, IERC20} from "./library/TokenHelper.sol"; /** * @title LB Hooks Base Rewarder * @dev Base contract for any LB Hooks Rewarder */ abstract contract LBHooksBaseRewarder is LBBaseHooks, Ownable2StepUpgradeable, Clone, ILBHooksBaseRewarder { using Uint256x256Math for uint256; using SafeCast for uint256; address public immutable implementation; int256 internal constant MAX_NUMBER_OF_BINS = 11; uint8 internal constant OFFSET_PRECISION = 128; bytes32 internal constant FLAGS = Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_MINT_FLAG | Hooks.BEFORE_BURN_FLAG | Hooks.BEFORE_TRANSFER_FLAG; address internal immutable _lbHooksManager; int24 internal _deltaBinA; int24 internal _deltaBinB; uint256 internal _totalUnclaimedRewards; mapping(uint256 => Bin) internal _bins; mapping(address => uint256) internal _unclaimedRewards; /** * @dev Constructor of the contract * @param LBHooksManager The address of the LBHooksManager contract */ constructor(address LBHooksManager) { implementation = address(this); _lbHooksManager = LBHooksManager; _disableInitializers(); } /** * @dev Receive function called when the contract receives native tokens */ receive() external payable { _nativeReceived(); } /** * @dev Fallback function called when the contract receives native tokens */ fallback() external payable { _nativeReceived(); } /** * @dev Returns the reward token * @return rewardToken The reward token */ function getRewardToken() external view virtual override returns (IERC20) { return _getRewardToken(); } /** * @dev Returns the LB Hooks Manager * @return lbHooksManager The LB Hooks Manager */ function getLBHooksManager() external view virtual override returns (address) { return _lbHooksManager; } /** * @dev Returns whether the rewarder is stopped * @return isStopped Whether the rewarder is stopped */ function isStopped() external view virtual override returns (bool) { return !_isLinked(); } /** * @dev Returns the rewarded range from [binStart, binEnd[ (exclusive) * @return binStart The bin start to be rewarded * @return binEnd The bin end to be rewarded, exclusive */ function getRewardedRange() external view virtual override returns (uint256 binStart, uint256 binEnd) { (,, binStart, binEnd) = _getRewardedRange(); } /** * @dev Returns the pending rewards for the given user and ids * The ids are expected to be unique, if they are not, the rewards returned might be greater than expected * @param user The address of the user * @param ids The ids of the bins * @return pendingRewards The pending rewards */ function getPendingRewards(address user, uint256[] calldata ids) external view virtual override returns (uint256) { if (!_isLinked()) return 0; uint256[] calldata ids_ = ids; // Avoid stack too deep error ILBPair lbPair = _getLBPair(); (uint256[] memory rewardedIds, uint24 activeId, uint256 binStart, uint256 binEnd) = _getRewardedRange(); (uint256[] memory liquiditiesX128, uint256[] memory totalSuppliesX64, uint256 totalLiquiditiesX128) = _getLiquidityData(lbPair, activeId, rewardedIds); address user_ = user; // Avoid stack too deep error uint256 pendingTotalRewards = _getPendingTotalRewards(); uint256 pendingRewards; for (uint256 i; i < ids_.length; ++i) { uint24 id = ids_[i].safe24(); uint256 accRewardsPerShareX64; uint256 userAccRewardsPerShareX64; { Bin storage bin = _bins[id]; accRewardsPerShareX64 = bin.accRewardsPerShareX64; userAccRewardsPerShareX64 = bin.userAccRewardsPerShareX64[user_]; } if (id >= binStart && id < binEnd) { uint256 index = id - binStart; uint256 totalSupplyX64 = totalSuppliesX64[index]; if (totalSupplyX64 > 0 && totalLiquiditiesX128 > 0) { uint256 weightX128 = liquiditiesX128[index].shiftDivRoundDown(OFFSET_PRECISION, totalLiquiditiesX128); accRewardsPerShareX64 += pendingTotalRewards.mulDivRoundDown(weightX128, totalSupplyX64); } } uint256 balanceX64 = lbPair.balanceOf(user_, id); if (accRewardsPerShareX64 > userAccRewardsPerShareX64) { unchecked { pendingRewards += (accRewardsPerShareX64 - userAccRewardsPerShareX64).mulShiftRoundDown( balanceX64, OFFSET_PRECISION ); } } } return pendingRewards + _unclaimedRewards[user_]; } /** * @dev Claims the rewards for the given user and ids * @param user The address of the user * @param ids The ids of the bins */ function claim(address user, uint256[] calldata ids) external virtual override { if (!_isLinked()) revert LBHooksBaseRewarder__UnlinkedHooks(); if (!_isAuthorizedCaller(user)) revert LBHooksBaseRewarder__UnauthorizedCaller(); _updateAccruedRewardsPerShare(); _updateUser(user, ids); _claim(user, ids, _unclaimedRewards[user]); } /** * @dev Sets the delta bins * The delta bins are used to determine the range of bins to be rewarded, * from [activeId + deltaBinA, activeId + deltaBinB[ (exclusive). * @param deltaBinA The delta bin A * @param deltaBinB The delta bin B */ function setDeltaBins(int24 deltaBinA, int24 deltaBinB) external virtual override onlyOwner { if (deltaBinA > deltaBinB) revert LBHooksBaseRewarder__InvalidDeltaBins(); if (int256(deltaBinB) - deltaBinA > MAX_NUMBER_OF_BINS) revert LBHooksBaseRewarder__ExceedsMaxNumberOfBins(); _updateAccruedRewardsPerShare(); _deltaBinA = deltaBinA; _deltaBinB = deltaBinB; emit DeltaBinsSet(deltaBinA, deltaBinB); } /** * @dev Sweeps the given token to the given address * @param token The address of the token * @param to The address of the recipient */ function sweep(IERC20 token, address to) external virtual override onlyOwner { uint256 balance = TokenHelper.safeBalanceOf(token, address(this)); if (balance == 0) revert LBHooksBaseRewarder__ZeroBalance(); if (_isLinked() && token == _getRewardToken()) revert LBHooksBaseRewarder__LockedRewardToken(); TokenHelper.safeTransfer(token, to, balance); } /** * @dev Internal function to return the reward token * @return The reward token */ function _getRewardToken() internal view virtual returns (IERC20) { return IERC20(_getArgAddress(20)); } /** * @dev Internal function to return whether caller is the msg.sender * @param user The address of the user * @return Whether the caller is the msg.sender */ function _isAuthorizedCaller(address user) internal view virtual returns (bool) { return user == msg.sender; } /** * @dev Internal helper function to return the rewarded range * @return rewardedIds The list of the rewarded ids from binStart to binEnd * @return activeId The active id * @return binStart The bin start to be rewarded * @return binEnd The bin end to be rewarded */ function _getRewardedRange() internal view virtual returns (uint256[] memory rewardedIds, uint24 activeId, uint256 binStart, uint256 binEnd) { activeId = _getLBPair().getActiveId(); (int24 deltaBinA, int24 deltaBinB) = (_deltaBinA, _deltaBinB); binStart = uint256(int256(uint256(activeId)) + deltaBinA); binEnd = uint256(int256(uint256(activeId)) + deltaBinB); if (binStart > type(uint24).max || binEnd > type(uint24).max) revert LBHooksBaseRewarder__Overflow(); uint256 length = binEnd - binStart; rewardedIds = new uint256[](length); for (uint256 i; i < length; ++i) { unchecked { rewardedIds[i] = (binStart + i).safe24(); } } } /** * @dev Internal function to return the liquidity data for the given ids * @param lbPair The LB Pair * @param activeId The active id * @param ids The ids of the bins * @return liquiditiesX128 The liquidities for the given ids * @return totalSuppliesX64 The total supplies for the given ids * @return totalLiquiditiesX128 The total liquidities for the given ids */ function _getLiquidityData(ILBPair lbPair, uint24 activeId, uint256[] memory ids) internal view virtual returns (uint256[] memory liquiditiesX128, uint256[] memory totalSuppliesX64, uint256 totalLiquiditiesX128) { uint256 activePriceX128 = PriceHelper.getPriceFromId(activeId, lbPair.getBinStep()); uint256 length = ids.length; liquiditiesX128 = new uint256[](length); totalSuppliesX64 = new uint256[](length); for (uint256 i; i < length; ++i) { uint24 id = ids[i].safe24(); (uint128 binReserveX, uint128 binReserveY) = lbPair.getBin(id); uint256 totalSupplyX64 = lbPair.totalSupply(id); uint256 liquidityX128 = BinHelper.getLiquidity(binReserveX, binReserveY, activePriceX128); liquiditiesX128[i] = liquidityX128; totalSuppliesX64[i] = totalSupplyX64; totalLiquiditiesX128 += liquidityX128; } } /** * @dev Internal function to convert the liquidity configs to ids * @param liquidityConfigs The liquidity configs * @return ids The ids */ function _convertLiquidityConfigs(bytes32[] memory liquidityConfigs) internal pure virtual returns (uint256[] memory ids) { uint256 length = liquidityConfigs.length; ids = new uint256[](length); for (uint256 i; i < length; ++i) { ids[i] = uint24(uint256(liquidityConfigs[i])); } } /** * @dev Internal function that allows the rewarder to receive native tokens only * if the rewarded token is native, else it will revert */ function _nativeReceived() internal view virtual { if (_getImmutableArgsOffset() != 0) revert LBHooksBaseRewarder__NotImplemented(); if (address(_getRewardToken()) != address(0)) revert LBHooksBaseRewarder__NotNativeRewarder(); } /** * @dev Internal function to update the accrued rewards per share */ function _updateAccruedRewardsPerShare() internal virtual { uint256 pendingTotalRewards = _updateRewards(); if (pendingTotalRewards == 0) return; ILBPair lbPair = _getLBPair(); (uint256[] memory ids, uint24 activeId,,) = _getRewardedRange(); (uint256[] memory liquiditiesX128, uint256[] memory totalSuppliesX64, uint256 totalLiquiditiesX128) = _getLiquidityData(lbPair, activeId, ids); if (totalLiquiditiesX128 == 0) return; _totalUnclaimedRewards += pendingTotalRewards; uint256 length = ids.length; for (uint256 i; i < length; ++i) { uint256 totalSupplyX64 = totalSuppliesX64[i]; if (totalSupplyX64 > 0) { uint256 weightX128 = liquiditiesX128[i].shiftDivRoundDown(OFFSET_PRECISION, totalLiquiditiesX128); _bins[ids[i]].accRewardsPerShareX64 += pendingTotalRewards.mulDivRoundDown(weightX128, totalSupplyX64); } } } /** * @dev Internal function to update the user * @param to The address of the user * @param ids The ids of the bins */ function _updateUser(address to, uint256[] memory ids) internal virtual { ILBPair lbPair = _getLBPair(); uint256 length = ids.length; uint256 pendingRewards; for (uint256 i; i < length; ++i) { uint24 id = ids[i].safe24(); uint256 balanceX64 = lbPair.balanceOf(to, id); Bin storage bin = _bins[id]; uint256 accRewardsPerShareX64 = bin.accRewardsPerShareX64; uint256 userAccRewardsPerShareX64 = bin.userAccRewardsPerShareX64[to]; if (accRewardsPerShareX64 > userAccRewardsPerShareX64) { unchecked { pendingRewards += (accRewardsPerShareX64 - userAccRewardsPerShareX64).mulShiftRoundDown( balanceX64, OFFSET_PRECISION ); } bin.userAccRewardsPerShareX64[to] = accRewardsPerShareX64; } } if (pendingRewards > 0) _unclaimedRewards[to] += pendingRewards; } /** * @dev Internal function to claim the rewards for the given user * @param user The address of the user * @param ids The ids of the bins * @param rewards The rewards to claim */ function _claim(address user, uint256[] memory ids, uint256 rewards) internal virtual { if (rewards == 0) return; _totalUnclaimedRewards -= rewards; _unclaimedRewards[user] -= rewards; emit Claim(user, rewards); _onClaim(user, ids); TokenHelper.safeTransfer(_getRewardToken(), user, rewards); } /** * @dev Override the internal function to return the LB Pair * @return lbPair The LB Pair */ function _getLBPair() internal view virtual override returns (ILBPair) { return ILBPair(_getArgAddress(0)); } /** * @dev Override the internal function that is called when the rewarder is set * Will revert if the rewarder is already linked via the inializer modifier * Will revert if the hooks parameters are not the expected ones * @param hooksParameters The hooks parameters * @param data The data used to initialize the rewarder; should at least contain the ABI encoded address of the owner */ function _onHooksSet(bytes32 hooksParameters, bytes calldata data) internal override initializer { if (hooksParameters != Hooks.setHooks(FLAGS, address(this))) { revert LBHooksBaseRewarder__InvalidHooksParameters(); } address owner = abi.decode(data, (address)); __Ownable_init(owner); _onHooksSet(data); } /** * @dev Override the internal function that is called before a swap on the LB Pair * Will update the accrued rewards per share */ function _beforeSwap(address, address, bool, bytes32) internal virtual override { _updateAccruedRewardsPerShare(); } /** * @dev Override the internal function that is called before a mint on the LB Pair * Will update the accrued rewards per share and the user rewards * @param to The address of the recipient of the LB Pair tokens * @param liquidityConfigs The liquidity configs */ function _beforeMint(address, address to, bytes32[] calldata liquidityConfigs, bytes32) internal virtual override { _updateAccruedRewardsPerShare(); _updateUser(to, _convertLiquidityConfigs(liquidityConfigs)); } /** * @dev Override the internal function that is called before a burn on the LB Pair * Will update the accrued rewards per share and the user rewards * @param from The address of the sender of the LB Pair tokens * @param ids The ids of the bins */ function _beforeBurn(address, address from, address, uint256[] calldata ids, uint256[] calldata) internal virtual override { _updateAccruedRewardsPerShare(); _updateUser(from, ids); } /** * @dev Override the internal function that is called before a transfer on the LB Pair * Will update the accrued rewards per share and both the sender and recipient rewards * @param from The address of the sender of the LB Pair tokens * @param to The address of the recipient of the LB Pair tokens * @param ids The ids of the bins */ function _beforeBatchTransferFrom(address, address from, address to, uint256[] calldata ids, uint256[] calldata) internal virtual override { _updateAccruedRewardsPerShare(); _updateUser(from, ids); _updateUser(to, ids); } /** * @dev Internal function that can be overriden to add custom logic when the rewarder is set * @param data The data used to initialize the rewarder */ function _onHooksSet(bytes calldata data) internal virtual {} /** * @dev Internal function that can be overriden to add custom logic when the rewards are claimed * @param user The address of the user * @param ids The ids of the bins */ function _onClaim(address user, uint256[] memory ids) internal virtual {} /** * @dev Internal function that **MUST** be overriden to return the total pending rewards * @return pendingTotalRewards The total pending rewards */ function _getPendingTotalRewards() internal view virtual returns (uint256 pendingTotalRewards); /** * @dev Internal function that **MUST** be overriden to update and return the total pending rewards * @return pendingTotalRewards The total pending rewards */ function _updateRewards() internal virtual returns (uint256 pendingTotalRewards); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ILBHooksBaseRewarder} from "./ILBHooksBaseRewarder.sol"; /** * @title LB Hooks Parent Rewarder Interface * @dev Interface for the LB Hooks Parent Rewarder */ interface ILBHooksBaseParentRewarder is ILBHooksBaseRewarder { error LBHooksRewarder__InvalidLBHooksExtraRewarder(); event LBHooksExtraRewarderSet(address lbHooksExtraRewarder); function getExtraHooksParameters() external view returns (bytes32 extraHooksParameters); function setLBHooksExtraRewarder(address lbHooksExtraRewarder, bytes calldata extraRewarderData) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ILBHooksBaseSimpleRewarder} from "./ILBHooksBaseSimpleRewarder.sol"; import {ILBHooksBaseParentRewarder} from "./ILBHooksBaseParentRewarder.sol"; /** * @title LB Hooks Extra Rewarder Interface * @dev Interface for the LB Hooks Extra Rewarder */ interface ILBHooksExtraRewarder is ILBHooksBaseSimpleRewarder { error LBHooksExtraRewarder__UnauthorizedCaller(); error LBHooksExtraRewarder__ParentRewarderNotLinked(); function getParentRewarder() external view returns (ILBHooksBaseParentRewarder); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ILBHooks} from "@lb-protocol/src/interfaces/ILBHooks.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title LB Hooks Base Rewarder Interface * @dev Interface for the LB Hooks Base Rewarder */ interface ILBHooksBaseRewarder is ILBHooks { error LBHooksBaseRewarder__InvalidDeltaBins(); error LBHooksBaseRewarder__Overflow(); error LBHooksBaseRewarder__NativeTransferFailed(); error LBHooksBaseRewarder__UnlinkedHooks(); error LBHooksBaseRewarder__InvalidHooksParameters(); error LBHooksBaseRewarder__ZeroBalance(); error LBHooksBaseRewarder__LockedRewardToken(); error LBHooksBaseRewarder__NotNativeRewarder(); error LBHooksBaseRewarder__NotImplemented(); error LBHooksBaseRewarder__UnauthorizedCaller(); error LBHooksBaseRewarder__ExceedsMaxNumberOfBins(); event DeltaBinsSet(int24 deltaBinA, int24 deltaBinB); event Claim(address indexed user, uint256 amount); struct Bin { uint256 accRewardsPerShareX64; mapping(address => uint256) userAccRewardsPerShareX64; } function getRewardToken() external view returns (IERC20); function getLBHooksManager() external view returns (address); function isStopped() external view returns (bool); function getRewardedRange() external view returns (uint256 binStart, uint256 binEnd); function getPendingRewards(address user, uint256[] calldata ids) external view returns (uint256 pendingRewards); function claim(address user, uint256[] calldata ids) external; function setDeltaBins(int24 deltaBinA, int24 deltaBinB) external; function sweep(IERC20 token, address to) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @dev Helper library for emitting standardized panic codes. * * ```solidity * contract Example { * using Panic for uint256; * * // Use any of the declared internal constants * function foo() { Panic.GENERIC.panic(); } * * // Alternatively * function foo() { Panic.panic(Panic.GENERIC); } * } * ``` * * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. */ // slither-disable-next-line unused-state library Panic { /// @dev generic / unspecified error uint256 internal constant GENERIC = 0x00; /// @dev used by the assert() builtin uint256 internal constant ASSERT = 0x01; /// @dev arithmetic underflow or overflow uint256 internal constant UNDER_OVERFLOW = 0x11; /// @dev division or modulo by zero uint256 internal constant DIVISION_BY_ZERO = 0x12; /// @dev enum conversion error uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; /// @dev invalid encoding in storage uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; /// @dev empty array pop uint256 internal constant EMPTY_ARRAY_POP = 0x31; /// @dev array out of bounds access uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; /// @dev resource error (too large allocation or too large array) uint256 internal constant RESOURCE_ERROR = 0x41; /// @dev calling invalid internal function uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; /// @dev Reverts with a panic code. Recommended to use with /// the internal constants with predefined codes. function panic(uint256 code) internal pure { /// @solidity memory-safe-assembly assembly { mstore(0x00, shl(0xe0, 0x4e487b71)) mstore(0x04, code) revert(0x00, 0x24) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { /// @solidity memory-safe-assembly assembly { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {ILBPair} from "./ILBPair.sol"; import {Hooks} from "../libraries/Hooks.sol"; interface ILBHooks { function getLBPair() external view returns (ILBPair); function isLinked() external view returns (bool); function onHooksSet(bytes32 hooksParameters, bytes calldata onHooksSetData) external returns (bytes4); function beforeSwap(address sender, address to, bool swapForY, bytes32 amountsIn) external returns (bytes4); function afterSwap(address sender, address to, bool swapForY, bytes32 amountsOut) external returns (bytes4); function beforeFlashLoan(address sender, address to, bytes32 amounts) external returns (bytes4); function afterFlashLoan(address sender, address to, bytes32 fees, bytes32 feesReceived) external returns (bytes4); function beforeMint(address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsReceived) external returns (bytes4); function afterMint(address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsIn) external returns (bytes4); function beforeBurn( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn ) external returns (bytes4); function afterBurn( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn ) external returns (bytes4); function beforeBatchTransferFrom( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amounts ) external returns (bytes4); function afterBatchTransferFrom( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amounts ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) pragma solidity ^0.8.20; import {OwnableUpgradeable} from "./OwnableUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This extension of the {Ownable} contract includes a two-step mechanism to transfer * ownership, where the new owner must call {acceptOwnership} in order to replace the * old one. This can help prevent common mistakes, such as transfers of ownership to * incorrect accounts, or to contracts that are unable to interact with the * permission system. * * The initial owner is specified at deployment time in the constructor for `Ownable`. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step struct Ownable2StepStorage { address _pendingOwner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00; function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) { assembly { $.slot := Ownable2StepStorageLocation } } event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); function __Ownable2Step_init() internal onlyInitializing { } function __Ownable2Step_init_unchained() internal onlyInitializing { } /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { Ownable2StepStorage storage $ = _getOwnable2StepStorage(); return $._pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { Ownable2StepStorage storage $ = _getOwnable2StepStorage(); $._pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { Ownable2StepStorage storage $ = _getOwnable2StepStorage(); delete $._pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); if (pendingOwner() != sender) { revert OwnableUnauthorizedAccount(sender); } _transferOwnership(sender); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Hooks} from "./libraries/Hooks.sol"; import {ILBHooks} from "./interfaces/ILBHooks.sol"; import {ILBPair} from "./interfaces/ILBPair.sol"; /** * @title Liquidity Book Base Hooks Contract * @notice Base contract for LBPair hooks * This contract is meant to be inherited by any contract that wants to implement LBPair hooks */ abstract contract LBBaseHooks is ILBHooks { error LBBaseHooks__InvalidCaller(address caller); error LBBaseHooks__NotLinked(); /** * @dev Modifier to check that the caller is the trusted caller */ modifier onlyTrustedCaller() { _checkTrustedCaller(); _; } /** * @dev Returns the LBPair contract * @return The LBPair contract */ function getLBPair() external view override returns (ILBPair) { return _getLBPair(); } /** * @dev Returns whether the contract is linked to the pair or not * @return Whether the contract is linked to the pair or not */ function isLinked() external view override returns (bool) { return _isLinked(); } /** * @notice Hook called by the pair when the hooks parameters are set * @dev Only callable by the pair * @param hooksParameters The hooks parameters * @param onHooksSetData The onHooksSet data * @return The function selector */ function onHooksSet(bytes32 hooksParameters, bytes calldata onHooksSetData) external override onlyTrustedCaller returns (bytes4) { if (!_isLinked()) revert LBBaseHooks__NotLinked(); _onHooksSet(hooksParameters, onHooksSetData); return this.onHooksSet.selector; } /** * @notice Hook called by the pair before a swap * @dev Only callable by the pair * @param sender The address that initiated the swap * @param to The address that will receive the swapped tokens * @param swapForY Whether the swap is for token Y * @param amountsIn The amounts in * @return The function selector */ function beforeSwap(address sender, address to, bool swapForY, bytes32 amountsIn) external override onlyTrustedCaller returns (bytes4) { _beforeSwap(sender, to, swapForY, amountsIn); return this.beforeSwap.selector; } /** * @notice Hook called by the pair after a swap * @dev Only callable by the pair * @param sender The address that initiated the swap * @param to The address that received the swapped tokens * @param swapForY Whether the swap was for token Y * @param amountsOut The amounts out * @return The function selector */ function afterSwap(address sender, address to, bool swapForY, bytes32 amountsOut) external override onlyTrustedCaller returns (bytes4) { _afterSwap(sender, to, swapForY, amountsOut); return this.afterSwap.selector; } /** * @notice Hook called by the pair before a flash loan * @dev Only callable by the pair * @param sender The address that initiated the flash loan * @param to The address that will receive the flash loaned tokens * @param amounts The amounts * @return The function selector */ function beforeFlashLoan(address sender, address to, bytes32 amounts) external override onlyTrustedCaller returns (bytes4) { _beforeFlashLoan(sender, to, amounts); return this.beforeFlashLoan.selector; } /** * @notice Hook called by the pair after a flash loan * @dev Only callable by the pair * @param sender The address that initiated the flash loan * @param to The address that received the flash loaned tokens * @param fees The flashloan fees * @param feesReceived The fees received * @return The function selector */ function afterFlashLoan(address sender, address to, bytes32 fees, bytes32 feesReceived) external override onlyTrustedCaller returns (bytes4) { _afterFlashLoan(sender, to, fees, feesReceived); return this.afterFlashLoan.selector; } /** * @notice Hook called by the pair before minting * @dev Only callable by the pair * @param sender The address that initiated the mint * @param to The address that will receive the minted tokens * @param liquidityConfigs The liquidity configurations * @param amountsReceived The amounts received * @return The function selector */ function beforeMint(address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsReceived) external override onlyTrustedCaller returns (bytes4) { _beforeMint(sender, to, liquidityConfigs, amountsReceived); return this.beforeMint.selector; } /** * @notice Hook called by the pair after minting * @dev Only callable by the pair * @param sender The address that initiated the mint * @param to The address that received the minted tokens * @param liquidityConfigs The liquidity configurations * @param amountsIn The amounts in * @return The function selector */ function afterMint(address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsIn) external override onlyTrustedCaller returns (bytes4) { _afterMint(sender, to, liquidityConfigs, amountsIn); return this.afterMint.selector; } /** * @notice Hook called by the pair before burning * @dev Only callable by the pair * @param sender The address that initiated the burn * @param from The address that will burn the tokens * @param to The address that will receive the burned tokens * @param ids The token ids * @param amountsToBurn The amounts to burn * @return The function selector */ function beforeBurn( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn ) external override onlyTrustedCaller returns (bytes4) { _beforeBurn(sender, from, to, ids, amountsToBurn); return this.beforeBurn.selector; } /** * @notice Hook called by the pair after burning * @dev Only callable by the pair * @param sender The address that initiated the burn * @param from The address that burned the tokens * @param to The address that received the burned tokens * @param ids The token ids * @param amountsToBurn The amounts to burn * @return The function selector */ function afterBurn( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn ) external override onlyTrustedCaller returns (bytes4) { _afterBurn(sender, from, to, ids, amountsToBurn); return this.afterBurn.selector; } /** * @notice Hook called by the pair before a batch transfer * @dev Only callable by the pair * @param sender The address that initiated the transfer * @param from The address that will transfer the tokens * @param to The address that will receive the tokens * @param ids The token ids * @param amounts The amounts * @return The function selector */ function beforeBatchTransferFrom( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amounts ) external override onlyTrustedCaller returns (bytes4) { _beforeBatchTransferFrom(sender, from, to, ids, amounts); return this.beforeBatchTransferFrom.selector; } /** * @notice Hook called by the pair after a batch transfer * @dev Only callable by the pair * @param sender The address that initiated the transfer * @param from The address that transferred the tokens * @param to The address that received the tokens * @param ids The token ids * @param amounts The amounts * @return The function selector */ function afterBatchTransferFrom( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amounts ) external override onlyTrustedCaller returns (bytes4) { _afterBatchTransferFrom(sender, from, to, ids, amounts); return this.afterBatchTransferFrom.selector; } /** * @dev Checks that the caller is the trusted caller, otherwise reverts */ function _checkTrustedCaller() internal view virtual { if (msg.sender != address(_getLBPair())) revert LBBaseHooks__InvalidCaller(msg.sender); } /** * @dev Checks if the contract is linked to the pair * @return Whether the contract is linked to the pair or not */ function _isLinked() internal view virtual returns (bool) { address hooks = Hooks.getHooks(_getLBPair().getLBHooksParameters()); return hooks == address(this); } /** * @dev Returns the LBPair contract */ function _getLBPair() internal view virtual returns (ILBPair); /** * @notice Internal function to be overridden that is called when the hooks parameters are set * @param hooksParameters The hooks parameters * @param onHooksSetData The onHooksSet data */ function _onHooksSet(bytes32 hooksParameters, bytes calldata onHooksSetData) internal virtual {} /** * @notice Internal function to be overridden that is called before a swap * @param sender The address that initiated the swap * @param to The address that will receive the swapped tokens * @param swapForY Whether the swap is for token Y * @param amountsIn The amounts in */ function _beforeSwap(address sender, address to, bool swapForY, bytes32 amountsIn) internal virtual {} /** * @notice Internal function to be overridden that is called after a swap * @param sender The address that initiated the swap * @param to The address that received the swapped tokens * @param swapForY Whether the swap was for token Y * @param amountsOut The amounts out */ function _afterSwap(address sender, address to, bool swapForY, bytes32 amountsOut) internal virtual {} /** * @notice Internal function to be overridden that is called before a flash loan * @param sender The address that initiated the flash loan * @param to The address that will receive the flash loaned tokens * @param amounts The amounts */ function _beforeFlashLoan(address sender, address to, bytes32 amounts) internal virtual {} /** * @notice Internal function to be overridden that is called after a flash loan * @param sender The address that initiated the flash loan * @param to The address that received the flash loaned tokens * @param fees The flashloan fees * @param feesReceived The fees received */ function _afterFlashLoan(address sender, address to, bytes32 fees, bytes32 feesReceived) internal virtual {} /** * @notice Internal function to be overridden that is called before minting * @param sender The address that initiated the mint * @param to The address that will receive the minted tokens * @param liquidityConfigs The liquidity configurations * @param amountsReceived The amounts received */ function _beforeMint(address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsReceived) internal virtual {} /** * @notice Internal function to be overridden that is called after minting * @param sender The address that initiated the mint * @param to The address that received the minted tokens * @param liquidityConfigs The liquidity configurations * @param amountsIn The amounts in */ function _afterMint(address sender, address to, bytes32[] calldata liquidityConfigs, bytes32 amountsIn) internal virtual {} /** * @notice Internal function to be overridden that is called before burning * @param sender The address that initiated the burn * @param from The address that will burn the tokens * @param to The address that will receive the burned tokens * @param ids The token ids * @param amountsToBurn The amounts to burn */ function _beforeBurn( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn ) internal virtual {} /** * @notice Internal function to be overridden that is called after burning * @param sender The address that initiated the burn * @param from The address that burned the tokens * @param to The address that received the burned tokens * @param ids The token ids * @param amountsToBurn The amounts to burn */ function _afterBurn( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn ) internal virtual {} /** * @notice Internal function to be overridden that is called before a batch transfer * @param sender The address that initiated the transfer * @param from The address that will transfer the tokens * @param to The address that will receive the tokens * @param ids The token ids * @param amounts The amounts */ function _beforeBatchTransferFrom( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amounts ) internal virtual {} /** * @notice Internal function to be overridden that is called after a batch transfer * @param sender The address that initiated the transfer * @param from The address that transferred the tokens * @param to The address that received the tokens * @param ids The token ids * @param amounts The amounts */ function _afterBatchTransferFrom( address sender, address from, address to, uint256[] calldata ids, uint256[] calldata amounts ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {BitMath} from "./BitMath.sol"; /** * @title Liquidity Book Uint256x256 Math Library * @author Trader Joe * @notice Helper contract used for full precision calculations */ library Uint256x256Math { error Uint256x256Math__MulShiftOverflow(); error Uint256x256Math__MulDivOverflow(); /** * @notice Calculates floor(x*y/denominator) with full precision * The result will be rounded down * @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv * Requirements: * - The denominator cannot be zero * - The result must fit within uint256 * Caveats: * - This function does not work with fixed-point numbers * @param x The multiplicand as an uint256 * @param y The multiplier as an uint256 * @param denominator The divisor as an uint256 * @return result The result as an uint256 */ function mulDivRoundDown(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { (uint256 prod0, uint256 prod1) = _getMulProds(x, y); return _getEndOfDivRoundDown(x, y, denominator, prod0, prod1); } /** * @notice Calculates ceil(x*y/denominator) with full precision * The result will be rounded up * @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv * Requirements: * - The denominator cannot be zero * - The result must fit within uint256 * Caveats: * - This function does not work with fixed-point numbers * @param x The multiplicand as an uint256 * @param y The multiplier as an uint256 * @param denominator The divisor as an uint256 * @return result The result as an uint256 */ function mulDivRoundUp(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { result = mulDivRoundDown(x, y, denominator); if (mulmod(x, y, denominator) != 0) result += 1; } /** * @notice Calculates floor(x * y / 2**offset) with full precision * The result will be rounded down * @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv * Requirements: * - The offset needs to be strictly lower than 256 * - The result must fit within uint256 * Caveats: * - This function does not work with fixed-point numbers * @param x The multiplicand as an uint256 * @param y The multiplier as an uint256 * @param offset The offset as an uint256, can't be greater than 256 * @return result The result as an uint256 */ function mulShiftRoundDown(uint256 x, uint256 y, uint8 offset) internal pure returns (uint256 result) { (uint256 prod0, uint256 prod1) = _getMulProds(x, y); if (prod0 != 0) result = prod0 >> offset; if (prod1 != 0) { // Make sure the result is less than 2^256. if (prod1 >= 1 << offset) revert Uint256x256Math__MulShiftOverflow(); unchecked { result += prod1 << (256 - offset); } } } /** * @notice Calculates floor(x * y / 2**offset) with full precision * The result will be rounded down * @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv * Requirements: * - The offset needs to be strictly lower than 256 * - The result must fit within uint256 * Caveats: * - This function does not work with fixed-point numbers * @param x The multiplicand as an uint256 * @param y The multiplier as an uint256 * @param offset The offset as an uint256, can't be greater than 256 * @return result The result as an uint256 */ function mulShiftRoundUp(uint256 x, uint256 y, uint8 offset) internal pure returns (uint256 result) { result = mulShiftRoundDown(x, y, offset); if (mulmod(x, y, 1 << offset) != 0) result += 1; } /** * @notice Calculates floor(x << offset / y) with full precision * The result will be rounded down * @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv * Requirements: * - The offset needs to be strictly lower than 256 * - The result must fit within uint256 * Caveats: * - This function does not work with fixed-point numbers * @param x The multiplicand as an uint256 * @param offset The number of bit to shift x as an uint256 * @param denominator The divisor as an uint256 * @return result The result as an uint256 */ function shiftDivRoundDown(uint256 x, uint8 offset, uint256 denominator) internal pure returns (uint256 result) { uint256 prod0; uint256 prod1; prod0 = x << offset; // Least significant 256 bits of the product unchecked { prod1 = x >> (256 - offset); // Most significant 256 bits of the product } return _getEndOfDivRoundDown(x, 1 << offset, denominator, prod0, prod1); } /** * @notice Calculates ceil(x << offset / y) with full precision * The result will be rounded up * @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv * Requirements: * - The offset needs to be strictly lower than 256 * - The result must fit within uint256 * Caveats: * - This function does not work with fixed-point numbers * @param x The multiplicand as an uint256 * @param offset The number of bit to shift x as an uint256 * @param denominator The divisor as an uint256 * @return result The result as an uint256 */ function shiftDivRoundUp(uint256 x, uint8 offset, uint256 denominator) internal pure returns (uint256 result) { result = shiftDivRoundDown(x, offset, denominator); if (mulmod(x, 1 << offset, denominator) != 0) result += 1; } /** * @notice Helper function to return the result of `x * y` as 2 uint256 * @param x The multiplicand as an uint256 * @param y The multiplier as an uint256 * @return prod0 The least significant 256 bits of the product * @return prod1 The most significant 256 bits of the product */ function _getMulProds(uint256 x, uint256 y) private pure returns (uint256 prod0, uint256 prod1) { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } } /** * @notice Helper function to return the result of `x * y / denominator` with full precision * @param x The multiplicand as an uint256 * @param y The multiplier as an uint256 * @param denominator The divisor as an uint256 * @param prod0 The least significant 256 bits of the product * @param prod1 The most significant 256 bits of the product * @return result The result as an uint256 */ function _getEndOfDivRoundDown(uint256 x, uint256 y, uint256 denominator, uint256 prod0, uint256 prod1) private pure returns (uint256 result) { // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { unchecked { result = prod0 / denominator; } } else { // Make sure the result is less than 2^256. Also prevents denominator == 0 if (prod1 >= denominator) revert Uint256x256Math__MulDivOverflow(); // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1 // See https://cs.stackexchange.com/q/138556/92363 unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function uint256 lpotdod = denominator & (~denominator + 1); assembly { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0 prod0 |= prod1 * lpotdod; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4 uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; } } } /** * @notice Calculates the square root of x * @dev Credit to OpenZeppelin's Math library under MIT license */ function sqrt(uint256 x) internal pure returns (uint256 sqrtX) { if (x == 0) return 0; uint256 msb = BitMath.mostSignificantBit(x); assembly { sqrtX := shl(shr(1, msb), 1) sqrtX := shr(1, add(sqrtX, div(x, sqrtX))) sqrtX := shr(1, add(sqrtX, div(x, sqrtX))) sqrtX := shr(1, add(sqrtX, div(x, sqrtX))) sqrtX := shr(1, add(sqrtX, div(x, sqrtX))) sqrtX := shr(1, add(sqrtX, div(x, sqrtX))) sqrtX := shr(1, add(sqrtX, div(x, sqrtX))) sqrtX := shr(1, add(sqrtX, div(x, sqrtX))) x := div(x, sqrtX) } return sqrtX < x ? sqrtX : x; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /** * @title Clone * @notice Class with helper read functions for clone with immutable args. * @author Trader Joe * @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Clone.sol) * @author Adapted from clones with immutable args by zefram.eth, Saw-mon & Natalie * (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args) */ abstract contract Clone { /** * @dev Reads an immutable arg with type bytes * @param argOffset The offset of the arg in the immutable args * @param length The length of the arg * @return arg The immutable bytes arg */ function _getArgBytes(uint256 argOffset, uint256 length) internal pure returns (bytes memory arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. arg := mload(0x40) // Store the array length. mstore(arg, length) // Copy the array. calldatacopy(add(arg, 0x20), add(offset, argOffset), length) // Allocate the memory, rounded up to the next 32 byte boundary. mstore(0x40, and(add(add(arg, 0x3f), length), not(0x1f))) } } /** * @dev Reads an immutable arg with type address * @param argOffset The offset of the arg in the immutable args * @return arg The immutable address arg */ function _getArgAddress(uint256 argOffset) internal pure returns (address arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(0x60, calldataload(add(offset, argOffset))) } } /** * @dev Reads an immutable arg with type uint256 * @param argOffset The offset of the arg in the immutable args * @return arg The immutable uint256 arg */ function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := calldataload(add(offset, argOffset)) } } /** * @dev Reads a uint256 array stored in the immutable args. * @param argOffset The offset of the arg in the immutable args * @param length The length of the arg * @return arg The immutable uint256 array arg */ function _getArgUint256Array(uint256 argOffset, uint256 length) internal pure returns (uint256[] memory arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. arg := mload(0x40) // Store the array length. mstore(arg, length) // Copy the array. calldatacopy(add(arg, 0x20), add(offset, argOffset), shl(5, length)) // Allocate the memory. mstore(0x40, add(add(arg, 0x20), shl(5, length))) } } /** * @dev Reads an immutable arg with type uint64 * @param argOffset The offset of the arg in the immutable args * @return arg The immutable uint64 arg */ function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(0xc0, calldataload(add(offset, argOffset))) } } /** * @dev Reads an immutable arg with type uint16 * @param argOffset The offset of the arg in the immutable args * @return arg The immutable uint16 arg */ function _getArgUint16(uint256 argOffset) internal pure returns (uint16 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(0xf0, calldataload(add(offset, argOffset))) } } /** * @dev Reads an immutable arg with type uint8 * @param argOffset The offset of the arg in the immutable args * @return arg The immutable uint8 arg */ function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) { uint256 offset = _getImmutableArgsOffset(); /// @solidity memory-safe-assembly assembly { arg := shr(0xf8, calldataload(add(offset, argOffset))) } } /** * @dev Reads the offset of the packed immutable args in calldata. * @return offset The offset of the packed immutable args in calldata. */ function _getImmutableArgsOffset() internal pure returns (uint256 offset) { /// @solidity memory-safe-assembly assembly { offset := sub(calldatasize(), shr(0xf0, calldataload(sub(calldatasize(), 2)))) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {Hooks} from "../libraries/Hooks.sol"; import {ILBFactory} from "./ILBFactory.sol"; import {ILBFlashLoanCallback} from "./ILBFlashLoanCallback.sol"; import {ILBToken} from "./ILBToken.sol"; interface ILBPair is ILBToken { error LBPair__ZeroBorrowAmount(); error LBPair__AddressZero(); error LBPair__EmptyMarketConfigs(); error LBPair__FlashLoanCallbackFailed(); error LBPair__FlashLoanInsufficientAmount(); error LBPair__InsufficientAmountIn(); error LBPair__InsufficientAmountOut(); error LBPair__InvalidInput(); error LBPair__InvalidStaticFeeParameters(); error LBPair__OnlyFactory(); error LBPair__OnlyProtocolFeeRecipient(); error LBPair__OutOfLiquidity(); error LBPair__TokenNotSupported(); error LBPair__ZeroAmount(uint24 id); error LBPair__ZeroAmountsOut(uint24 id); error LBPair__ZeroShares(uint24 id); error LBPair__MaxTotalFeeExceeded(); error LBPair__InvalidHooks(); struct MintArrays { uint256[] ids; bytes32[] amounts; uint256[] liquidityMinted; } event DepositedToBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts); event WithdrawnFromBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts); event CompositionFees(address indexed sender, uint24 id, bytes32 totalFees, bytes32 protocolFees); event CollectedProtocolFees(address indexed feeRecipient, bytes32 protocolFees); event Swap( address indexed sender, address indexed to, uint24 id, bytes32 amountsIn, bytes32 amountsOut, uint24 volatilityAccumulator, bytes32 totalFees, bytes32 protocolFees ); event StaticFeeParametersSet( address indexed sender, uint16 baseFactor, uint16 filterPeriod, uint16 decayPeriod, uint16 reductionFactor, uint24 variableFeeControl, uint16 protocolShare, uint24 maxVolatilityAccumulator ); event HooksParametersSet(address indexed sender, bytes32 hooksParameters); event FlashLoan( address indexed sender, ILBFlashLoanCallback indexed receiver, uint24 activeId, bytes32 amounts, bytes32 totalFees, bytes32 protocolFees ); event OracleLengthIncreased(address indexed sender, uint16 oracleLength); event ForcedDecay(address indexed sender, uint24 idReference, uint24 volatilityReference); function initialize( uint16 baseFactor, uint16 filterPeriod, uint16 decayPeriod, uint16 reductionFactor, uint24 variableFeeControl, uint16 protocolShare, uint24 maxVolatilityAccumulator, uint24 activeId ) external; function implementation() external view returns (address); function getFactory() external view returns (ILBFactory factory); function getTokenX() external view returns (IERC20 tokenX); function getTokenY() external view returns (IERC20 tokenY); function getBinStep() external view returns (uint16 binStep); function getReserves() external view returns (uint128 reserveX, uint128 reserveY); function getActiveId() external view returns (uint24 activeId); function getBin(uint24 id) external view returns (uint128 binReserveX, uint128 binReserveY); function getNextNonEmptyBin(bool swapForY, uint24 id) external view returns (uint24 nextId); function getProtocolFees() external view returns (uint128 protocolFeeX, uint128 protocolFeeY); function getStaticFeeParameters() external view returns ( uint16 baseFactor, uint16 filterPeriod, uint16 decayPeriod, uint16 reductionFactor, uint24 variableFeeControl, uint16 protocolShare, uint24 maxVolatilityAccumulator ); function getLBHooksParameters() external view returns (bytes32 hooksParameters); function getVariableFeeParameters() external view returns (uint24 volatilityAccumulator, uint24 volatilityReference, uint24 idReference, uint40 timeOfLastUpdate); function getOracleParameters() external view returns (uint8 sampleLifetime, uint16 size, uint16 activeSize, uint40 lastUpdated, uint40 firstTimestamp); function getOracleSampleAt(uint40 lookupTimestamp) external view returns (uint64 cumulativeId, uint64 cumulativeVolatility, uint64 cumulativeBinCrossed); function getPriceFromId(uint24 id) external view returns (uint256 price); function getIdFromPrice(uint256 price) external view returns (uint24 id); function getSwapIn(uint128 amountOut, bool swapForY) external view returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee); function getSwapOut(uint128 amountIn, bool swapForY) external view returns (uint128 amountInLeft, uint128 amountOut, uint128 fee); function swap(bool swapForY, address to) external returns (bytes32 amountsOut); function flashLoan(ILBFlashLoanCallback receiver, bytes32 amounts, bytes calldata data) external; function mint(address to, bytes32[] calldata liquidityConfigs, address refundTo) external returns (bytes32 amountsReceived, bytes32 amountsLeft, uint256[] memory liquidityMinted); function burn(address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn) external returns (bytes32[] memory amounts); function collectProtocolFees() external returns (bytes32 collectedProtocolFees); function increaseOracleLength(uint16 newLength) external; function setStaticFeeParameters( uint16 baseFactor, uint16 filterPeriod, uint16 decayPeriod, uint16 reductionFactor, uint24 variableFeeControl, uint16 protocolShare, uint24 maxVolatilityAccumulator ) external; function setHooksParameters(bytes32 hooksParameters, bytes calldata onHooksSetData) external; function forceDecay() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {Uint128x128Math} from "./math/Uint128x128Math.sol"; import {Uint256x256Math} from "./math/Uint256x256Math.sol"; import {SafeCast} from "./math/SafeCast.sol"; import {Constants} from "./Constants.sol"; /** * @title Liquidity Book Price Helper Library * @author Trader Joe * @notice This library contains functions to calculate prices */ library PriceHelper { using Uint128x128Math for uint256; using Uint256x256Math for uint256; using SafeCast for uint256; int256 private constant REAL_ID_SHIFT = 1 << 23; /** * @dev Calculates the price from the id and the bin step * @param id The id * @param binStep The bin step * @return price The price as a 128.128-binary fixed-point number */ function getPriceFromId(uint24 id, uint16 binStep) internal pure returns (uint256 price) { uint256 base = getBase(binStep); int256 exponent = getExponent(id); price = base.pow(exponent); } /** * @dev Calculates the id from the price and the bin step * @param price The price as a 128.128-binary fixed-point number * @param binStep The bin step * @return id The id */ function getIdFromPrice(uint256 price, uint16 binStep) internal pure returns (uint24 id) { uint256 base = getBase(binStep); int256 realId = price.log2() / base.log2(); unchecked { id = uint256(REAL_ID_SHIFT + realId).safe24(); } } /** * @dev Calculates the base from the bin step, which is `1 + binStep / BASIS_POINT_MAX` * @param binStep The bin step * @return base The base */ function getBase(uint16 binStep) internal pure returns (uint256) { unchecked { return Constants.SCALE + (uint256(binStep) << Constants.SCALE_OFFSET) / Constants.BASIS_POINT_MAX; } } /** * @dev Calculates the exponent from the id, which is `id - REAL_ID_SHIFT` * @param id The id * @return exponent The exponent */ function getExponent(uint24 id) internal pure returns (int256) { unchecked { return int256(uint256(id)) - REAL_ID_SHIFT; } } /** * @dev Converts a price with 18 decimals to a 128.128-binary fixed-point number * @param price The price with 18 decimals * @return price128x128 The 128.128-binary fixed-point number */ function convertDecimalPriceTo128x128(uint256 price) internal pure returns (uint256) { return price.shiftDivRoundDown(Constants.SCALE_OFFSET, Constants.PRECISION); } /** * @dev Converts a 128.128-binary fixed-point number to a price with 18 decimals * @param price128x128 The 128.128-binary fixed-point number * @return price The price with 18 decimals */ function convert128x128PriceToDecimal(uint256 price128x128) internal pure returns (uint256) { return price128x128.mulShiftRoundDown(Constants.PRECISION, Constants.SCALE_OFFSET); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {PackedUint128Math} from "./math/PackedUint128Math.sol"; import {Uint256x256Math} from "./math/Uint256x256Math.sol"; import {SafeCast} from "./math/SafeCast.sol"; import {Constants} from "./Constants.sol"; import {PairParameterHelper} from "./PairParameterHelper.sol"; import {FeeHelper} from "./FeeHelper.sol"; import {PriceHelper} from "./PriceHelper.sol"; import {TokenHelper, IERC20} from "./TokenHelper.sol"; /** * @title Liquidity Book Bin Helper Library * @author Trader Joe * @notice This library contains functions to help interaction with bins. */ library BinHelper { using PackedUint128Math for bytes32; using PackedUint128Math for uint128; using Uint256x256Math for uint256; using PriceHelper for uint24; using SafeCast for uint256; using PairParameterHelper for bytes32; using FeeHelper for uint128; using TokenHelper for IERC20; error BinHelper__CompositionFactorFlawed(uint24 id); error BinHelper__LiquidityOverflow(); error BinHelper__MaxLiquidityPerBinExceeded(); /** * @dev Returns the amount of tokens that will be received when burning the given amount of liquidity * @param binReserves The reserves of the bin * @param amountToBurn The amount of liquidity to burn * @param totalSupply The total supply of the liquidity book * @return amountsOut The encoded amount of tokens that will be received */ function getAmountOutOfBin(bytes32 binReserves, uint256 amountToBurn, uint256 totalSupply) internal pure returns (bytes32 amountsOut) { (uint128 binReserveX, uint128 binReserveY) = binReserves.decode(); uint128 amountXOutFromBin; uint128 amountYOutFromBin; if (binReserveX > 0) { amountXOutFromBin = (amountToBurn.mulDivRoundDown(binReserveX, totalSupply)).safe128(); } if (binReserveY > 0) { amountYOutFromBin = (amountToBurn.mulDivRoundDown(binReserveY, totalSupply)).safe128(); } amountsOut = amountXOutFromBin.encode(amountYOutFromBin); } /** * @dev Returns the share and the effective amounts in when adding liquidity * @param binReserves The reserves of the bin * @param amountsIn The amounts of tokens to add * @param price The price of the bin * @param totalSupply The total supply of the liquidity book * @return shares The share of the liquidity book that the user will receive * @return effectiveAmountsIn The encoded effective amounts of tokens that the user will add. * This is the amount of tokens that the user will actually add to the liquidity book, * and will always be less than or equal to the amountsIn. */ function getSharesAndEffectiveAmountsIn(bytes32 binReserves, bytes32 amountsIn, uint256 price, uint256 totalSupply) internal pure returns (uint256 shares, bytes32 effectiveAmountsIn) { (uint256 x, uint256 y) = amountsIn.decode(); uint256 userLiquidity = getLiquidity(x, y, price); if (userLiquidity == 0) return (0, 0); uint256 binLiquidity = getLiquidity(binReserves, price); if (binLiquidity == 0 || totalSupply == 0) return (userLiquidity.sqrt(), amountsIn); shares = userLiquidity.mulDivRoundDown(totalSupply, binLiquidity); uint256 effectiveLiquidity = shares.mulDivRoundUp(binLiquidity, totalSupply); if (userLiquidity > effectiveLiquidity) { uint256 deltaLiquidity = userLiquidity - effectiveLiquidity; // The other way might be more efficient, but as y is the quote asset, it is more valuable if (deltaLiquidity >= Constants.SCALE) { uint256 deltaY = deltaLiquidity >> Constants.SCALE_OFFSET; deltaY = deltaY > y ? y : deltaY; y -= deltaY; deltaLiquidity -= deltaY << Constants.SCALE_OFFSET; } if (deltaLiquidity >= price) { uint256 deltaX = deltaLiquidity / price; deltaX = deltaX > x ? x : deltaX; x -= deltaX; } amountsIn = uint128(x).encode(uint128(y)); } if (getLiquidity(binReserves.add(amountsIn), price) > Constants.MAX_LIQUIDITY_PER_BIN) { revert BinHelper__MaxLiquidityPerBinExceeded(); } return (shares, amountsIn); } /** * @dev Returns the amount of liquidity following the constant sum formula `L = price * x + y` * @param amounts The amounts of tokens * @param price The price of the bin * @return liquidity The amount of liquidity */ function getLiquidity(bytes32 amounts, uint256 price) internal pure returns (uint256 liquidity) { (uint256 x, uint256 y) = amounts.decode(); return getLiquidity(x, y, price); } /** * @dev Returns the amount of liquidity following the constant sum formula `L = price * x + y` * @param x The amount of the token X * @param y The amount of the token Y * @param price The price of the bin * @return liquidity The amount of liquidity */ function getLiquidity(uint256 x, uint256 y, uint256 price) internal pure returns (uint256 liquidity) { if (x > 0) { unchecked { liquidity = price * x; if (liquidity / x != price) revert BinHelper__LiquidityOverflow(); } } if (y > 0) { unchecked { y <<= Constants.SCALE_OFFSET; liquidity += y; if (liquidity < y) revert BinHelper__LiquidityOverflow(); } } return liquidity; } /** * @dev Verify that the amounts are correct and that the composition factor is not flawed * @param amounts The amounts of tokens * @param activeId The id of the active bin * @param id The id of the bin */ function verifyAmounts(bytes32 amounts, uint24 activeId, uint24 id) internal pure { if (id < activeId && (amounts << 128) > 0 || id > activeId && uint256(amounts) > type(uint128).max) { revert BinHelper__CompositionFactorFlawed(id); } } /** * @dev Returns the composition fees when adding liquidity to the active bin with a different * composition factor than the bin's one, as it does an implicit swap * @param binReserves The reserves of the bin * @param parameters The parameters of the liquidity book * @param binStep The step of the bin * @param amountsIn The amounts of tokens to add * @param totalSupply The total supply of the liquidity book * @param shares The share of the liquidity book that the user will receive * @return fees The encoded fees that will be charged */ function getCompositionFees( bytes32 binReserves, bytes32 parameters, uint16 binStep, bytes32 amountsIn, uint256 totalSupply, uint256 shares ) internal pure returns (bytes32 fees) { if (shares == 0) return 0; (uint128 amountX, uint128 amountY) = amountsIn.decode(); (uint128 receivedAmountX, uint128 receivedAmountY) = getAmountOutOfBin(binReserves.add(amountsIn), shares, totalSupply + shares).decode(); if (receivedAmountX > amountX) { uint128 feeY = (amountY - receivedAmountY).getCompositionFee(parameters.getTotalFee(binStep)); fees = feeY.encodeSecond(); } else if (receivedAmountY > amountY) { uint128 feeX = (amountX - receivedAmountX).getCompositionFee(parameters.getTotalFee(binStep)); fees = feeX.encodeFirst(); } } /** * @dev Returns whether the bin is empty (true) or not (false) * @param binReserves The reserves of the bin * @param isX Whether the reserve to check is the X reserve (true) or the Y reserve (false) * @return Whether the bin is empty (true) or not (false) */ function isEmpty(bytes32 binReserves, bool isX) internal pure returns (bool) { return isX ? binReserves.decodeX() == 0 : binReserves.decodeY() == 0; } /** * @dev Returns the amounts of tokens that will be added and removed from the bin during a swap * along with the fees that will be charged * @param binReserves The reserves of the bin * @param parameters The parameters of the liquidity book * @param binStep The step of the bin * @param swapForY Whether the swap is for Y (true) or for X (false) * @param activeId The id of the active bin * @param amountsInLeft The amounts of tokens left to swap * @return amountsInWithFees The encoded amounts of tokens that will be added to the bin, including fees * @return amountsOutOfBin The encoded amounts of tokens that will be removed from the bin * @return totalFees The encoded fees that will be charged */ function getAmounts( bytes32 binReserves, bytes32 parameters, uint16 binStep, bool swapForY, // swap `swapForY` and `activeId` to avoid stack too deep uint24 activeId, bytes32 amountsInLeft ) internal pure returns (bytes32 amountsInWithFees, bytes32 amountsOutOfBin, bytes32 totalFees) { uint256 price = activeId.getPriceFromId(binStep); { uint128 binReserveOut = binReserves.decode(!swapForY); uint128 maxAmountIn = swapForY ? uint256(binReserveOut).shiftDivRoundUp(Constants.SCALE_OFFSET, price).safe128() : uint256(binReserveOut).mulShiftRoundUp(price, Constants.SCALE_OFFSET).safe128(); uint128 totalFee = parameters.getTotalFee(binStep); uint128 maxFee = maxAmountIn.getFeeAmount(totalFee); maxAmountIn += maxFee; uint128 amountIn128 = amountsInLeft.decode(swapForY); uint128 fee128; uint128 amountOut128; if (amountIn128 >= maxAmountIn) { fee128 = maxFee; amountIn128 = maxAmountIn; amountOut128 = binReserveOut; } else { fee128 = amountIn128.getFeeAmountFrom(totalFee); uint256 amountIn = amountIn128 - fee128; amountOut128 = swapForY ? uint256(amountIn).mulShiftRoundDown(price, Constants.SCALE_OFFSET).safe128() : uint256(amountIn).shiftDivRoundDown(Constants.SCALE_OFFSET, price).safe128(); if (amountOut128 > binReserveOut) amountOut128 = binReserveOut; } (amountsInWithFees, amountsOutOfBin, totalFees) = swapForY ? (amountIn128.encodeFirst(), amountOut128.encodeSecond(), fee128.encodeFirst()) : (amountIn128.encodeSecond(), amountOut128.encodeFirst(), fee128.encodeSecond()); } if ( getLiquidity(binReserves.add(amountsInWithFees).sub(amountsOutOfBin), price) > Constants.MAX_LIQUIDITY_PER_BIN ) { revert BinHelper__MaxLiquidityPerBinExceeded(); } } /** * @dev Returns the encoded amounts that were transferred to the contract * @param reserves The reserves * @param tokenX The token X * @param tokenY The token Y * @return amounts The amounts, encoded as follows: * [0 - 128[: amountX * [128 - 256[: amountY */ function received(bytes32 reserves, IERC20 tokenX, IERC20 tokenY) internal view returns (bytes32 amounts) { amounts = _balanceOf(tokenX).encode(_balanceOf(tokenY)).sub(reserves); } /** * @dev Returns the encoded amounts that were transferred to the contract, only for token X * @param reserves The reserves * @param tokenX The token X * @return amounts The amounts, encoded as follows: * [0 - 128[: amountX * [128 - 256[: empty */ function receivedX(bytes32 reserves, IERC20 tokenX) internal view returns (bytes32) { uint128 reserveX = reserves.decodeX(); return (_balanceOf(tokenX) - reserveX).encodeFirst(); } /** * @dev Returns the encoded amounts that were transferred to the contract, only for token Y * @param reserves The reserves * @param tokenY The token Y * @return amounts The amounts, encoded as follows: * [0 - 128[: empty * [128 - 256[: amountY */ function receivedY(bytes32 reserves, IERC20 tokenY) internal view returns (bytes32) { uint128 reserveY = reserves.decodeY(); return (_balanceOf(tokenY) - reserveY).encodeSecond(); } /** * @dev Transfers the encoded amounts to the recipient * @param amounts The amounts, encoded as follows: * [0 - 128[: amountX * [128 - 256[: amountY * @param tokenX The token X * @param tokenY The token Y * @param recipient The recipient */ function transfer(bytes32 amounts, IERC20 tokenX, IERC20 tokenY, address recipient) internal { (uint128 amountX, uint128 amountY) = amounts.decode(); if (amountX > 0) tokenX.safeTransfer(recipient, amountX); if (amountY > 0) tokenY.safeTransfer(recipient, amountY); } /** * @dev Transfers the encoded amounts to the recipient, only for token X * @param amounts The amounts, encoded as follows: * [0 - 128[: amountX * [128 - 256[: empty * @param tokenX The token X * @param recipient The recipient */ function transferX(bytes32 amounts, IERC20 tokenX, address recipient) internal { uint128 amountX = amounts.decodeX(); if (amountX > 0) tokenX.safeTransfer(recipient, amountX); } /** * @dev Transfers the encoded amounts to the recipient, only for token Y * @param amounts The amounts, encoded as follows: * [0 - 128[: empty * [128 - 256[: amountY * @param tokenY The token Y * @param recipient The recipient */ function transferY(bytes32 amounts, IERC20 tokenY, address recipient) internal { uint128 amountY = amounts.decodeY(); if (amountY > 0) tokenY.safeTransfer(recipient, amountY); } function _balanceOf(IERC20 token) private view returns (uint128) { return token.balanceOf(address(this)).safe128(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /** * @title Liquidity Book Safe Cast Library * @author Trader Joe * @notice This library contains functions to safely cast uint256 to different uint types. */ library SafeCast { error SafeCast__Exceeds248Bits(); error SafeCast__Exceeds240Bits(); error SafeCast__Exceeds232Bits(); error SafeCast__Exceeds224Bits(); error SafeCast__Exceeds216Bits(); error SafeCast__Exceeds208Bits(); error SafeCast__Exceeds200Bits(); error SafeCast__Exceeds192Bits(); error SafeCast__Exceeds184Bits(); error SafeCast__Exceeds176Bits(); error SafeCast__Exceeds168Bits(); error SafeCast__Exceeds160Bits(); error SafeCast__Exceeds152Bits(); error SafeCast__Exceeds144Bits(); error SafeCast__Exceeds136Bits(); error SafeCast__Exceeds128Bits(); error SafeCast__Exceeds120Bits(); error SafeCast__Exceeds112Bits(); error SafeCast__Exceeds104Bits(); error SafeCast__Exceeds96Bits(); error SafeCast__Exceeds88Bits(); error SafeCast__Exceeds80Bits(); error SafeCast__Exceeds72Bits(); error SafeCast__Exceeds64Bits(); error SafeCast__Exceeds56Bits(); error SafeCast__Exceeds48Bits(); error SafeCast__Exceeds40Bits(); error SafeCast__Exceeds32Bits(); error SafeCast__Exceeds24Bits(); error SafeCast__Exceeds16Bits(); error SafeCast__Exceeds8Bits(); /** * @dev Returns x on uint248 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint248 */ function safe248(uint256 x) internal pure returns (uint248 y) { if ((y = uint248(x)) != x) revert SafeCast__Exceeds248Bits(); } /** * @dev Returns x on uint240 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint240 */ function safe240(uint256 x) internal pure returns (uint240 y) { if ((y = uint240(x)) != x) revert SafeCast__Exceeds240Bits(); } /** * @dev Returns x on uint232 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint232 */ function safe232(uint256 x) internal pure returns (uint232 y) { if ((y = uint232(x)) != x) revert SafeCast__Exceeds232Bits(); } /** * @dev Returns x on uint224 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint224 */ function safe224(uint256 x) internal pure returns (uint224 y) { if ((y = uint224(x)) != x) revert SafeCast__Exceeds224Bits(); } /** * @dev Returns x on uint216 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint216 */ function safe216(uint256 x) internal pure returns (uint216 y) { if ((y = uint216(x)) != x) revert SafeCast__Exceeds216Bits(); } /** * @dev Returns x on uint208 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint208 */ function safe208(uint256 x) internal pure returns (uint208 y) { if ((y = uint208(x)) != x) revert SafeCast__Exceeds208Bits(); } /** * @dev Returns x on uint200 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint200 */ function safe200(uint256 x) internal pure returns (uint200 y) { if ((y = uint200(x)) != x) revert SafeCast__Exceeds200Bits(); } /** * @dev Returns x on uint192 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint192 */ function safe192(uint256 x) internal pure returns (uint192 y) { if ((y = uint192(x)) != x) revert SafeCast__Exceeds192Bits(); } /** * @dev Returns x on uint184 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint184 */ function safe184(uint256 x) internal pure returns (uint184 y) { if ((y = uint184(x)) != x) revert SafeCast__Exceeds184Bits(); } /** * @dev Returns x on uint176 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint176 */ function safe176(uint256 x) internal pure returns (uint176 y) { if ((y = uint176(x)) != x) revert SafeCast__Exceeds176Bits(); } /** * @dev Returns x on uint168 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint168 */ function safe168(uint256 x) internal pure returns (uint168 y) { if ((y = uint168(x)) != x) revert SafeCast__Exceeds168Bits(); } /** * @dev Returns x on uint160 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint160 */ function safe160(uint256 x) internal pure returns (uint160 y) { if ((y = uint160(x)) != x) revert SafeCast__Exceeds160Bits(); } /** * @dev Returns x on uint152 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint152 */ function safe152(uint256 x) internal pure returns (uint152 y) { if ((y = uint152(x)) != x) revert SafeCast__Exceeds152Bits(); } /** * @dev Returns x on uint144 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint144 */ function safe144(uint256 x) internal pure returns (uint144 y) { if ((y = uint144(x)) != x) revert SafeCast__Exceeds144Bits(); } /** * @dev Returns x on uint136 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint136 */ function safe136(uint256 x) internal pure returns (uint136 y) { if ((y = uint136(x)) != x) revert SafeCast__Exceeds136Bits(); } /** * @dev Returns x on uint128 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint128 */ function safe128(uint256 x) internal pure returns (uint128 y) { if ((y = uint128(x)) != x) revert SafeCast__Exceeds128Bits(); } /** * @dev Returns x on uint120 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint120 */ function safe120(uint256 x) internal pure returns (uint120 y) { if ((y = uint120(x)) != x) revert SafeCast__Exceeds120Bits(); } /** * @dev Returns x on uint112 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint112 */ function safe112(uint256 x) internal pure returns (uint112 y) { if ((y = uint112(x)) != x) revert SafeCast__Exceeds112Bits(); } /** * @dev Returns x on uint104 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint104 */ function safe104(uint256 x) internal pure returns (uint104 y) { if ((y = uint104(x)) != x) revert SafeCast__Exceeds104Bits(); } /** * @dev Returns x on uint96 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint96 */ function safe96(uint256 x) internal pure returns (uint96 y) { if ((y = uint96(x)) != x) revert SafeCast__Exceeds96Bits(); } /** * @dev Returns x on uint88 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint88 */ function safe88(uint256 x) internal pure returns (uint88 y) { if ((y = uint88(x)) != x) revert SafeCast__Exceeds88Bits(); } /** * @dev Returns x on uint80 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint80 */ function safe80(uint256 x) internal pure returns (uint80 y) { if ((y = uint80(x)) != x) revert SafeCast__Exceeds80Bits(); } /** * @dev Returns x on uint72 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint72 */ function safe72(uint256 x) internal pure returns (uint72 y) { if ((y = uint72(x)) != x) revert SafeCast__Exceeds72Bits(); } /** * @dev Returns x on uint64 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint64 */ function safe64(uint256 x) internal pure returns (uint64 y) { if ((y = uint64(x)) != x) revert SafeCast__Exceeds64Bits(); } /** * @dev Returns x on uint56 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint56 */ function safe56(uint256 x) internal pure returns (uint56 y) { if ((y = uint56(x)) != x) revert SafeCast__Exceeds56Bits(); } /** * @dev Returns x on uint48 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint48 */ function safe48(uint256 x) internal pure returns (uint48 y) { if ((y = uint48(x)) != x) revert SafeCast__Exceeds48Bits(); } /** * @dev Returns x on uint40 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint40 */ function safe40(uint256 x) internal pure returns (uint40 y) { if ((y = uint40(x)) != x) revert SafeCast__Exceeds40Bits(); } /** * @dev Returns x on uint32 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint32 */ function safe32(uint256 x) internal pure returns (uint32 y) { if ((y = uint32(x)) != x) revert SafeCast__Exceeds32Bits(); } /** * @dev Returns x on uint24 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint24 */ function safe24(uint256 x) internal pure returns (uint24 y) { if ((y = uint24(x)) != x) revert SafeCast__Exceeds24Bits(); } /** * @dev Returns x on uint16 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint16 */ function safe16(uint256 x) internal pure returns (uint16 y) { if ((y = uint16(x)) != x) revert SafeCast__Exceeds16Bits(); } /** * @dev Returns x on uint8 and check that it does not overflow * @param x The value as an uint256 * @return y The value as an uint8 */ function safe8(uint256 x) internal pure returns (uint8 y) { if ((y = uint8(x)) != x) revert SafeCast__Exceeds8Bits(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ILBHooksBaseRewarder} from "./ILBHooksBaseRewarder.sol"; /** * @title LB Hooks Simple Rewarder Interface * @dev Interface for the LB Hooks Simple Rewarder */ interface ILBHooksBaseSimpleRewarder is ILBHooksBaseRewarder { error LBHooksBaseSimpleRewarder__InvalidStartTimestamp(); error LBHooksBaseSimpleRewarder__InvalidDuration(); error LBHooksBaseSimpleRewarder__ZeroReward(); error LBHooksBaseSimpleRewarder__Stopped(); event RewardParameterUpdated(uint256 rewardPerSecond, uint256 startTimestamp, uint256 endTimestamp); function getRewarderParameter() external view returns (uint256 rewardPerSecond, uint256 lastUpdateTimestamp, uint256 endTimestamp); function getRemainingRewards() external view returns (uint256 remainingRewards); function setRewarderParameters(uint256 maxRewardPerSecond, uint256 startTimestamp, uint256 expectedDuration) external returns (uint256 rewardPerSecond); function setRewardPerSecond(uint256 maxRewardPerSecond, uint256 expectedDuration) external returns (uint256 rewardPerSecond); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /** * @title Liquidity Book Bit Math Library * @author Trader Joe * @notice Helper contract used for bit calculations */ library BitMath { /** * @dev Returns the index of the closest bit on the right of x that is non null * @param x The value as a uint256 * @param bit The index of the bit to start searching at * @return id The index of the closest non null bit on the right of x. * If there is no closest bit, it returns max(uint256) */ function closestBitRight(uint256 x, uint8 bit) internal pure returns (uint256 id) { unchecked { uint256 shift = 255 - bit; x <<= shift; // can't overflow as it's non-zero and we shifted it by `_shift` return (x == 0) ? type(uint256).max : mostSignificantBit(x) - shift; } } /** * @dev Returns the index of the closest bit on the left of x that is non null * @param x The value as a uint256 * @param bit The index of the bit to start searching at * @return id The index of the closest non null bit on the left of x. * If there is no closest bit, it returns max(uint256) */ function closestBitLeft(uint256 x, uint8 bit) internal pure returns (uint256 id) { unchecked { x >>= bit; return (x == 0) ? type(uint256).max : leastSignificantBit(x) + bit; } } /** * @dev Returns the index of the most significant bit of x * This function returns 0 if x is 0 * @param x The value as a uint256 * @return msb The index of the most significant bit of x */ function mostSignificantBit(uint256 x) internal pure returns (uint8 msb) { assembly { if gt(x, 0xffffffffffffffffffffffffffffffff) { x := shr(128, x) msb := 128 } if gt(x, 0xffffffffffffffff) { x := shr(64, x) msb := add(msb, 64) } if gt(x, 0xffffffff) { x := shr(32, x) msb := add(msb, 32) } if gt(x, 0xffff) { x := shr(16, x) msb := add(msb, 16) } if gt(x, 0xff) { x := shr(8, x) msb := add(msb, 8) } if gt(x, 0xf) { x := shr(4, x) msb := add(msb, 4) } if gt(x, 0x3) { x := shr(2, x) msb := add(msb, 2) } if gt(x, 0x1) { msb := add(msb, 1) } } } /** * @dev Returns the index of the least significant bit of x * This function returns 255 if x is 0 * @param x The value as a uint256 * @return lsb The index of the least significant bit of x */ function leastSignificantBit(uint256 x) internal pure returns (uint8 lsb) { assembly { let sx := shl(128, x) if iszero(iszero(sx)) { lsb := 128 x := sx } sx := shl(64, x) if iszero(iszero(sx)) { x := sx lsb := add(lsb, 64) } sx := shl(32, x) if iszero(iszero(sx)) { x := sx lsb := add(lsb, 32) } sx := shl(16, x) if iszero(iszero(sx)) { x := sx lsb := add(lsb, 16) } sx := shl(8, x) if iszero(iszero(sx)) { x := sx lsb := add(lsb, 8) } sx := shl(4, x) if iszero(iszero(sx)) { x := sx lsb := add(lsb, 4) } sx := shl(2, x) if iszero(iszero(sx)) { x := sx lsb := add(lsb, 2) } if iszero(iszero(shl(1, x))) { lsb := add(lsb, 1) } lsb := sub(255, lsb) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ILBHooks} from "./ILBHooks.sol"; import {ILBPair} from "./ILBPair.sol"; /** * @title Liquidity Book Factory Interface * @author Trader Joe * @notice Required interface of LBFactory contract */ interface ILBFactory { error LBFactory__IdenticalAddresses(IERC20 token); error LBFactory__QuoteAssetNotWhitelisted(IERC20 quoteAsset); error LBFactory__QuoteAssetAlreadyWhitelisted(IERC20 quoteAsset); error LBFactory__AddressZero(); error LBFactory__LBPairAlreadyExists(IERC20 tokenX, IERC20 tokenY, uint256 _binStep); error LBFactory__LBPairDoesNotExist(IERC20 tokenX, IERC20 tokenY, uint256 binStep); error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint256 binStep); error LBFactory__FlashLoanFeeAboveMax(uint256 fees, uint256 maxFees); error LBFactory__BinStepTooLow(uint256 binStep); error LBFactory__PresetIsLockedForUsers(address user, uint256 binStep); error LBFactory__LBPairIgnoredIsAlreadyInTheSameState(); error LBFactory__BinStepHasNoPreset(uint256 binStep); error LBFactory__PresetOpenStateIsAlreadyInTheSameState(); error LBFactory__SameFeeRecipient(address feeRecipient); error LBFactory__SameFlashLoanFee(uint256 flashLoanFee); error LBFactory__LBPairSafetyCheckFailed(address LBPairImplementation); error LBFactory__SameImplementation(address LBPairImplementation); error LBFactory__ImplementationNotSet(); error LBFactory__SameHooksImplementation(address hooksImplementation); error LBFactory__SameHooksParameters(bytes32 hooksParameters); error LBFactory__InvalidHooksParameters(); error LBFactory__CannotGrantDefaultAdminRole(); /** * @dev Structure to store the LBPair information, such as: * binStep: The bin step of the LBPair * LBPair: The address of the LBPair * createdByOwner: Whether the pair was created by the owner of the factory * ignoredForRouting: Whether the pair is ignored for routing or not. An ignored pair will not be explored during routes finding */ struct LBPairInformation { uint16 binStep; ILBPair LBPair; bool createdByOwner; bool ignoredForRouting; } event LBPairCreated( IERC20 indexed tokenX, IERC20 indexed tokenY, uint256 indexed binStep, ILBPair LBPair, uint256 pid ); event FeeRecipientSet(address oldRecipient, address newRecipient); event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee); event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation); event LBPairIgnoredStateChanged(ILBPair indexed LBPair, bool ignored); event PresetSet( uint256 indexed binStep, uint256 baseFactor, uint256 filterPeriod, uint256 decayPeriod, uint256 reductionFactor, uint256 variableFeeControl, uint256 protocolShare, uint256 maxVolatilityAccumulator ); event PresetOpenStateChanged(uint256 indexed binStep, bool indexed isOpen); event PresetRemoved(uint256 indexed binStep); event QuoteAssetAdded(IERC20 indexed quoteAsset); event QuoteAssetRemoved(IERC20 indexed quoteAsset); function getMinBinStep() external pure returns (uint256); function getFeeRecipient() external view returns (address); function getMaxFlashLoanFee() external pure returns (uint256); function getFlashLoanFee() external view returns (uint256); function getLBPairImplementation() external view returns (address); function getNumberOfLBPairs() external view returns (uint256); function getLBPairAtIndex(uint256 id) external returns (ILBPair); function getNumberOfQuoteAssets() external view returns (uint256); function getQuoteAssetAtIndex(uint256 index) external view returns (IERC20); function isQuoteAsset(IERC20 token) external view returns (bool); function getLBPairInformation(IERC20 tokenX, IERC20 tokenY, uint256 binStep) external view returns (LBPairInformation memory); function getPreset(uint256 binStep) external view returns ( uint256 baseFactor, uint256 filterPeriod, uint256 decayPeriod, uint256 reductionFactor, uint256 variableFeeControl, uint256 protocolShare, uint256 maxAccumulator, bool isOpen ); function getAllBinSteps() external view returns (uint256[] memory presetsBinStep); function getOpenBinSteps() external view returns (uint256[] memory openBinStep); function getAllLBPairs(IERC20 tokenX, IERC20 tokenY) external view returns (LBPairInformation[] memory LBPairsBinStep); function setLBPairImplementation(address lbPairImplementation) external; function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep) external returns (ILBPair pair); function setLBPairIgnored(IERC20 tokenX, IERC20 tokenY, uint16 binStep, bool ignored) external; function setPreset( uint16 binStep, uint16 baseFactor, uint16 filterPeriod, uint16 decayPeriod, uint16 reductionFactor, uint24 variableFeeControl, uint16 protocolShare, uint24 maxVolatilityAccumulator, bool isOpen ) external; function setPresetOpenState(uint16 binStep, bool isOpen) external; function removePreset(uint16 binStep) external; function setFeesParametersOnPair( IERC20 tokenX, IERC20 tokenY, uint16 binStep, uint16 baseFactor, uint16 filterPeriod, uint16 decayPeriod, uint16 reductionFactor, uint24 variableFeeControl, uint16 protocolShare, uint24 maxVolatilityAccumulator ) external; function setLBHooksParametersOnPair( IERC20 tokenX, IERC20 tokenY, uint16 binStep, bytes32 hooksParameters, bytes memory onHooksSetData ) external; function removeLBHooksOnPair(IERC20 tokenX, IERC20 tokenY, uint16 binStep) external; function setFeeRecipient(address feeRecipient) external; function setFlashLoanFee(uint256 flashLoanFee) external; function addQuoteAsset(IERC20 quoteAsset) external; function removeQuoteAsset(IERC20 quoteAsset) external; function forceDecay(ILBPair lbPair) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @title Liquidity Book Flashloan Callback Interface /// @author Trader Joe /// @notice Required interface to interact with LB flash loans interface ILBFlashLoanCallback { function LBFlashLoanCallback( address sender, IERC20 tokenX, IERC20 tokenY, bytes32 amounts, bytes32 totalFees, bytes calldata data ) external returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /** * @title Liquidity Book Token Interface * @author Trader Joe * @notice Interface to interact with the LBToken. */ interface ILBToken { error LBToken__AddressThisOrZero(); error LBToken__InvalidLength(); error LBToken__SelfApproval(address owner); error LBToken__SpenderNotApproved(address from, address spender); error LBToken__TransferExceedsBalance(address from, uint256 id, uint256 amount); error LBToken__BurnExceedsBalance(address from, uint256 id, uint256 amount); event TransferBatch( address indexed sender, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); event ApprovalForAll(address indexed account, address indexed sender, bool approved); function name() external view returns (string memory); function symbol() external view returns (string memory); function totalSupply(uint256 id) external view returns (uint256); function balanceOf(address account, uint256 id) external view returns (uint256); function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); function isApprovedForAll(address owner, address spender) external view returns (bool); function approveForAll(address spender, bool approved) external; function batchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {Constants} from "../Constants.sol"; import {BitMath} from "./BitMath.sol"; /** * @title Liquidity Book Uint128x128 Math Library * @author Trader Joe * @notice Helper contract used for power and log calculations */ library Uint128x128Math { using BitMath for uint256; error Uint128x128Math__LogUnderflow(); error Uint128x128Math__PowUnderflow(uint256 x, int256 y); uint256 constant LOG_SCALE_OFFSET = 127; uint256 constant LOG_SCALE = 1 << LOG_SCALE_OFFSET; uint256 constant LOG_SCALE_SQUARED = LOG_SCALE * LOG_SCALE; /** * @notice Calculates the binary logarithm of x. * @dev Based on the iterative approximation algorithm. * https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation * Requirements: * - x must be greater than zero. * Caveats: * - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation * Also because x is converted to an unsigned 129.127-binary fixed-point number during the operation to optimize the multiplication * @param x The unsigned 128.128-binary fixed-point number for which to calculate the binary logarithm. * @return result The binary logarithm as a signed 128.128-binary fixed-point number. */ function log2(uint256 x) internal pure returns (int256 result) { // Convert x to a unsigned 129.127-binary fixed-point number to optimize the multiplication. // If we use an offset of 128 bits, y would need 129 bits and y**2 would would overflow and we would have to // use mulDiv, by reducing x to 129.127-binary fixed-point number we assert that y will use 128 bits, and we // can use the regular multiplication if (x == 1) return -128; if (x == 0) revert Uint128x128Math__LogUnderflow(); x >>= 1; unchecked { // This works because log2(x) = -log2(1/x). int256 sign; if (x >= LOG_SCALE) { sign = 1; } else { sign = -1; // Do the fixed-point inversion inline to save gas x = LOG_SCALE_SQUARED / x; } // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n). uint256 n = (x >> LOG_SCALE_OFFSET).mostSignificantBit(); // The integer part of the logarithm as a signed 129.127-binary fixed-point number. The operation can't overflow // because n is maximum 255, LOG_SCALE_OFFSET is 127 bits and sign is either 1 or -1. result = int256(n) << LOG_SCALE_OFFSET; // This is y = x * 2^(-n). uint256 y = x >> n; // If y = 1, the fractional part is zero. if (y != LOG_SCALE) { // Calculate the fractional part via the iterative approximation. // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster. for (int256 delta = int256(1 << (LOG_SCALE_OFFSET - 1)); delta > 0; delta >>= 1) { y = (y * y) >> LOG_SCALE_OFFSET; // Is y^2 > 2 and so in the range [2,4)? if (y >= 1 << (LOG_SCALE_OFFSET + 1)) { // Add the 2^(-m) factor to the logarithm. result += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } } // Convert x back to unsigned 128.128-binary fixed-point number result = (result * sign) << 1; } } /** * @notice Returns the value of x^y. It calculates `1 / x^abs(y)` if x is bigger than 2^128. * At the end of the operations, we invert the result if needed. * @param x The unsigned 128.128-binary fixed-point number for which to calculate the power * @param y A relative number without any decimals, needs to be between ]-2^21; 2^21[ */ function pow(uint256 x, int256 y) internal pure returns (uint256 result) { bool invert; uint256 absY; if (y == 0) return Constants.SCALE; assembly { absY := y if slt(absY, 0) { absY := sub(0, absY) invert := iszero(invert) } } if (absY < 0x100000) { result = Constants.SCALE; assembly { let squared := x if gt(x, 0xffffffffffffffffffffffffffffffff) { squared := div(not(0), squared) invert := iszero(invert) } if and(absY, 0x1) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x2) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x4) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x8) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x10) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x20) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x40) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x80) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x100) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x200) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x400) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x800) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x1000) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x2000) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x4000) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x8000) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x10000) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x20000) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x40000) { result := shr(128, mul(result, squared)) } squared := shr(128, mul(squared, squared)) if and(absY, 0x80000) { result := shr(128, mul(result, squared)) } } } // revert if y is too big or if x^y underflowed if (result == 0) revert Uint128x128Math__PowUnderflow(x, y); return invert ? type(uint256).max / result : result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /** * @title Liquidity Book Constants Library * @author Trader Joe * @notice Set of constants for Liquidity Book contracts */ library Constants { uint8 internal constant SCALE_OFFSET = 128; uint256 internal constant SCALE = 1 << SCALE_OFFSET; uint256 internal constant PRECISION = 1e18; uint256 internal constant SQUARED_PRECISION = PRECISION * PRECISION; uint256 internal constant MAX_FEE = 0.1e18; // 10% uint256 internal constant MAX_PROTOCOL_SHARE = 2_500; // 25% of the fee uint256 internal constant BASIS_POINT_MAX = 10_000; // (2^256 - 1) / (2 * log(2**128) / log(1.0001)) uint256 internal constant MAX_LIQUIDITY_PER_BIN = 65251743116719673010965625540244653191619923014385985379600384103134737; /// @dev The expected return after a successful flash loan bytes32 internal constant CALLBACK_SUCCESS = keccak256("LBPair.onFlashLoan"); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {Constants} from "../Constants.sol"; /** * @title Liquidity Book Packed Uint128 Math Library * @author Trader Joe * @notice This library contains functions to encode and decode two uint128 into a single bytes32 * and interact with the encoded bytes32. */ library PackedUint128Math { error PackedUint128Math__AddOverflow(); error PackedUint128Math__SubUnderflow(); error PackedUint128Math__MultiplierTooLarge(); uint256 private constant OFFSET = 128; uint256 private constant MASK_128 = 0xffffffffffffffffffffffffffffffff; uint256 private constant MASK_128_PLUS_ONE = MASK_128 + 1; /** * @dev Encodes two uint128 into a single bytes32 * @param x1 The first uint128 * @param x2 The second uint128 * @return z The encoded bytes32 as follows: * [0 - 128[: x1 * [128 - 256[: x2 */ function encode(uint128 x1, uint128 x2) internal pure returns (bytes32 z) { assembly { z := or(and(x1, MASK_128), shl(OFFSET, x2)) } } /** * @dev Encodes a uint128 into a single bytes32 as the first uint128 * @param x1 The uint128 * @return z The encoded bytes32 as follows: * [0 - 128[: x1 * [128 - 256[: empty */ function encodeFirst(uint128 x1) internal pure returns (bytes32 z) { assembly { z := and(x1, MASK_128) } } /** * @dev Encodes a uint128 into a single bytes32 as the second uint128 * @param x2 The uint128 * @return z The encoded bytes32 as follows: * [0 - 128[: empty * [128 - 256[: x2 */ function encodeSecond(uint128 x2) internal pure returns (bytes32 z) { assembly { z := shl(OFFSET, x2) } } /** * @dev Encodes a uint128 into a single bytes32 as the first or second uint128 * @param x The uint128 * @param first Whether to encode as the first or second uint128 * @return z The encoded bytes32 as follows: * if first: * [0 - 128[: x * [128 - 256[: empty * else: * [0 - 128[: empty * [128 - 256[: x */ function encode(uint128 x, bool first) internal pure returns (bytes32 z) { return first ? encodeFirst(x) : encodeSecond(x); } /** * @dev Decodes a bytes32 into two uint128 * @param z The encoded bytes32 as follows: * [0 - 128[: x1 * [128 - 256[: x2 * @return x1 The first uint128 * @return x2 The second uint128 */ function decode(bytes32 z) internal pure returns (uint128 x1, uint128 x2) { assembly { x1 := and(z, MASK_128) x2 := shr(OFFSET, z) } } /** * @dev Decodes a bytes32 into a uint128 as the first uint128 * @param z The encoded bytes32 as follows: * [0 - 128[: x * [128 - 256[: any * @return x The first uint128 */ function decodeX(bytes32 z) internal pure returns (uint128 x) { assembly { x := and(z, MASK_128) } } /** * @dev Decodes a bytes32 into a uint128 as the second uint128 * @param z The encoded bytes32 as follows: * [0 - 128[: any * [128 - 256[: y * @return y The second uint128 */ function decodeY(bytes32 z) internal pure returns (uint128 y) { assembly { y := shr(OFFSET, z) } } /** * @dev Decodes a bytes32 into a uint128 as the first or second uint128 * @param z The encoded bytes32 as follows: * if first: * [0 - 128[: x1 * [128 - 256[: empty * else: * [0 - 128[: empty * [128 - 256[: x2 * @param first Whether to decode as the first or second uint128 * @return x The decoded uint128 */ function decode(bytes32 z, bool first) internal pure returns (uint128 x) { return first ? decodeX(z) : decodeY(z); } /** * @dev Adds two encoded bytes32, reverting on overflow on any of the uint128 * @param x The first bytes32 encoded as follows: * [0 - 128[: x1 * [128 - 256[: x2 * @param y The second bytes32 encoded as follows: * [0 - 128[: y1 * [128 - 256[: y2 * @return z The sum of x and y encoded as follows: * [0 - 128[: x1 + y1 * [128 - 256[: x2 + y2 */ function add(bytes32 x, bytes32 y) internal pure returns (bytes32 z) { assembly { z := add(x, y) } if (z < x || uint128(uint256(z)) < uint128(uint256(x))) { revert PackedUint128Math__AddOverflow(); } } /** * @dev Adds an encoded bytes32 and two uint128, reverting on overflow on any of the uint128 * @param x The bytes32 encoded as follows: * [0 - 128[: x1 * [128 - 256[: x2 * @param y1 The first uint128 * @param y2 The second uint128 * @return z The sum of x and y encoded as follows: * [0 - 128[: x1 + y1 * [128 - 256[: x2 + y2 */ function add(bytes32 x, uint128 y1, uint128 y2) internal pure returns (bytes32) { return add(x, encode(y1, y2)); } /** * @dev Subtracts two encoded bytes32, reverting on underflow on any of the uint128 * @param x The first bytes32 encoded as follows: * [0 - 128[: x1 * [128 - 256[: x2 * @param y The second bytes32 encoded as follows: * [0 - 128[: y1 * [128 - 256[: y2 * @return z The difference of x and y encoded as follows: * [0 - 128[: x1 - y1 * [128 - 256[: x2 - y2 */ function sub(bytes32 x, bytes32 y) internal pure returns (bytes32 z) { assembly { z := sub(x, y) } if (z > x || uint128(uint256(z)) > uint128(uint256(x))) { revert PackedUint128Math__SubUnderflow(); } } /** * @dev Subtracts an encoded bytes32 and two uint128, reverting on underflow on any of the uint128 * @param x The bytes32 encoded as follows: * [0 - 128[: x1 * [128 - 256[: x2 * @param y1 The first uint128 * @param y2 The second uint128 * @return z The difference of x and y encoded as follows: * [0 - 128[: x1 - y1 * [128 - 256[: x2 - y2 */ function sub(bytes32 x, uint128 y1, uint128 y2) internal pure returns (bytes32) { return sub(x, encode(y1, y2)); } /** * @dev Returns whether any of the uint128 of x is strictly greater than the corresponding uint128 of y * @param x The first bytes32 encoded as follows: * [0 - 128[: x1 * [128 - 256[: x2 * @param y The second bytes32 encoded as follows: * [0 - 128[: y1 * [128 - 256[: y2 * @return x1 < y1 || x2 < y2 */ function lt(bytes32 x, bytes32 y) internal pure returns (bool) { (uint128 x1, uint128 x2) = decode(x); (uint128 y1, uint128 y2) = decode(y); return x1 < y1 || x2 < y2; } /** * @dev Returns whether any of the uint128 of x is strictly greater than the corresponding uint128 of y * @param x The first bytes32 encoded as follows: * [0 - 128[: x1 * [128 - 256[: x2 * @param y The second bytes32 encoded as follows: * [0 - 128[: y1 * [128 - 256[: y2 * @return x1 < y1 || x2 < y2 */ function gt(bytes32 x, bytes32 y) internal pure returns (bool) { (uint128 x1, uint128 x2) = decode(x); (uint128 y1, uint128 y2) = decode(y); return x1 > y1 || x2 > y2; } /** * @dev Multiplies an encoded bytes32 by a uint128 then divides the result by 10_000, rounding down * The result can't overflow as the multiplier needs to be smaller or equal to 10_000 * @param x The bytes32 encoded as follows: * [0 - 128[: x1 * [128 - 256[: x2 * @param multiplier The uint128 to multiply by (must be smaller or equal to 10_000) * @return z The product of x and multiplier encoded as follows: * [0 - 128[: floor((x1 * multiplier) / 10_000) * [128 - 256[: floor((x2 * multiplier) / 10_000) */ function scalarMulDivBasisPointRoundDown(bytes32 x, uint128 multiplier) internal pure returns (bytes32 z) { if (multiplier == 0) return 0; uint256 BASIS_POINT_MAX = Constants.BASIS_POINT_MAX; if (multiplier > BASIS_POINT_MAX) revert PackedUint128Math__MultiplierTooLarge(); (uint128 x1, uint128 x2) = decode(x); assembly { x1 := div(mul(x1, multiplier), BASIS_POINT_MAX) x2 := div(mul(x2, multiplier), BASIS_POINT_MAX) } return encode(x1, x2); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {Constants} from "./Constants.sol"; import {SafeCast} from "./math/SafeCast.sol"; import {Encoded} from "./math/Encoded.sol"; /** * @title Liquidity Book Pair Parameter Helper Library * @author Trader Joe * @dev This library contains functions to get and set parameters of a pair * The parameters are stored in a single bytes32 variable in the following format: * [0 - 16[: base factor (16 bits) * [16 - 28[: filter period (12 bits) * [28 - 40[: decay period (12 bits) * [40 - 54[: reduction factor (14 bits) * [54 - 78[: variable fee control (24 bits) * [78 - 92[: protocol share (14 bits) * [92 - 112[: max volatility accumulator (20 bits) * [112 - 132[: volatility accumulator (20 bits) * [132 - 152[: volatility reference (20 bits) * [152 - 176[: index reference (24 bits) * [176 - 216[: time of last update (40 bits) * [216 - 232[: oracle index (16 bits) * [232 - 256[: active index (24 bits) */ library PairParameterHelper { using SafeCast for uint256; using Encoded for bytes32; error PairParametersHelper__InvalidParameter(); uint256 internal constant OFFSET_BASE_FACTOR = 0; uint256 internal constant OFFSET_FILTER_PERIOD = 16; uint256 internal constant OFFSET_DECAY_PERIOD = 28; uint256 internal constant OFFSET_REDUCTION_FACTOR = 40; uint256 internal constant OFFSET_VAR_FEE_CONTROL = 54; uint256 internal constant OFFSET_PROTOCOL_SHARE = 78; uint256 internal constant OFFSET_MAX_VOL_ACC = 92; uint256 internal constant OFFSET_VOL_ACC = 112; uint256 internal constant OFFSET_VOL_REF = 132; uint256 internal constant OFFSET_ID_REF = 152; uint256 internal constant OFFSET_TIME_LAST_UPDATE = 176; uint256 internal constant OFFSET_ORACLE_ID = 216; uint256 internal constant OFFSET_ACTIVE_ID = 232; uint256 internal constant MASK_STATIC_PARAMETER = 0xffffffffffffffffffffffffffff; /** * @dev Get the base factor from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 16[: base factor (16 bits) * [16 - 256[: other parameters * @return baseFactor The base factor */ function getBaseFactor(bytes32 params) internal pure returns (uint16 baseFactor) { baseFactor = params.decodeUint16(OFFSET_BASE_FACTOR); } /** * @dev Get the filter period from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 16[: other parameters * [16 - 28[: filter period (12 bits) * [28 - 256[: other parameters * @return filterPeriod The filter period */ function getFilterPeriod(bytes32 params) internal pure returns (uint16 filterPeriod) { filterPeriod = params.decodeUint12(OFFSET_FILTER_PERIOD); } /** * @dev Get the decay period from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 28[: other parameters * [28 - 40[: decay period (12 bits) * [40 - 256[: other parameters * @return decayPeriod The decay period */ function getDecayPeriod(bytes32 params) internal pure returns (uint16 decayPeriod) { decayPeriod = params.decodeUint12(OFFSET_DECAY_PERIOD); } /** * @dev Get the reduction factor from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 40[: other parameters * [40 - 54[: reduction factor (14 bits) * [54 - 256[: other parameters * @return reductionFactor The reduction factor */ function getReductionFactor(bytes32 params) internal pure returns (uint16 reductionFactor) { reductionFactor = params.decodeUint14(OFFSET_REDUCTION_FACTOR); } /** * @dev Get the variable fee control from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 54[: other parameters * [54 - 78[: variable fee control (24 bits) * [78 - 256[: other parameters * @return variableFeeControl The variable fee control */ function getVariableFeeControl(bytes32 params) internal pure returns (uint24 variableFeeControl) { variableFeeControl = params.decodeUint24(OFFSET_VAR_FEE_CONTROL); } /** * @dev Get the protocol share from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 78[: other parameters * [78 - 92[: protocol share (14 bits) * [92 - 256[: other parameters * @return protocolShare The protocol share */ function getProtocolShare(bytes32 params) internal pure returns (uint16 protocolShare) { protocolShare = params.decodeUint14(OFFSET_PROTOCOL_SHARE); } /** * @dev Get the max volatility accumulator from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 92[: other parameters * [92 - 112[: max volatility accumulator (20 bits) * [112 - 256[: other parameters * @return maxVolatilityAccumulator The max volatility accumulator */ function getMaxVolatilityAccumulator(bytes32 params) internal pure returns (uint24 maxVolatilityAccumulator) { maxVolatilityAccumulator = params.decodeUint20(OFFSET_MAX_VOL_ACC); } /** * @dev Get the volatility accumulator from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 112[: other parameters * [112 - 132[: volatility accumulator (20 bits) * [132 - 256[: other parameters * @return volatilityAccumulator The volatility accumulator */ function getVolatilityAccumulator(bytes32 params) internal pure returns (uint24 volatilityAccumulator) { volatilityAccumulator = params.decodeUint20(OFFSET_VOL_ACC); } /** * @dev Get the volatility reference from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 132[: other parameters * [132 - 152[: volatility reference (20 bits) * [152 - 256[: other parameters * @return volatilityReference The volatility reference */ function getVolatilityReference(bytes32 params) internal pure returns (uint24 volatilityReference) { volatilityReference = params.decodeUint20(OFFSET_VOL_REF); } /** * @dev Get the index reference from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 152[: other parameters * [152 - 176[: index reference (24 bits) * [176 - 256[: other parameters * @return idReference The index reference */ function getIdReference(bytes32 params) internal pure returns (uint24 idReference) { idReference = params.decodeUint24(OFFSET_ID_REF); } /** * @dev Get the time of last update from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 176[: other parameters * [176 - 216[: time of last update (40 bits) * [216 - 256[: other parameters * @return timeOflastUpdate The time of last update */ function getTimeOfLastUpdate(bytes32 params) internal pure returns (uint40 timeOflastUpdate) { timeOflastUpdate = params.decodeUint40(OFFSET_TIME_LAST_UPDATE); } /** * @dev Get the oracle id from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 216[: other parameters * [216 - 232[: oracle id (16 bits) * [232 - 256[: other parameters * @return oracleId The oracle id */ function getOracleId(bytes32 params) internal pure returns (uint16 oracleId) { oracleId = params.decodeUint16(OFFSET_ORACLE_ID); } /** * @dev Get the active index from the encoded pair parameters * @param params The encoded pair parameters, as follows: * [0 - 232[: other parameters * [232 - 256[: active index (24 bits) * @return activeId The active index */ function getActiveId(bytes32 params) internal pure returns (uint24 activeId) { activeId = params.decodeUint24(OFFSET_ACTIVE_ID); } /** * @dev Get the delta between the current active index and the cached active index * @param params The encoded pair parameters, as follows: * [0 - 232[: other parameters * [232 - 256[: active index (24 bits) * @param activeId The current active index * @return The delta */ function getDeltaId(bytes32 params, uint24 activeId) internal pure returns (uint24) { uint24 id = getActiveId(params); unchecked { return activeId > id ? activeId - id : id - activeId; } } /** * @dev Calculates the base fee, with 18 decimals * @param params The encoded pair parameters * @param binStep The bin step (in basis points) * @return baseFee The base fee */ function getBaseFee(bytes32 params, uint16 binStep) internal pure returns (uint256) { unchecked { // Base factor is in basis points, binStep is in basis points, so we multiply by 1e10 return uint256(getBaseFactor(params)) * binStep * 1e10; } } /** * @dev Calculates the variable fee * @param params The encoded pair parameters * @param binStep The bin step (in basis points) * @return variableFee The variable fee */ function getVariableFee(bytes32 params, uint16 binStep) internal pure returns (uint256 variableFee) { uint256 variableFeeControl = getVariableFeeControl(params); if (variableFeeControl != 0) { unchecked { // The volatility accumulator is in basis points, binStep is in basis points, // and the variable fee control is in basis points, so the result is in 100e18th uint256 prod = uint256(getVolatilityAccumulator(params)) * binStep; variableFee = (prod * prod * variableFeeControl + 99) / 100; } } } /** * @dev Calculates the total fee, which is the sum of the base fee and the variable fee * @param params The encoded pair parameters * @param binStep The bin step (in basis points) * @return totalFee The total fee */ function getTotalFee(bytes32 params, uint16 binStep) internal pure returns (uint128) { unchecked { return (getBaseFee(params, binStep) + getVariableFee(params, binStep)).safe128(); } } /** * @dev Set the oracle id in the encoded pair parameters * @param params The encoded pair parameters * @param oracleId The oracle id * @return The updated encoded pair parameters */ function setOracleId(bytes32 params, uint16 oracleId) internal pure returns (bytes32) { return params.set(oracleId, Encoded.MASK_UINT16, OFFSET_ORACLE_ID); } /** * @dev Set the volatility reference in the encoded pair parameters * @param params The encoded pair parameters * @param volRef The volatility reference * @return The updated encoded pair parameters */ function setVolatilityReference(bytes32 params, uint24 volRef) internal pure returns (bytes32) { if (volRef > Encoded.MASK_UINT20) revert PairParametersHelper__InvalidParameter(); return params.set(volRef, Encoded.MASK_UINT20, OFFSET_VOL_REF); } /** * @dev Set the volatility accumulator in the encoded pair parameters * @param params The encoded pair parameters * @param volAcc The volatility accumulator * @return The updated encoded pair parameters */ function setVolatilityAccumulator(bytes32 params, uint24 volAcc) internal pure returns (bytes32) { if (volAcc > Encoded.MASK_UINT20) revert PairParametersHelper__InvalidParameter(); return params.set(volAcc, Encoded.MASK_UINT20, OFFSET_VOL_ACC); } /** * @dev Set the active id in the encoded pair parameters * @param params The encoded pair parameters * @param activeId The active id * @return newParams The updated encoded pair parameters */ function setActiveId(bytes32 params, uint24 activeId) internal pure returns (bytes32 newParams) { return params.set(activeId, Encoded.MASK_UINT24, OFFSET_ACTIVE_ID); } /** * @dev Sets the static fee parameters in the encoded pair parameters * @param params The encoded pair parameters * @param baseFactor The base factor * @param filterPeriod The filter period * @param decayPeriod The decay period * @param reductionFactor The reduction factor * @param variableFeeControl The variable fee control * @param protocolShare The protocol share * @param maxVolatilityAccumulator The max volatility accumulator * @return newParams The updated encoded pair parameters */ function setStaticFeeParameters( bytes32 params, uint16 baseFactor, uint16 filterPeriod, uint16 decayPeriod, uint16 reductionFactor, uint24 variableFeeControl, uint16 protocolShare, uint24 maxVolatilityAccumulator ) internal pure returns (bytes32 newParams) { if ( filterPeriod > decayPeriod || decayPeriod > Encoded.MASK_UINT12 || reductionFactor > Constants.BASIS_POINT_MAX || protocolShare > Constants.MAX_PROTOCOL_SHARE || maxVolatilityAccumulator > Encoded.MASK_UINT20 ) revert PairParametersHelper__InvalidParameter(); newParams = newParams.set(baseFactor, Encoded.MASK_UINT16, OFFSET_BASE_FACTOR); newParams = newParams.set(filterPeriod, Encoded.MASK_UINT12, OFFSET_FILTER_PERIOD); newParams = newParams.set(decayPeriod, Encoded.MASK_UINT12, OFFSET_DECAY_PERIOD); newParams = newParams.set(reductionFactor, Encoded.MASK_UINT14, OFFSET_REDUCTION_FACTOR); newParams = newParams.set(variableFeeControl, Encoded.MASK_UINT24, OFFSET_VAR_FEE_CONTROL); newParams = newParams.set(protocolShare, Encoded.MASK_UINT14, OFFSET_PROTOCOL_SHARE); newParams = newParams.set(maxVolatilityAccumulator, Encoded.MASK_UINT20, OFFSET_MAX_VOL_ACC); return params.set(uint256(newParams), MASK_STATIC_PARAMETER, 0); } /** * @dev Updates the index reference in the encoded pair parameters * @param params The encoded pair parameters * @return newParams The updated encoded pair parameters */ function updateIdReference(bytes32 params) internal pure returns (bytes32 newParams) { uint24 activeId = getActiveId(params); return params.set(activeId, Encoded.MASK_UINT24, OFFSET_ID_REF); } /** * @dev Updates the time of last update in the encoded pair parameters * @param params The encoded pair parameters * @param timestamp The timestamp * @return newParams The updated encoded pair parameters */ function updateTimeOfLastUpdate(bytes32 params, uint256 timestamp) internal pure returns (bytes32 newParams) { uint40 currentTime = timestamp.safe40(); return params.set(currentTime, Encoded.MASK_UINT40, OFFSET_TIME_LAST_UPDATE); } /** * @dev Updates the volatility reference in the encoded pair parameters * @param params The encoded pair parameters * @return The updated encoded pair parameters */ function updateVolatilityReference(bytes32 params) internal pure returns (bytes32) { uint256 volAcc = getVolatilityAccumulator(params); uint256 reductionFactor = getReductionFactor(params); uint24 volRef; unchecked { volRef = uint24(volAcc * reductionFactor / Constants.BASIS_POINT_MAX); } return setVolatilityReference(params, volRef); } /** * @dev Updates the volatility accumulator in the encoded pair parameters * @param params The encoded pair parameters * @param activeId The active id * @return The updated encoded pair parameters */ function updateVolatilityAccumulator(bytes32 params, uint24 activeId) internal pure returns (bytes32) { uint256 idReference = getIdReference(params); uint256 deltaId; uint256 volAcc; unchecked { deltaId = activeId > idReference ? activeId - idReference : idReference - activeId; volAcc = (uint256(getVolatilityReference(params)) + deltaId * Constants.BASIS_POINT_MAX); } uint256 maxVolAcc = getMaxVolatilityAccumulator(params); volAcc = volAcc > maxVolAcc ? maxVolAcc : volAcc; return setVolatilityAccumulator(params, uint24(volAcc)); } /** * @dev Updates the volatility reference and the volatility accumulator in the encoded pair parameters * @param params The encoded pair parameters * @param timestamp The timestamp * @return The updated encoded pair parameters */ function updateReferences(bytes32 params, uint256 timestamp) internal pure returns (bytes32) { uint256 dt = timestamp - getTimeOfLastUpdate(params); if (dt >= getFilterPeriod(params)) { params = updateIdReference(params); params = dt < getDecayPeriod(params) ? updateVolatilityReference(params) : setVolatilityReference(params, 0); } return updateTimeOfLastUpdate(params, timestamp); } /** * @dev Updates the volatility reference and the volatility accumulator in the encoded pair parameters * @param params The encoded pair parameters * @param activeId The active id * @param timestamp The timestamp * @return The updated encoded pair parameters */ function updateVolatilityParameters(bytes32 params, uint24 activeId, uint256 timestamp) internal pure returns (bytes32) { params = updateReferences(params, timestamp); return updateVolatilityAccumulator(params, activeId); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {Constants} from "./Constants.sol"; /** * @title Liquidity Book Fee Helper Library * @author Trader Joe * @notice This library contains functions to calculate fees */ library FeeHelper { error FeeHelper__FeeTooLarge(); error FeeHelper__ProtocolShareTooLarge(); /** * @dev Modifier to check that the fee is not too large * @param fee The fee */ modifier verifyFee(uint128 fee) { _verifyFee(fee); _; } /** * @dev Modifier to check that the protocol share is not too large * @param protocolShare The protocol share */ modifier verifyProtocolShare(uint128 protocolShare) { if (protocolShare > Constants.MAX_PROTOCOL_SHARE) revert FeeHelper__ProtocolShareTooLarge(); _; } /** * @dev Calculates the fee amount from the amount with fees, rounding up * @param amountWithFees The amount with fees * @param totalFee The total fee * @return feeAmount The fee amount */ function getFeeAmountFrom(uint128 amountWithFees, uint128 totalFee) internal pure verifyFee(totalFee) returns (uint128) { unchecked { // Can't overflow, max(result) = (type(uint128).max * 0.1e18 + 1e18 - 1) / 1e18 < 2^128 return uint128((uint256(amountWithFees) * totalFee + Constants.PRECISION - 1) / Constants.PRECISION); } } /** * @dev Calculates the fee amount that will be charged, rounding up * @param amount The amount * @param totalFee The total fee * @return feeAmount The fee amount */ function getFeeAmount(uint128 amount, uint128 totalFee) internal pure verifyFee(totalFee) returns (uint128) { unchecked { uint256 denominator = Constants.PRECISION - totalFee; // Can't overflow, max(result) = (type(uint128).max * 0.1e18 + (1e18 - 1)) / 0.9e18 < 2^128 return uint128((uint256(amount) * totalFee + denominator - 1) / denominator); } } /** * @dev Calculates the composition fee amount from the amount with fees, rounding down * @param amountWithFees The amount with fees * @param totalFee The total fee * @return The amount with fees */ function getCompositionFee(uint128 amountWithFees, uint128 totalFee) internal pure verifyFee(totalFee) returns (uint128) { unchecked { uint256 denominator = Constants.SQUARED_PRECISION; // Can't overflow, max(result) = type(uint128).max * 0.1e18 * 1.1e18 / 1e36 <= 2^128 * 0.11e36 / 1e36 < 2^128 return uint128(uint256(amountWithFees) * totalFee * (uint256(totalFee) + Constants.PRECISION) / denominator); } } /** * @dev Calculates the protocol fee amount from the fee amount and the protocol share, rounding down * @param feeAmount The fee amount * @param protocolShare The protocol share * @return protocolFeeAmount The protocol fee amount */ function getProtocolFeeAmount(uint128 feeAmount, uint128 protocolShare) internal pure verifyProtocolShare(protocolShare) returns (uint128) { unchecked { return uint128(uint256(feeAmount) * protocolShare / Constants.BASIS_POINT_MAX); } } /** * @dev Internal function to check that the fee is not too large * @param fee The fee */ function _verifyFee(uint128 fee) private pure { if (fee > Constants.MAX_FEE) revert FeeHelper__FeeTooLarge(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title Liquidity Book Token Helper Library * @author Trader Joe * @notice Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using TokenHelper for IERC20;` statement to your contract, * which allows you to call the safe operation as `token.safeTransfer(...)` */ library TokenHelper { error TokenHelper__TransferFailed(); /** * @notice Transfers token and reverts if the transfer fails * @param token The address of the token * @param owner The owner of the tokens * @param recipient The address of the recipient * @param amount The amount to send */ function safeTransferFrom(IERC20 token, address owner, address recipient, uint256 amount) internal { bytes memory data = abi.encodeWithSelector(token.transferFrom.selector, owner, recipient, amount); _callAndCatch(token, data); } /** * @notice Transfers token and reverts if the transfer fails * @param token The address of the token * @param recipient The address of the recipient * @param amount The amount to send */ function safeTransfer(IERC20 token, address recipient, uint256 amount) internal { bytes memory data = abi.encodeWithSelector(token.transfer.selector, recipient, amount); _callAndCatch(token, data); } function _callAndCatch(IERC20 token, bytes memory data) internal { bool success; assembly { mstore(0x00, 0) success := call(gas(), token, 0, add(data, 0x20), mload(data), 0x00, 0x20) switch success case 0 { if returndatasize() { returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } } default { switch returndatasize() case 0 { success := iszero(iszero(extcodesize(token))) } default { success := and(success, eq(mload(0x00), 1)) } } } if (!success) revert TokenHelper__TransferFailed(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /** * @title Liquidity Book Encoded Library * @author Trader Joe * @notice Helper contract used for decoding bytes32 sample */ library Encoded { uint256 internal constant MASK_UINT1 = 0x1; uint256 internal constant MASK_UINT8 = 0xff; uint256 internal constant MASK_UINT12 = 0xfff; uint256 internal constant MASK_UINT14 = 0x3fff; uint256 internal constant MASK_UINT16 = 0xffff; uint256 internal constant MASK_UINT20 = 0xfffff; uint256 internal constant MASK_UINT24 = 0xffffff; uint256 internal constant MASK_UINT40 = 0xffffffffff; uint256 internal constant MASK_UINT64 = 0xffffffffffffffff; uint256 internal constant MASK_UINT128 = 0xffffffffffffffffffffffffffffffff; /** * @notice Internal function to set a value in an encoded bytes32 using a mask and offset * @dev This function can overflow * @param encoded The previous encoded value * @param value The value to encode * @param mask The mask * @param offset The offset * @return newEncoded The new encoded value */ function set(bytes32 encoded, uint256 value, uint256 mask, uint256 offset) internal pure returns (bytes32 newEncoded) { assembly { newEncoded := and(encoded, not(shl(offset, mask))) newEncoded := or(newEncoded, shl(offset, and(value, mask))) } } /** * @notice Internal function to set a bool in an encoded bytes32 using an offset * @dev This function can overflow * @param encoded The previous encoded value * @param boolean The bool to encode * @param offset The offset * @return newEncoded The new encoded value */ function setBool(bytes32 encoded, bool boolean, uint256 offset) internal pure returns (bytes32 newEncoded) { return set(encoded, boolean ? 1 : 0, MASK_UINT1, offset); } /** * @notice Internal function to decode a bytes32 sample using a mask and offset * @dev This function can overflow * @param encoded The encoded value * @param mask The mask * @param offset The offset * @return value The decoded value */ function decode(bytes32 encoded, uint256 mask, uint256 offset) internal pure returns (uint256 value) { assembly { value := and(shr(offset, encoded), mask) } } /** * @notice Internal function to decode a bytes32 sample into a bool using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return boolean The decoded value as a bool */ function decodeBool(bytes32 encoded, uint256 offset) internal pure returns (bool boolean) { assembly { boolean := and(shr(offset, encoded), MASK_UINT1) } } /** * @notice Internal function to decode a bytes32 sample into a uint8 using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return value The decoded value */ function decodeUint8(bytes32 encoded, uint256 offset) internal pure returns (uint8 value) { assembly { value := and(shr(offset, encoded), MASK_UINT8) } } /** * @notice Internal function to decode a bytes32 sample into a uint12 using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return value The decoded value as a uint16, since uint12 is not supported */ function decodeUint12(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) { assembly { value := and(shr(offset, encoded), MASK_UINT12) } } /** * @notice Internal function to decode a bytes32 sample into a uint14 using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return value The decoded value as a uint16, since uint14 is not supported */ function decodeUint14(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) { assembly { value := and(shr(offset, encoded), MASK_UINT14) } } /** * @notice Internal function to decode a bytes32 sample into a uint16 using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return value The decoded value */ function decodeUint16(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) { assembly { value := and(shr(offset, encoded), MASK_UINT16) } } /** * @notice Internal function to decode a bytes32 sample into a uint20 using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return value The decoded value as a uint24, since uint20 is not supported */ function decodeUint20(bytes32 encoded, uint256 offset) internal pure returns (uint24 value) { assembly { value := and(shr(offset, encoded), MASK_UINT20) } } /** * @notice Internal function to decode a bytes32 sample into a uint24 using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return value The decoded value */ function decodeUint24(bytes32 encoded, uint256 offset) internal pure returns (uint24 value) { assembly { value := and(shr(offset, encoded), MASK_UINT24) } } /** * @notice Internal function to decode a bytes32 sample into a uint40 using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return value The decoded value */ function decodeUint40(bytes32 encoded, uint256 offset) internal pure returns (uint40 value) { assembly { value := and(shr(offset, encoded), MASK_UINT40) } } /** * @notice Internal function to decode a bytes32 sample into a uint64 using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return value The decoded value */ function decodeUint64(bytes32 encoded, uint256 offset) internal pure returns (uint64 value) { assembly { value := and(shr(offset, encoded), MASK_UINT64) } } /** * @notice Internal function to decode a bytes32 sample into a uint128 using an offset * @dev This function can overflow * @param encoded The encoded value * @param offset The offset * @return value The decoded value */ function decodeUint128(bytes32 encoded, uint256 offset) internal pure returns (uint128 value) { assembly { value := and(shr(offset, encoded), MASK_UINT128) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "@lb-protocol/=lib/lb-rewarder/lib/dexv2/", "@moe-core/=lib/lb-rewarder/lib/moe-core/", "@openzeppelin/contracts-upgradeable/=lib/lb-rewarder/lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/lb-rewarder/lib/openzeppelin-contracts/contracts/", "@solmate/=lib/lb-rewarder/lib/moe-core/lib/solmate/", "@tj-dexv2/=lib/lb-rewarder/lib/moe-core/lib/dexv2/", "dexv2/=lib/lb-rewarder/lib/dexv2/", "ds-test/=lib/lb-rewarder/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/lb-rewarder/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "lb-rewarder/=lib/lb-rewarder/src/", "moe-core/=lib/lb-rewarder/lib/moe-core/", "openzeppelin-contracts-upgradeable/=lib/lb-rewarder/lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/lb-rewarder/lib/openzeppelin-contracts/", "solmate/=lib/lb-rewarder/lib/moe-core/lib/solmate/src/", "solrary/=lib/solrary/src/" ], "optimizer": { "enabled": true, "runs": 600 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"lbHooksManager","type":"address"},{"internalType":"contract IMasterChef","name":"masterChef","type":"address"},{"internalType":"contract IERC20","name":"metro","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"BinHelper__LiquidityOverflow","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"Hooks__CallFailed","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"LBBaseHooks__InvalidCaller","type":"error"},{"inputs":[],"name":"LBBaseHooks__NotLinked","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__ExceedsMaxNumberOfBins","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__InvalidDeltaBins","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__InvalidHooksParameters","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__LockedRewardToken","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__NativeTransferFailed","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__NotImplemented","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__NotNativeRewarder","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__Overflow","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__UnauthorizedCaller","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__UnlinkedHooks","type":"error"},{"inputs":[],"name":"LBHooksBaseRewarder__ZeroBalance","type":"error"},{"inputs":[],"name":"LBHooksRewarder__InvalidLBHooksExtraRewarder","type":"error"},{"inputs":[],"name":"NotInitializing","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":"SafeCast__Exceeds24Bits","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TokenHelper__NativeTransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"Uint128x128Math__PowUnderflow","type":"error"},{"inputs":[],"name":"Uint256x256Math__MulDivOverflow","type":"error"},{"inputs":[],"name":"Uint256x256Math__MulShiftOverflow","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int24","name":"deltaBinA","type":"int24"},{"indexed":false,"internalType":"int24","name":"deltaBinB","type":"int24"}],"name":"DeltaBinsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"lbHooksExtraRewarder","type":"address"}],"name":"LBHooksExtraRewarderSet","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":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"afterBatchTransferFrom","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amountsToBurn","type":"uint256[]"}],"name":"afterBurn","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes32","name":"fees","type":"bytes32"},{"internalType":"bytes32","name":"feesReceived","type":"bytes32"}],"name":"afterFlashLoan","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes32[]","name":"liquidityConfigs","type":"bytes32[]"},{"internalType":"bytes32","name":"amountsIn","type":"bytes32"}],"name":"afterMint","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"swapForY","type":"bool"},{"internalType":"bytes32","name":"amountsOut","type":"bytes32"}],"name":"afterSwap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"beforeBatchTransferFrom","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amountsToBurn","type":"uint256[]"}],"name":"beforeBurn","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes32","name":"amounts","type":"bytes32"}],"name":"beforeFlashLoan","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes32[]","name":"liquidityConfigs","type":"bytes32[]"},{"internalType":"bytes32","name":"amountsReceived","type":"bytes32"}],"name":"beforeMint","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"swapForY","type":"bool"},{"internalType":"bytes32","name":"amountsIn","type":"bytes32"}],"name":"beforeSwap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExtraHooksParameters","outputs":[{"internalType":"bytes32","name":"extraHooksParameters","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLBHooksManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLBPair","outputs":[{"internalType":"contract ILBPair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMasterChef","outputs":[{"internalType":"contract IMasterChef","name":"masterChef","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"getPendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPid","outputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardedRange","outputs":[{"internalType":"uint256","name":"binStart","type":"uint256"},{"internalType":"uint256","name":"binEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isLinked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hooksParameters","type":"bytes32"},{"internalType":"bytes","name":"onHooksSetData","type":"bytes"}],"name":"onHooksSet","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"deltaBinA","type":"int24"},{"internalType":"int24","name":"deltaBinB","type":"int24"}],"name":"setDeltaBins","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lbHooksExtraRewarder","type":"address"},{"internalType":"bytes","name":"extraRewarderData","type":"bytes"}],"name":"setLBHooksExtraRewarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","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"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101006040523480156200001257600080fd5b50604051620044ac380380620044ac833981016040819052620000359162000135565b306080526001600160a01b03831660a05282620000516200006b565b506001600160a01b0391821660c0521660e0525062000189565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000bc5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146200011c5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6001600160a01b03811681146200011c57600080fd5b6000806000606084860312156200014b57600080fd5b835162000158816200011f565b60208501519093506200016b816200011f565b60408501519092506200017e816200011f565b809150509250925092565b60805160a05160c05160e0516142a3620002096000396000818161058b015281816108eb015281816112c9015281816119c00152818161207a01526127b001526000818161071a01528181611fed0152818161273f015281816129c701526129f70152600081816106c70152610f79015260006104e001526142a36000f3fe6080604052600436106102bf5760003560e01c806370a082311161016e578063b8dc491b116100cb578063ea9db9d31161007f578063fdc2725711610064578063fdc272571461084f578063fe9ffeb31461086f578063feee373514610899576102ce565b8063ea9db9d31461080f578063f2fde38b1461082f576102ce565b8063c8772963116100b0578063c877296314610773578063dd62ed3e14610795578063e30c3978146107fa576102ce565b8063b8dc491b1461073e578063c7d12e881461075e576102ce565b80638da5cb5b116101225780639b4c8ea5116101075780639b4c8ea5146106b8578063a9059cbb146106eb578063b56449631461070b576102ce565b80638da5cb5b1461068e57806395d89b41146106a3576102ce565b806379ba50971161015357806379ba50971461063957806379c8ccf71461064e5780637a51a4c61461066e576102ce565b806370a08231146105cf578063715018a614610624576102ce565b80634e430b5a1161021c5780635f9c01b1116101d057806367ddb278116101b557806367ddb2781461055c57806369940d791461057c5780636e094176146105af576102ce565b80635f9c01b11461051a57806360bed5f31461053c576102ce565b806353e8079b1161020157806353e8079b1461048e578063566aff6a146104ae5780635c60da1b146104ce576102ce565b80634e430b5a1461044e578063505d90331461046e576102ce565b806323b872dd116102735780633f683b6a116102585780633f683b6a146103f957806343b312df1461040e578063457182781461042e576102ce565b806323b872dd146103bd578063313ce567146103dd576102ce565b806309fa1f90116102a457806309fa1f90146103315780630d4abdb31461034657806318160ddd1461037f576102ce565b806306fdde03146102d6578063095ea7b314610301576102ce565b366102ce576102cc6108b9565b005b6102cc6108b9565b3480156102e257600080fd5b506102eb61092b565b6040516102f8919061361b565b60405180910390f35b34801561030d57600080fd5b5061032161031c366004613663565b610a00565b60405190151581526020016102f8565b34801561033d57600080fd5b50610321610a1a565b34801561035257600080fd5b506103666103613660046136db565b610a29565b6040516001600160e01b031990911681526020016102f8565b34801561038b57600080fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b6040519081526020016102f8565b3480156103c957600080fd5b506103216103d8366004613748565b610a53565b3480156103e957600080fd5b50604051601281526020016102f8565b34801561040557600080fd5b50610321610a79565b34801561041a57600080fd5b506102cc61042936600461379b565b610a89565b34801561043a57600080fd5b506102cc6104493660046137ce565b610b63565b34801561045a57600080fd5b50610366610469366004613865565b610c4e565b34801561047a57600080fd5b50610366610489366004613748565b610c98565b34801561049a57600080fd5b506103666104a93660046138b2565b610cb2565b3480156104ba57600080fd5b506103af6104c93660046137ce565b610ccd565b3480156104da57600080fd5b506105027f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102f8565b34801561052657600080fd5b503660011981013560f01c90033560601c610502565b34801561054857600080fd5b50610366610557366004613903565b610f35565b34801561056857600080fd5b50610366610577366004613949565b610f50565b34801561058857600080fd5b507f0000000000000000000000000000000000000000000000000000000000000000610502565b3480156105bb57600080fd5b506102cc6105ca3660046139f1565b610f6e565b3480156105db57600080fd5b506103af6105ea366004613a2d565b6001600160a01b031660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00602052604090205490565b34801561063057600080fd5b506102cc611145565b34801561064557600080fd5b506102cc611157565b34801561065a57600080fd5b50610366610669366004613949565b6111a4565b34801561067a57600080fd5b506103666106893660046136db565b6111d1565b34801561069a57600080fd5b506105026111ed565b3480156106af57600080fd5b506102eb611222565b3480156106c457600080fd5b507f0000000000000000000000000000000000000000000000000000000000000000610502565b3480156106f757600080fd5b50610321610706366004613663565b611273565b34801561071757600080fd5b507f0000000000000000000000000000000000000000000000000000000000000000610502565b34801561074a57600080fd5b506102cc610759366004613a4a565b611281565b34801561076a57600080fd5b506004546103af565b34801561077f57600080fd5b503660011981013560f01c9003601401356103af565b3480156107a157600080fd5b506103af6107b0366004613a4a565b6001600160a01b0391821660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b34801561080657600080fd5b50610502611326565b34801561081b57600080fd5b5061036661082a366004613949565b61134f565b34801561083b57600080fd5b506102cc61084a366004613a2d565b61137c565b34801561085b57600080fd5b5061036661086a366004613949565b611401565b34801561087b57600080fd5b5061088461141f565b604080519283526020830191909152016102f8565b3480156108a557600080fd5b506103666108b43660046138b2565b611435565b3660011981013560f01c146108e1576040516335f187f960e01b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016156109295760405163e22dfb1160e01b815260040160405180910390fd5b565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0380546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace009161097c90613a83565b80601f01602080910402602001604051908101604052809291908181526020018280546109a890613a83565b80156109f55780601f106109ca576101008083540402835291602001916109f5565b820191906000526020600020905b8154815290600101906020018083116109d857829003601f168201915b505050505091505090565b600033610a0e81858561145c565b60019150505b92915050565b6000610a24611469565b905090565b6000610a336114f4565b610a408686868686611525565b50630d4abdb360e01b5b95945050505050565b600033610a61858285611549565b610a6c8585856115e6565b60019150505b9392505050565b6000610a83611469565b15905090565b610a91611645565b8060020b8260020b1315610ab8576040516320aec07960e01b815260040160405180910390fd5b600b8260020b8260020b610acc9190613ad3565b1315610aeb5760405163be0ae43b60e01b815260040160405180910390fd5b610af3611677565b6000805462ffffff83811663010000000265ffffffffffff19909216908516171790556040517f0db02dbe95af4e060b3a554370b11d345d2c7ce375ca69cefa13977d5253479490610b579084908490600292830b8152910b602082015260400190565b60405180910390a15050565b610b6b611469565b610b88576040516319e0ccff60e11b815260040160405180910390fd5b336001600160a01b03841614610bb157604051637613d16960e01b815260040160405180910390fd5b610bb9611677565b610bf6838383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117a992505050565b610c498383838080602002602001604051908101604052809392919081815260200183836020028082843760009201829052506001600160a01b038a168152600360205260409020549250611922915050565b505050565b6000610c586114f4565b610c60611469565b610c7d57604051632def67a360e21b815260040160405180910390fd5b610c888484846119e6565b5063272185ad60e11b9392505050565b6000610ca26114f4565b5063505d903360e01b9392505050565b6000610cbc6114f4565b506353e8079b60e01b949350505050565b6000610cd7611469565b610ce357506000610a72565b82823660011981013560f01c90033560601c6000808080610d02611b4e565b93509350935093506000806000610d1a888789611cd5565b919450925090508d6000610d2c611f80565b90506000805b8c811015610efb576000610d5d8f8f84818110610d5157610d51613afa565b905060200201356120dc565b62ffffff8116600081815260026020908152604080832080546001600160a01b038c16855260019091019092529091205492935091908c11801590610da657508a8362ffffff16105b15610e40576000610dbc8d62ffffff8616613b10565b905060008a8281518110610dd257610dd2613afa565b60200260200101519050600081118015610dec575060008a115b15610e3d576000610e2260808c8f8681518110610e0b57610e0b613afa565b60200260200101516121079092919063ffffffff16565b9050610e2f89828461213b565b610e399086613b23565b9450505b50505b60008f6001600160a01b031662fdd58e89866040518363ffffffff1660e01b8152600401610e889291906001600160a01b0392909216825262ffffff16602082015260400190565b602060405180830381865afa158015610ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec99190613b36565b905081831115610ee657610ee182840382608061215b565b860195505b5050505080610ef490613b4f565b9050610d32565b506001600160a01b038316600090815260036020526040902054610f1f9082613b23565b9d50505050505050505050505050509392505050565b6000610f3f6114f4565b506360bed5f360e01b949350505050565b6000610f5a6114f4565b50630cfbb64f60e31b979650505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610fa657610fa6611645565b6001600160a01b038316156110fe576001600160a01b03831661015160a01b1760048190553660011981013560f01c90033560601c6001600160a01b0316846001600160a01b0316635f9c01b16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611022573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110469190613b68565b6001600160a01b03161415806110cf5750306001600160a01b0316846001600160a01b03166320e1bba76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561109f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c39190613b68565b6001600160a01b031614155b156110ed576040516330e53f0760e11b815260040160405180910390fd5b6110f88184846121d2565b50611104565b60006004555b6040516001600160a01b03841681527fb9f3bf6e5f15f5daaaa5de4e2ac8f4f19c47a6d4e489efb48bd0d26ff478eba19060200160405180910390a1505050565b61114d611645565b6109296000612230565b3380611161611326565b6001600160a01b0316146111985760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6111a181612230565b50565b60006111ae6114f4565b6111bd8888888888888861226c565b506379c8ccf760e01b979650505050505050565b60006111db6114f4565b50633d28d26360e11b95945050505050565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b546001600160a01b031692915050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace009161097c90613a83565b600033610a0e8185856115e6565b611289611645565b6000611295833061228d565b9050806000036112b85760405163279157a960e01b815260040160405180910390fd5b6112c0611469565b80156112fd57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316145b1561131b5760405163071e53cd60e21b815260040160405180910390fd5b610c4983838361231d565b6000807f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00611212565b60006113596114f4565b611368888888888888886123b9565b5063ea9db9d360e01b979650505050505050565b611384611645565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b0319166001600160a01b03831690811782556113c86111ed565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a35050565b600061140b6114f4565b5063fdc2725760e01b979650505050505050565b60008061142a611b4e565b909590945092505050565b600061143f6114f4565b61144b858585856123da565b5063feee373560e01b949350505050565b610c4983838360016123f5565b6000806114e33660011981013560f01c90033560601c6001600160a01b031663781a89156040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e09190613b36565b90565b6001600160a01b0316301492915050565b3660011981013560f01c90033560601c331461092957604051634a27038360e01b815233600482015260240161118f565b61153285858585856124ee565b611542600454868686868661253b565b5050505050565b6001600160a01b0383811660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace01602090815260408083209386168352929052205460001981146115e057818110156115d157604051637dc7a0d960e11b81526001600160a01b0384166004820152602481018290526044810183905260640161118f565b6115e0848484840360006123f5565b50505050565b6001600160a01b03831661161057604051634b637e8f60e11b81526000600482015260240161118f565b6001600160a01b03821661163a5760405163ec442f0560e01b81526000600482015260240161118f565b610c49838383612585565b3361164e6111ed565b6001600160a01b0316146109295760405163118cdaa760e01b815233600482015260240161118f565b60006116816126d5565b90508060000361168e5750565b3660011981013560f01c90033560601c6000806116a9611b4e565b50509150915060008060006116bf868587611cd5565b925092509250806000036116d65750505050505050565b86600160008282546116e89190613b23565b9091555050845160005b8181101561179e57600084828151811061170e5761170e613afa565b60200260200101519050600081111561178d57600061173b608086898681518110610e0b57610e0b613afa565b90506117488b828461213b565b600260008b868151811061175e5761175e613afa565b6020026020010151815260200190815260200160002060000160008282546117869190613b23565b9091555050505b5061179781613b4f565b90506116f2565b505050505050505050565b80513660011981013560f01c90033560601c906000805b828110156118e75760006117ec8683815181106117df576117df613afa565b60200260200101516120dc565b604051627eeac760e11b81526001600160a01b03898116600483015262ffffff8316602483015291925060009187169062fdd58e90604401602060405180830381865afa158015611841573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118659190613b36565b62ffffff8316600090815260026020908152604080832080546001600160a01b038e168552600182019093529220549293509091808211156118d1576118af81830385608061215b565b6001600160a01b038c1660009081526001850160205260409020839055909601955b5050505050806118e090613b4f565b90506117c0565b508015611542576001600160a01b03851660009081526003602052604081208054839290611916908490613b23565b90915550505050505050565b8060000361192f57505050565b80600160008282546119419190613b10565b90915550506001600160a01b0383166000908152600360205260408120805483929061196e908490613b10565b90915550506040518181526001600160a01b038416907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a26119bb83836127e9565b610c497f0000000000000000000000000000000000000000000000000000000000000000848361231d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015611a315750825b905060008267ffffffffffffffff166001148015611a4e5750303b155b905081158015611a5c575080155b15611a7a5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315611aae57845468ff00000000000000001916680100000000000000001785555b3061015160a01b178814611ad55760405163f481290160e01b815260040160405180910390fd5b6000611ae387890189613a2d565b9050611aee8161284e565b611af8888861285f565b508315611b4457845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6060600080803660011981013560f01c900335841c6001600160a01b031663dbe65edc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc49190613b85565b600054909350600281810b9163010000009004900b611be88262ffffff8716613baa565b9350611bfd600282900b62ffffff8716613baa565b925062ffffff841180611c12575062ffffff83115b15611c305760405163328fa59b60e01b815260040160405180910390fd5b6000611c3c8585613b10565b90508067ffffffffffffffff811115611c5757611c57613bd2565b604051908082528060200260200182016040528015611c80578160200160208202803683370190505b50965060005b81811015611ccb57611c998187016120dc565b62ffffff16888281518110611cb057611cb0613afa565b6020908102919091010152611cc481613b4f565b9050611c86565b5050505090919293565b606080600080611d4686886001600160a01b03166317f11ecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d419190613bf8565b612a8f565b85519091508067ffffffffffffffff811115611d6457611d64613bd2565b604051908082528060200260200182016040528015611d8d578160200160208202803683370190505b5094508067ffffffffffffffff811115611da957611da9613bd2565b604051908082528060200260200182016040528015611dd2578160200160208202803683370190505b50935060005b81811015611f74576000611df78883815181106117df576117df613afa565b604051630157d2d160e31b815262ffffff8216600482015290915060009081906001600160a01b038d1690630abe9688906024016040805180830381865afa158015611e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6b9190613c35565b60405163bd85b03960e01b815262ffffff8616600482015291935091506000906001600160a01b038e169063bd85b03990602401602060405180830381865afa158015611ebc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee09190613b36565b90506000611f13846fffffffffffffffffffffffffffffffff16846fffffffffffffffffffffffffffffffff168a612aca565b9050808b8781518110611f2857611f28613afa565b602002602001018181525050818a8781518110611f4757611f47613afa565b6020908102919091010152611f5c818a613b23565b9850505050505080611f6d90613b4f565b9050611dd8565b50505093509350939050565b604080516001808252818301909252600091829190602080830190803683375091925050503660011981013560f01c90036014013581600081518110611fc857611fc8613afa565b6020908102919091010152604051632b357fb560e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063566aff6a906120249030908690600401613c9a565b600060405180830381865afa158015612041573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120699190810190613d84565b5050905060006001546120a261209c7f000000000000000000000000000000000000000000000000000000000000000090565b3061228d565b6120ac9190613b10565b905080826000815181106120c2576120c2613afa565b60200260200101516120d49190613b23565b935050505090565b8062ffffff8116811461210257604051639b63641560e01b815260040160405180910390fd5b919050565b600060ff831684811b9061ffff6101008290031686901c906121319087906001901b868585612b35565b9695505050505050565b600080600061214a8686612be1565b915091506121318686868585612b35565b600080600061216a8686612be1565b9150915081600014612180578360ff1682901c92505b80156121c057600160ff85161b81106121ac57604051638e471a8960e01b815260040160405180910390fd5b8360ff166101000361ffff1681901b830192505b50509392505050565b50505050505050565b8215610c4957610c4983634e430b5a60e01b8585856040516024016121f993929190613e6a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612c00565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b031916815561226882612c64565b5050565b61227b87878787878787612cd5565b6121c960045488888888888888612d57565b60006001600160a01b0383161561230d576040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa1580156122e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123089190613b36565b610a72565b506001600160a01b031631919050565b8015610c49576001600160a01b0383166123a5576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461237e576040519150601f19603f3d011682016040523d82523d6000602084013e612383565b606091505b50509050806115e057604051636750787b60e11b815260040160405180910390fd5b610c496001600160a01b0384168383612d9e565b6123c887878787878787612df0565b6121c960045488888888888888612e35565b6123e684848484612e7b565b6115e060045485858585612e83565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b0385166124405760405163e602df0560e01b81526000600482015260240161118f565b6001600160a01b03841661246a57604051634a1406b160e11b81526000600482015260240161118f565b6001600160a01b0380861660009081526001830160209081526040808320938816835292905220839055811561154257836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040516124df91815260200190565b60405180910390a35050505050565b6124f6611677565b61154284612536858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612ee092505050565b6117a9565b7410000000000000000000000000000000000000000086161561257d5761257d86630d4abdb360e01b87878787876040516024016121f9959493929190613eeb565b505050505050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b0384166125d357818160020160008282546125c89190613b23565b909155506126459050565b6001600160a01b038416600090815260208290526040902054828110156126265760405163391434e360e21b81526001600160a01b0386166004820152602481018290526044810184905260640161118f565b6001600160a01b03851660009081526020839052604090209083900390555b6001600160a01b038316612663576002810180548390039055612682565b6001600160a01b03831660009081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516126c791815260200190565b60405180910390a350505050565b604080516001808252818301909252600091829190602080830190803683375091925050503660011981013560f01c9003601401358160008151811061271d5761271d613afa565b6020908102919091010152604051630d74982760e31b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636ba4c13890612774908490600401613f2a565b600060405180830381600087803b15801561278e57600080fd5b505af11580156127a2573d6000803e3d6000fd5b5050505060006127d261209c7f000000000000000000000000000000000000000000000000000000000000000090565b9050600154816127e29190613b10565b9250505090565b6004548015610c49576040516308ae304f60e31b81526001600160a01b038216906345718278906128209086908690600401613c9a565b600060405180830381600087803b15801561283a57600080fd5b505af11580156121c9573d6000803e3d6000fd5b612856612f8b565b6111a181612fd9565b6000808061286f84860186613f3d565b935093509350506000836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156128b6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128de9190810190613f99565b90506000836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612920573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129489190810190613f99565b90506000828261295b8661ffff1661300b565b60405160200161296d9392919061402d565b60408051601f19818403018152828201909152601782527f4c4220486f6f6b73204d6574726f205265776172646572000000000000000000602083015291506129b681836130ab565b6129c13060016130bd565b6129ed307f0000000000000000000000000000000000000000000000000000000000000000600161145c565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e2bbb1583660011981013560f01c9003601401356040516001600160e01b031960e084901b168152600481019190915260016024820152604401600060405180830381600087803b158015612a6c57600080fd5b505af1158015612a80573d6000803e3d6000fd5b50505050505050505050505050565b600061271071ffff00000000000000000000000000000000608084901b1604600160801b0162ffffff8416627fffff1901610a4a82826130f3565b60008315612b05575080830281848281612ae657612ae66140a0565b0414612b05576040516363f1e01f60e01b815260040160405180910390fd5b8215610a725760809290921b91820182811015610a72576040516363f1e01f60e01b815260040160405180910390fd5b600081600003612b5657838381612b4e57612b4e6140a0565b049050610a4a565b838210612b76576040516313eae71560e01b815260040160405180910390fd5b600084868809600186198101871660008190038190049091018683119095039490940294038390049390931760029290940460038102831880820284030280820284030280820284030280820284030280820284030290810290920390910292909202949350505050565b6000806000198385098385029250828110838203039150509250929050565b600080839050602083015160e01c602060008551602087016000865af192503d151583151615612c34573d6000803e3d6000fd5b8060005160e01c14601f3d11168316925050816115e057604051636c93cb9b60e01b815260040160405180910390fd5b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b612cdd611677565b612d1a868585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117a992505050565b6121c9858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117a992505050565b7501000000000000000000000000000000000000000000881615611b4457611b44886379c8ccf760e01b898989898989896040516024016121f997969594939291906140b6565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610c4990849061335c565b612df8611677565b6121c9868585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117a992505050565b74400000000000000000000000000000000000000000881615611b4457611b448863ea9db9d360e01b898989898989896040516024016121f997969594939291906140b6565b6115e0611677565b74010000000000000000000000000000000000000000851615611542576040516001600160a01b0380861660248301528416604482015282151560648201526084810182905261154290869063feee373560e01b9060a4016121f9565b80516060908067ffffffffffffffff811115612efe57612efe613bd2565b604051908082528060200260200182016040528015612f27578160200160208202803683370190505b50915060005b81811015612f8457838181518110612f4757612f47613afa565b602002602001015160001c62ffffff16838281518110612f6957612f69613afa565b6020908102919091010152612f7d81613b4f565b9050612f2d565b5050919050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff1661092957604051631afcd79f60e31b815260040160405180910390fd5b612fe1612f8b565b6001600160a01b03811661119857604051631e4fbdf760e01b81526000600482015260240161118f565b60606000613018836133bf565b600101905060008167ffffffffffffffff81111561303857613038613bd2565b6040519080825280601f01601f191660200182016040528015613062576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461306c57509392505050565b6130b3612f8b565b61226882826134a1565b6001600160a01b0382166130e75760405163ec442f0560e01b81526000600482015260240161118f565b61226860008383612585565b60008060008360000361310f5750600160801b9150610a149050565b50826000811215613121579015906000035b6210000081101561331a57600160801b9250846fffffffffffffffffffffffffffffffff81111561315457911591600019045b60018216156131655792830260801c925b800260801c600282161561317b5792830260801c925b800260801c60048216156131915792830260801c925b800260801c60088216156131a75792830260801c925b800260801c60108216156131bd5792830260801c925b800260801c60208216156131d35792830260801c925b800260801c60408216156131e95792830260801c925b8002608090811c908216156132005792830260801c925b800260801c6101008216156132175792830260801c925b800260801c61020082161561322e5792830260801c925b800260801c6104008216156132455792830260801c925b800260801c61080082161561325c5792830260801c925b800260801c6110008216156132735792830260801c925b800260801c61200082161561328a5792830260801c925b800260801c6140008216156132a15792830260801c925b800260801c6180008216156132b85792830260801c925b800260801c620100008216156132d05792830260801c925b800260801c620200008216156132e85792830260801c925b800260801c620400008216156133005792830260801c925b800260801c620800008216156133185792830260801c925b505b8260000361334557604051631dba598d60e11b8152600481018690526024810185905260440161118f565b816133505782610a4a565b610a4a8360001961410c565b60006133716001600160a01b03841683613504565b90508051600014158015613396575080806020019051810190613394919061412e565b155b15610c4957604051635274afe760e01b81526001600160a01b038416600482015260240161118f565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613408577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310613434576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061345257662386f26fc10000830492506010015b6305f5e100831061346a576305f5e100830492506008015b612710831061347e57612710830492506004015b60648310613490576064830492506002015b600a8310610a145760010192915050565b6134a9612f8b565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace036134f58482614191565b50600481016115e08382614191565b6060610a728383600084600080856001600160a01b0316848660405161352a9190614251565b60006040518083038185875af1925050503d8060008114613567576040519150601f19603f3d011682016040523d82523d6000602084013e61356c565b606091505b509150915061213186838360608261358757612308826135ce565b815115801561359e57506001600160a01b0384163b155b156135c757604051639996b31560e01b81526001600160a01b038516600482015260240161118f565b5080610a72565b8051156135de5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60005b838110156136125781810151838201526020016135fa565b50506000910152565b602081526000825180602084015261363a8160408501602087016135f7565b601f01601f19169190910160400192915050565b6001600160a01b03811681146111a157600080fd5b6000806040838503121561367657600080fd5b82356136818161364e565b946020939093013593505050565b60008083601f8401126136a157600080fd5b50813567ffffffffffffffff8111156136b957600080fd5b6020830191508360208260051b85010111156136d457600080fd5b9250929050565b6000806000806000608086880312156136f357600080fd5b85356136fe8161364e565b9450602086013561370e8161364e565b9350604086013567ffffffffffffffff81111561372a57600080fd5b6137368882890161368f565b96999598509660600135949350505050565b60008060006060848603121561375d57600080fd5b83356137688161364e565b925060208401356137788161364e565b929592945050506040919091013590565b8035600281900b811461210257600080fd5b600080604083850312156137ae57600080fd5b6137b783613789565b91506137c560208401613789565b90509250929050565b6000806000604084860312156137e357600080fd5b83356137ee8161364e565b9250602084013567ffffffffffffffff81111561380a57600080fd5b6138168682870161368f565b9497909650939450505050565b60008083601f84011261383557600080fd5b50813567ffffffffffffffff81111561384d57600080fd5b6020830191508360208285010111156136d457600080fd5b60008060006040848603121561387a57600080fd5b83359250602084013567ffffffffffffffff81111561389857600080fd5b61381686828701613823565b80151581146111a157600080fd5b600080600080608085870312156138c857600080fd5b84356138d38161364e565b935060208501356138e38161364e565b925060408501356138f3816138a4565b9396929550929360600135925050565b6000806000806080858703121561391957600080fd5b84356139248161364e565b935060208501356139348161364e565b93969395505050506040820135916060013590565b600080600080600080600060a0888a03121561396457600080fd5b873561396f8161364e565b9650602088013561397f8161364e565b9550604088013561398f8161364e565b9450606088013567ffffffffffffffff808211156139ac57600080fd5b6139b88b838c0161368f565b909650945060808a01359150808211156139d157600080fd5b506139de8a828b0161368f565b989b979a50959850939692959293505050565b600080600060408486031215613a0657600080fd5b8335613a118161364e565b9250602084013567ffffffffffffffff81111561389857600080fd5b600060208284031215613a3f57600080fd5b8135610a728161364e565b60008060408385031215613a5d57600080fd5b8235613a688161364e565b91506020830135613a788161364e565b809150509250929050565b600181811c90821680613a9757607f821691505b602082108103613ab757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181036000831280158383131683831282161715613af357613af3613abd565b5092915050565b634e487b7160e01b600052603260045260246000fd5b81810381811115610a1457610a14613abd565b80820180821115610a1457610a14613abd565b600060208284031215613b4857600080fd5b5051919050565b600060018201613b6157613b61613abd565b5060010190565b600060208284031215613b7a57600080fd5b8151610a728161364e565b600060208284031215613b9757600080fd5b815162ffffff81168114610a7257600080fd5b8082018281126000831280158216821582161715613bca57613bca613abd565b505092915050565b634e487b7160e01b600052604160045260246000fd5b61ffff811681146111a157600080fd5b600060208284031215613c0a57600080fd5b8151610a7281613be8565b80516fffffffffffffffffffffffffffffffff8116811461210257600080fd5b60008060408385031215613c4857600080fd5b613c5183613c15565b91506137c560208401613c15565b600081518084526020808501945080840160005b83811015613c8f57815187529582019590820190600101613c73565b509495945050505050565b6001600160a01b0383168152604060208201526000613cbc6040830184613c5f565b949350505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715613ced57613ced613bd2565b604052919050565b600067ffffffffffffffff821115613d0f57613d0f613bd2565b5060051b60200190565b600082601f830112613d2a57600080fd5b81516020613d3f613d3a83613cf5565b613cc4565b82815260059290921b84018101918181019086841115613d5e57600080fd5b8286015b84811015613d795780518352918301918301613d62565b509695505050505050565b600080600060608486031215613d9957600080fd5b835167ffffffffffffffff80821115613db157600080fd5b613dbd87838801613d19565b9450602091508186015181811115613dd457600080fd5b8601601f81018813613de557600080fd5b8051613df3613d3a82613cf5565b81815260059190911b8201840190848101908a831115613e1257600080fd5b928501925b82841015613e39578351613e2a8161364e565b82529285019290850190613e17565b60408a0151909750945050505080821115613e5357600080fd5b50613e6086828701613d19565b9150509250925092565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115613ed257600080fd5b8260051b80836020870137939093016020019392505050565b60006001600160a01b03808816835280871660208401525060806040830152613f18608083018587613ea0565b90508260608301529695505050505050565b602081526000610a726020830184613c5f565b60008060008060808587031215613f5357600080fd5b8435613f5e8161364e565b93506020850135613f6e8161364e565b92506040850135613f7e8161364e565b91506060850135613f8e81613be8565b939692955090935050565b600060208284031215613fab57600080fd5b815167ffffffffffffffff80821115613fc357600080fd5b818401915084601f830112613fd757600080fd5b815181811115613fe957613fe9613bd2565b613ffc601f8201601f1916602001613cc4565b915080825285602082850101111561401357600080fd5b6140248160208401602086016135f7565b50949350505050565b6702b37ba32902621160c51b8152600084516140508160088501602089016135f7565b602d60f81b60089184019182015284516140718160098401602089016135f7565b601d60f91b60099290910191820152835161409381600a8401602088016135f7565b01600a0195945050505050565b634e487b7160e01b600052601260045260246000fd5b60006001600160a01b03808a168352808916602084015280881660408401525060a060608301526140eb60a083018688613ea0565b82810360808401526140fe818587613ea0565b9a9950505050505050505050565b60008261412957634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561414057600080fd5b8151610a72816138a4565b601f821115610c4957600081815260208120601f850160051c810160208610156141725750805b601f850160051c820191505b8181101561257d5782815560010161417e565b815167ffffffffffffffff8111156141ab576141ab613bd2565b6141bf816141b98454613a83565b8461414b565b602080601f8311600181146141f457600084156141dc5750858301515b600019600386901b1c1916600185901b17855561257d565b600085815260208120601f198616915b8281101561422357888601518255948401946001909101908401614204565b50858210156142415787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600082516142638184602087016135f7565b919091019291505056fea2646970667358221220256ea07fe364c2616c75e449a345c12a5fb91690ac0df78f3ba5dde2b3333d9e64736f6c6343000814003300000000000000000000000021428f5e261543bdd441db00fe266b60b3c7cf6600000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea000000000000000000000000f9c49d96dca71eeb655e89cf4d19351aad6cdace
Deployed Bytecode
0x6080604052600436106102bf5760003560e01c806370a082311161016e578063b8dc491b116100cb578063ea9db9d31161007f578063fdc2725711610064578063fdc272571461084f578063fe9ffeb31461086f578063feee373514610899576102ce565b8063ea9db9d31461080f578063f2fde38b1461082f576102ce565b8063c8772963116100b0578063c877296314610773578063dd62ed3e14610795578063e30c3978146107fa576102ce565b8063b8dc491b1461073e578063c7d12e881461075e576102ce565b80638da5cb5b116101225780639b4c8ea5116101075780639b4c8ea5146106b8578063a9059cbb146106eb578063b56449631461070b576102ce565b80638da5cb5b1461068e57806395d89b41146106a3576102ce565b806379ba50971161015357806379ba50971461063957806379c8ccf71461064e5780637a51a4c61461066e576102ce565b806370a08231146105cf578063715018a614610624576102ce565b80634e430b5a1161021c5780635f9c01b1116101d057806367ddb278116101b557806367ddb2781461055c57806369940d791461057c5780636e094176146105af576102ce565b80635f9c01b11461051a57806360bed5f31461053c576102ce565b806353e8079b1161020157806353e8079b1461048e578063566aff6a146104ae5780635c60da1b146104ce576102ce565b80634e430b5a1461044e578063505d90331461046e576102ce565b806323b872dd116102735780633f683b6a116102585780633f683b6a146103f957806343b312df1461040e578063457182781461042e576102ce565b806323b872dd146103bd578063313ce567146103dd576102ce565b806309fa1f90116102a457806309fa1f90146103315780630d4abdb31461034657806318160ddd1461037f576102ce565b806306fdde03146102d6578063095ea7b314610301576102ce565b366102ce576102cc6108b9565b005b6102cc6108b9565b3480156102e257600080fd5b506102eb61092b565b6040516102f8919061361b565b60405180910390f35b34801561030d57600080fd5b5061032161031c366004613663565b610a00565b60405190151581526020016102f8565b34801561033d57600080fd5b50610321610a1a565b34801561035257600080fd5b506103666103613660046136db565b610a29565b6040516001600160e01b031990911681526020016102f8565b34801561038b57600080fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b6040519081526020016102f8565b3480156103c957600080fd5b506103216103d8366004613748565b610a53565b3480156103e957600080fd5b50604051601281526020016102f8565b34801561040557600080fd5b50610321610a79565b34801561041a57600080fd5b506102cc61042936600461379b565b610a89565b34801561043a57600080fd5b506102cc6104493660046137ce565b610b63565b34801561045a57600080fd5b50610366610469366004613865565b610c4e565b34801561047a57600080fd5b50610366610489366004613748565b610c98565b34801561049a57600080fd5b506103666104a93660046138b2565b610cb2565b3480156104ba57600080fd5b506103af6104c93660046137ce565b610ccd565b3480156104da57600080fd5b506105027f0000000000000000000000001a5ded6adcfc64acede86151b1f142088c6e03da81565b6040516001600160a01b0390911681526020016102f8565b34801561052657600080fd5b503660011981013560f01c90033560601c610502565b34801561054857600080fd5b50610366610557366004613903565b610f35565b34801561056857600080fd5b50610366610577366004613949565b610f50565b34801561058857600080fd5b507f000000000000000000000000f9c49d96dca71eeb655e89cf4d19351aad6cdace610502565b3480156105bb57600080fd5b506102cc6105ca3660046139f1565b610f6e565b3480156105db57600080fd5b506103af6105ea366004613a2d565b6001600160a01b031660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00602052604090205490565b34801561063057600080fd5b506102cc611145565b34801561064557600080fd5b506102cc611157565b34801561065a57600080fd5b50610366610669366004613949565b6111a4565b34801561067a57600080fd5b506103666106893660046136db565b6111d1565b34801561069a57600080fd5b506105026111ed565b3480156106af57600080fd5b506102eb611222565b3480156106c457600080fd5b507f00000000000000000000000021428f5e261543bdd441db00fe266b60b3c7cf66610502565b3480156106f757600080fd5b50610321610706366004613663565b611273565b34801561071757600080fd5b507f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea610502565b34801561074a57600080fd5b506102cc610759366004613a4a565b611281565b34801561076a57600080fd5b506004546103af565b34801561077f57600080fd5b503660011981013560f01c9003601401356103af565b3480156107a157600080fd5b506103af6107b0366004613a4a565b6001600160a01b0391821660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b34801561080657600080fd5b50610502611326565b34801561081b57600080fd5b5061036661082a366004613949565b61134f565b34801561083b57600080fd5b506102cc61084a366004613a2d565b61137c565b34801561085b57600080fd5b5061036661086a366004613949565b611401565b34801561087b57600080fd5b5061088461141f565b604080519283526020830191909152016102f8565b3480156108a557600080fd5b506103666108b43660046138b2565b611435565b3660011981013560f01c146108e1576040516335f187f960e01b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000f9c49d96dca71eeb655e89cf4d19351aad6cdace16156109295760405163e22dfb1160e01b815260040160405180910390fd5b565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0380546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace009161097c90613a83565b80601f01602080910402602001604051908101604052809291908181526020018280546109a890613a83565b80156109f55780601f106109ca576101008083540402835291602001916109f5565b820191906000526020600020905b8154815290600101906020018083116109d857829003601f168201915b505050505091505090565b600033610a0e81858561145c565b60019150505b92915050565b6000610a24611469565b905090565b6000610a336114f4565b610a408686868686611525565b50630d4abdb360e01b5b95945050505050565b600033610a61858285611549565b610a6c8585856115e6565b60019150505b9392505050565b6000610a83611469565b15905090565b610a91611645565b8060020b8260020b1315610ab8576040516320aec07960e01b815260040160405180910390fd5b600b8260020b8260020b610acc9190613ad3565b1315610aeb5760405163be0ae43b60e01b815260040160405180910390fd5b610af3611677565b6000805462ffffff83811663010000000265ffffffffffff19909216908516171790556040517f0db02dbe95af4e060b3a554370b11d345d2c7ce375ca69cefa13977d5253479490610b579084908490600292830b8152910b602082015260400190565b60405180910390a15050565b610b6b611469565b610b88576040516319e0ccff60e11b815260040160405180910390fd5b336001600160a01b03841614610bb157604051637613d16960e01b815260040160405180910390fd5b610bb9611677565b610bf6838383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117a992505050565b610c498383838080602002602001604051908101604052809392919081815260200183836020028082843760009201829052506001600160a01b038a168152600360205260409020549250611922915050565b505050565b6000610c586114f4565b610c60611469565b610c7d57604051632def67a360e21b815260040160405180910390fd5b610c888484846119e6565b5063272185ad60e11b9392505050565b6000610ca26114f4565b5063505d903360e01b9392505050565b6000610cbc6114f4565b506353e8079b60e01b949350505050565b6000610cd7611469565b610ce357506000610a72565b82823660011981013560f01c90033560601c6000808080610d02611b4e565b93509350935093506000806000610d1a888789611cd5565b919450925090508d6000610d2c611f80565b90506000805b8c811015610efb576000610d5d8f8f84818110610d5157610d51613afa565b905060200201356120dc565b62ffffff8116600081815260026020908152604080832080546001600160a01b038c16855260019091019092529091205492935091908c11801590610da657508a8362ffffff16105b15610e40576000610dbc8d62ffffff8616613b10565b905060008a8281518110610dd257610dd2613afa565b60200260200101519050600081118015610dec575060008a115b15610e3d576000610e2260808c8f8681518110610e0b57610e0b613afa565b60200260200101516121079092919063ffffffff16565b9050610e2f89828461213b565b610e399086613b23565b9450505b50505b60008f6001600160a01b031662fdd58e89866040518363ffffffff1660e01b8152600401610e889291906001600160a01b0392909216825262ffffff16602082015260400190565b602060405180830381865afa158015610ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec99190613b36565b905081831115610ee657610ee182840382608061215b565b860195505b5050505080610ef490613b4f565b9050610d32565b506001600160a01b038316600090815260036020526040902054610f1f9082613b23565b9d50505050505050505050505050509392505050565b6000610f3f6114f4565b506360bed5f360e01b949350505050565b6000610f5a6114f4565b50630cfbb64f60e31b979650505050505050565b336001600160a01b037f00000000000000000000000021428f5e261543bdd441db00fe266b60b3c7cf661614610fa657610fa6611645565b6001600160a01b038316156110fe576001600160a01b03831661015160a01b1760048190553660011981013560f01c90033560601c6001600160a01b0316846001600160a01b0316635f9c01b16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611022573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110469190613b68565b6001600160a01b03161415806110cf5750306001600160a01b0316846001600160a01b03166320e1bba76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561109f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c39190613b68565b6001600160a01b031614155b156110ed576040516330e53f0760e11b815260040160405180910390fd5b6110f88184846121d2565b50611104565b60006004555b6040516001600160a01b03841681527fb9f3bf6e5f15f5daaaa5de4e2ac8f4f19c47a6d4e489efb48bd0d26ff478eba19060200160405180910390a1505050565b61114d611645565b6109296000612230565b3380611161611326565b6001600160a01b0316146111985760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6111a181612230565b50565b60006111ae6114f4565b6111bd8888888888888861226c565b506379c8ccf760e01b979650505050505050565b60006111db6114f4565b50633d28d26360e11b95945050505050565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b546001600160a01b031692915050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace009161097c90613a83565b600033610a0e8185856115e6565b611289611645565b6000611295833061228d565b9050806000036112b85760405163279157a960e01b815260040160405180910390fd5b6112c0611469565b80156112fd57507f000000000000000000000000f9c49d96dca71eeb655e89cf4d19351aad6cdace6001600160a01b0316836001600160a01b0316145b1561131b5760405163071e53cd60e21b815260040160405180910390fd5b610c4983838361231d565b6000807f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00611212565b60006113596114f4565b611368888888888888886123b9565b5063ea9db9d360e01b979650505050505050565b611384611645565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b0319166001600160a01b03831690811782556113c86111ed565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a35050565b600061140b6114f4565b5063fdc2725760e01b979650505050505050565b60008061142a611b4e565b909590945092505050565b600061143f6114f4565b61144b858585856123da565b5063feee373560e01b949350505050565b610c4983838360016123f5565b6000806114e33660011981013560f01c90033560601c6001600160a01b031663781a89156040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e09190613b36565b90565b6001600160a01b0316301492915050565b3660011981013560f01c90033560601c331461092957604051634a27038360e01b815233600482015260240161118f565b61153285858585856124ee565b611542600454868686868661253b565b5050505050565b6001600160a01b0383811660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace01602090815260408083209386168352929052205460001981146115e057818110156115d157604051637dc7a0d960e11b81526001600160a01b0384166004820152602481018290526044810183905260640161118f565b6115e0848484840360006123f5565b50505050565b6001600160a01b03831661161057604051634b637e8f60e11b81526000600482015260240161118f565b6001600160a01b03821661163a5760405163ec442f0560e01b81526000600482015260240161118f565b610c49838383612585565b3361164e6111ed565b6001600160a01b0316146109295760405163118cdaa760e01b815233600482015260240161118f565b60006116816126d5565b90508060000361168e5750565b3660011981013560f01c90033560601c6000806116a9611b4e565b50509150915060008060006116bf868587611cd5565b925092509250806000036116d65750505050505050565b86600160008282546116e89190613b23565b9091555050845160005b8181101561179e57600084828151811061170e5761170e613afa565b60200260200101519050600081111561178d57600061173b608086898681518110610e0b57610e0b613afa565b90506117488b828461213b565b600260008b868151811061175e5761175e613afa565b6020026020010151815260200190815260200160002060000160008282546117869190613b23565b9091555050505b5061179781613b4f565b90506116f2565b505050505050505050565b80513660011981013560f01c90033560601c906000805b828110156118e75760006117ec8683815181106117df576117df613afa565b60200260200101516120dc565b604051627eeac760e11b81526001600160a01b03898116600483015262ffffff8316602483015291925060009187169062fdd58e90604401602060405180830381865afa158015611841573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118659190613b36565b62ffffff8316600090815260026020908152604080832080546001600160a01b038e168552600182019093529220549293509091808211156118d1576118af81830385608061215b565b6001600160a01b038c1660009081526001850160205260409020839055909601955b5050505050806118e090613b4f565b90506117c0565b508015611542576001600160a01b03851660009081526003602052604081208054839290611916908490613b23565b90915550505050505050565b8060000361192f57505050565b80600160008282546119419190613b10565b90915550506001600160a01b0383166000908152600360205260408120805483929061196e908490613b10565b90915550506040518181526001600160a01b038416907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a26119bb83836127e9565b610c497f000000000000000000000000f9c49d96dca71eeb655e89cf4d19351aad6cdace848361231d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015611a315750825b905060008267ffffffffffffffff166001148015611a4e5750303b155b905081158015611a5c575080155b15611a7a5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315611aae57845468ff00000000000000001916680100000000000000001785555b3061015160a01b178814611ad55760405163f481290160e01b815260040160405180910390fd5b6000611ae387890189613a2d565b9050611aee8161284e565b611af8888861285f565b508315611b4457845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6060600080803660011981013560f01c900335841c6001600160a01b031663dbe65edc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc49190613b85565b600054909350600281810b9163010000009004900b611be88262ffffff8716613baa565b9350611bfd600282900b62ffffff8716613baa565b925062ffffff841180611c12575062ffffff83115b15611c305760405163328fa59b60e01b815260040160405180910390fd5b6000611c3c8585613b10565b90508067ffffffffffffffff811115611c5757611c57613bd2565b604051908082528060200260200182016040528015611c80578160200160208202803683370190505b50965060005b81811015611ccb57611c998187016120dc565b62ffffff16888281518110611cb057611cb0613afa565b6020908102919091010152611cc481613b4f565b9050611c86565b5050505090919293565b606080600080611d4686886001600160a01b03166317f11ecc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d419190613bf8565b612a8f565b85519091508067ffffffffffffffff811115611d6457611d64613bd2565b604051908082528060200260200182016040528015611d8d578160200160208202803683370190505b5094508067ffffffffffffffff811115611da957611da9613bd2565b604051908082528060200260200182016040528015611dd2578160200160208202803683370190505b50935060005b81811015611f74576000611df78883815181106117df576117df613afa565b604051630157d2d160e31b815262ffffff8216600482015290915060009081906001600160a01b038d1690630abe9688906024016040805180830381865afa158015611e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6b9190613c35565b60405163bd85b03960e01b815262ffffff8616600482015291935091506000906001600160a01b038e169063bd85b03990602401602060405180830381865afa158015611ebc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee09190613b36565b90506000611f13846fffffffffffffffffffffffffffffffff16846fffffffffffffffffffffffffffffffff168a612aca565b9050808b8781518110611f2857611f28613afa565b602002602001018181525050818a8781518110611f4757611f47613afa565b6020908102919091010152611f5c818a613b23565b9850505050505080611f6d90613b4f565b9050611dd8565b50505093509350939050565b604080516001808252818301909252600091829190602080830190803683375091925050503660011981013560f01c90036014013581600081518110611fc857611fc8613afa565b6020908102919091010152604051632b357fb560e11b81526000906001600160a01b037f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea169063566aff6a906120249030908690600401613c9a565b600060405180830381865afa158015612041573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120699190810190613d84565b5050905060006001546120a261209c7f000000000000000000000000f9c49d96dca71eeb655e89cf4d19351aad6cdace90565b3061228d565b6120ac9190613b10565b905080826000815181106120c2576120c2613afa565b60200260200101516120d49190613b23565b935050505090565b8062ffffff8116811461210257604051639b63641560e01b815260040160405180910390fd5b919050565b600060ff831684811b9061ffff6101008290031686901c906121319087906001901b868585612b35565b9695505050505050565b600080600061214a8686612be1565b915091506121318686868585612b35565b600080600061216a8686612be1565b9150915081600014612180578360ff1682901c92505b80156121c057600160ff85161b81106121ac57604051638e471a8960e01b815260040160405180910390fd5b8360ff166101000361ffff1681901b830192505b50509392505050565b50505050505050565b8215610c4957610c4983634e430b5a60e01b8585856040516024016121f993929190613e6a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612c00565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b031916815561226882612c64565b5050565b61227b87878787878787612cd5565b6121c960045488888888888888612d57565b60006001600160a01b0383161561230d576040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa1580156122e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123089190613b36565b610a72565b506001600160a01b031631919050565b8015610c49576001600160a01b0383166123a5576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461237e576040519150601f19603f3d011682016040523d82523d6000602084013e612383565b606091505b50509050806115e057604051636750787b60e11b815260040160405180910390fd5b610c496001600160a01b0384168383612d9e565b6123c887878787878787612df0565b6121c960045488888888888888612e35565b6123e684848484612e7b565b6115e060045485858585612e83565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b0385166124405760405163e602df0560e01b81526000600482015260240161118f565b6001600160a01b03841661246a57604051634a1406b160e11b81526000600482015260240161118f565b6001600160a01b0380861660009081526001830160209081526040808320938816835292905220839055811561154257836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040516124df91815260200190565b60405180910390a35050505050565b6124f6611677565b61154284612536858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612ee092505050565b6117a9565b7410000000000000000000000000000000000000000086161561257d5761257d86630d4abdb360e01b87878787876040516024016121f9959493929190613eeb565b505050505050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006001600160a01b0384166125d357818160020160008282546125c89190613b23565b909155506126459050565b6001600160a01b038416600090815260208290526040902054828110156126265760405163391434e360e21b81526001600160a01b0386166004820152602481018290526044810184905260640161118f565b6001600160a01b03851660009081526020839052604090209083900390555b6001600160a01b038316612663576002810180548390039055612682565b6001600160a01b03831660009081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516126c791815260200190565b60405180910390a350505050565b604080516001808252818301909252600091829190602080830190803683375091925050503660011981013560f01c9003601401358160008151811061271d5761271d613afa565b6020908102919091010152604051630d74982760e31b81526001600160a01b037f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea1690636ba4c13890612774908490600401613f2a565b600060405180830381600087803b15801561278e57600080fd5b505af11580156127a2573d6000803e3d6000fd5b5050505060006127d261209c7f000000000000000000000000f9c49d96dca71eeb655e89cf4d19351aad6cdace90565b9050600154816127e29190613b10565b9250505090565b6004548015610c49576040516308ae304f60e31b81526001600160a01b038216906345718278906128209086908690600401613c9a565b600060405180830381600087803b15801561283a57600080fd5b505af11580156121c9573d6000803e3d6000fd5b612856612f8b565b6111a181612fd9565b6000808061286f84860186613f3d565b935093509350506000836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156128b6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128de9190810190613f99565b90506000836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612920573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129489190810190613f99565b90506000828261295b8661ffff1661300b565b60405160200161296d9392919061402d565b60408051601f19818403018152828201909152601782527f4c4220486f6f6b73204d6574726f205265776172646572000000000000000000602083015291506129b681836130ab565b6129c13060016130bd565b6129ed307f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea600161145c565b6001600160a01b037f00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea1663e2bbb1583660011981013560f01c9003601401356040516001600160e01b031960e084901b168152600481019190915260016024820152604401600060405180830381600087803b158015612a6c57600080fd5b505af1158015612a80573d6000803e3d6000fd5b50505050505050505050505050565b600061271071ffff00000000000000000000000000000000608084901b1604600160801b0162ffffff8416627fffff1901610a4a82826130f3565b60008315612b05575080830281848281612ae657612ae66140a0565b0414612b05576040516363f1e01f60e01b815260040160405180910390fd5b8215610a725760809290921b91820182811015610a72576040516363f1e01f60e01b815260040160405180910390fd5b600081600003612b5657838381612b4e57612b4e6140a0565b049050610a4a565b838210612b76576040516313eae71560e01b815260040160405180910390fd5b600084868809600186198101871660008190038190049091018683119095039490940294038390049390931760029290940460038102831880820284030280820284030280820284030280820284030280820284030290810290920390910292909202949350505050565b6000806000198385098385029250828110838203039150509250929050565b600080839050602083015160e01c602060008551602087016000865af192503d151583151615612c34573d6000803e3d6000fd5b8060005160e01c14601f3d11168316925050816115e057604051636c93cb9b60e01b815260040160405180910390fd5b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b612cdd611677565b612d1a868585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117a992505050565b6121c9858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117a992505050565b7501000000000000000000000000000000000000000000881615611b4457611b44886379c8ccf760e01b898989898989896040516024016121f997969594939291906140b6565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610c4990849061335c565b612df8611677565b6121c9868585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506117a992505050565b74400000000000000000000000000000000000000000881615611b4457611b448863ea9db9d360e01b898989898989896040516024016121f997969594939291906140b6565b6115e0611677565b74010000000000000000000000000000000000000000851615611542576040516001600160a01b0380861660248301528416604482015282151560648201526084810182905261154290869063feee373560e01b9060a4016121f9565b80516060908067ffffffffffffffff811115612efe57612efe613bd2565b604051908082528060200260200182016040528015612f27578160200160208202803683370190505b50915060005b81811015612f8457838181518110612f4757612f47613afa565b602002602001015160001c62ffffff16838281518110612f6957612f69613afa565b6020908102919091010152612f7d81613b4f565b9050612f2d565b5050919050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff1661092957604051631afcd79f60e31b815260040160405180910390fd5b612fe1612f8b565b6001600160a01b03811661119857604051631e4fbdf760e01b81526000600482015260240161118f565b60606000613018836133bf565b600101905060008167ffffffffffffffff81111561303857613038613bd2565b6040519080825280601f01601f191660200182016040528015613062576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461306c57509392505050565b6130b3612f8b565b61226882826134a1565b6001600160a01b0382166130e75760405163ec442f0560e01b81526000600482015260240161118f565b61226860008383612585565b60008060008360000361310f5750600160801b9150610a149050565b50826000811215613121579015906000035b6210000081101561331a57600160801b9250846fffffffffffffffffffffffffffffffff81111561315457911591600019045b60018216156131655792830260801c925b800260801c600282161561317b5792830260801c925b800260801c60048216156131915792830260801c925b800260801c60088216156131a75792830260801c925b800260801c60108216156131bd5792830260801c925b800260801c60208216156131d35792830260801c925b800260801c60408216156131e95792830260801c925b8002608090811c908216156132005792830260801c925b800260801c6101008216156132175792830260801c925b800260801c61020082161561322e5792830260801c925b800260801c6104008216156132455792830260801c925b800260801c61080082161561325c5792830260801c925b800260801c6110008216156132735792830260801c925b800260801c61200082161561328a5792830260801c925b800260801c6140008216156132a15792830260801c925b800260801c6180008216156132b85792830260801c925b800260801c620100008216156132d05792830260801c925b800260801c620200008216156132e85792830260801c925b800260801c620400008216156133005792830260801c925b800260801c620800008216156133185792830260801c925b505b8260000361334557604051631dba598d60e11b8152600481018690526024810185905260440161118f565b816133505782610a4a565b610a4a8360001961410c565b60006133716001600160a01b03841683613504565b90508051600014158015613396575080806020019051810190613394919061412e565b155b15610c4957604051635274afe760e01b81526001600160a01b038416600482015260240161118f565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613408577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310613434576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061345257662386f26fc10000830492506010015b6305f5e100831061346a576305f5e100830492506008015b612710831061347e57612710830492506004015b60648310613490576064830492506002015b600a8310610a145760010192915050565b6134a9612f8b565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace036134f58482614191565b50600481016115e08382614191565b6060610a728383600084600080856001600160a01b0316848660405161352a9190614251565b60006040518083038185875af1925050503d8060008114613567576040519150601f19603f3d011682016040523d82523d6000602084013e61356c565b606091505b509150915061213186838360608261358757612308826135ce565b815115801561359e57506001600160a01b0384163b155b156135c757604051639996b31560e01b81526001600160a01b038516600482015260240161118f565b5080610a72565b8051156135de5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60005b838110156136125781810151838201526020016135fa565b50506000910152565b602081526000825180602084015261363a8160408501602087016135f7565b601f01601f19169190910160400192915050565b6001600160a01b03811681146111a157600080fd5b6000806040838503121561367657600080fd5b82356136818161364e565b946020939093013593505050565b60008083601f8401126136a157600080fd5b50813567ffffffffffffffff8111156136b957600080fd5b6020830191508360208260051b85010111156136d457600080fd5b9250929050565b6000806000806000608086880312156136f357600080fd5b85356136fe8161364e565b9450602086013561370e8161364e565b9350604086013567ffffffffffffffff81111561372a57600080fd5b6137368882890161368f565b96999598509660600135949350505050565b60008060006060848603121561375d57600080fd5b83356137688161364e565b925060208401356137788161364e565b929592945050506040919091013590565b8035600281900b811461210257600080fd5b600080604083850312156137ae57600080fd5b6137b783613789565b91506137c560208401613789565b90509250929050565b6000806000604084860312156137e357600080fd5b83356137ee8161364e565b9250602084013567ffffffffffffffff81111561380a57600080fd5b6138168682870161368f565b9497909650939450505050565b60008083601f84011261383557600080fd5b50813567ffffffffffffffff81111561384d57600080fd5b6020830191508360208285010111156136d457600080fd5b60008060006040848603121561387a57600080fd5b83359250602084013567ffffffffffffffff81111561389857600080fd5b61381686828701613823565b80151581146111a157600080fd5b600080600080608085870312156138c857600080fd5b84356138d38161364e565b935060208501356138e38161364e565b925060408501356138f3816138a4565b9396929550929360600135925050565b6000806000806080858703121561391957600080fd5b84356139248161364e565b935060208501356139348161364e565b93969395505050506040820135916060013590565b600080600080600080600060a0888a03121561396457600080fd5b873561396f8161364e565b9650602088013561397f8161364e565b9550604088013561398f8161364e565b9450606088013567ffffffffffffffff808211156139ac57600080fd5b6139b88b838c0161368f565b909650945060808a01359150808211156139d157600080fd5b506139de8a828b0161368f565b989b979a50959850939692959293505050565b600080600060408486031215613a0657600080fd5b8335613a118161364e565b9250602084013567ffffffffffffffff81111561389857600080fd5b600060208284031215613a3f57600080fd5b8135610a728161364e565b60008060408385031215613a5d57600080fd5b8235613a688161364e565b91506020830135613a788161364e565b809150509250929050565b600181811c90821680613a9757607f821691505b602082108103613ab757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181036000831280158383131683831282161715613af357613af3613abd565b5092915050565b634e487b7160e01b600052603260045260246000fd5b81810381811115610a1457610a14613abd565b80820180821115610a1457610a14613abd565b600060208284031215613b4857600080fd5b5051919050565b600060018201613b6157613b61613abd565b5060010190565b600060208284031215613b7a57600080fd5b8151610a728161364e565b600060208284031215613b9757600080fd5b815162ffffff81168114610a7257600080fd5b8082018281126000831280158216821582161715613bca57613bca613abd565b505092915050565b634e487b7160e01b600052604160045260246000fd5b61ffff811681146111a157600080fd5b600060208284031215613c0a57600080fd5b8151610a7281613be8565b80516fffffffffffffffffffffffffffffffff8116811461210257600080fd5b60008060408385031215613c4857600080fd5b613c5183613c15565b91506137c560208401613c15565b600081518084526020808501945080840160005b83811015613c8f57815187529582019590820190600101613c73565b509495945050505050565b6001600160a01b0383168152604060208201526000613cbc6040830184613c5f565b949350505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715613ced57613ced613bd2565b604052919050565b600067ffffffffffffffff821115613d0f57613d0f613bd2565b5060051b60200190565b600082601f830112613d2a57600080fd5b81516020613d3f613d3a83613cf5565b613cc4565b82815260059290921b84018101918181019086841115613d5e57600080fd5b8286015b84811015613d795780518352918301918301613d62565b509695505050505050565b600080600060608486031215613d9957600080fd5b835167ffffffffffffffff80821115613db157600080fd5b613dbd87838801613d19565b9450602091508186015181811115613dd457600080fd5b8601601f81018813613de557600080fd5b8051613df3613d3a82613cf5565b81815260059190911b8201840190848101908a831115613e1257600080fd5b928501925b82841015613e39578351613e2a8161364e565b82529285019290850190613e17565b60408a0151909750945050505080821115613e5357600080fd5b50613e6086828701613d19565b9150509250925092565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115613ed257600080fd5b8260051b80836020870137939093016020019392505050565b60006001600160a01b03808816835280871660208401525060806040830152613f18608083018587613ea0565b90508260608301529695505050505050565b602081526000610a726020830184613c5f565b60008060008060808587031215613f5357600080fd5b8435613f5e8161364e565b93506020850135613f6e8161364e565b92506040850135613f7e8161364e565b91506060850135613f8e81613be8565b939692955090935050565b600060208284031215613fab57600080fd5b815167ffffffffffffffff80821115613fc357600080fd5b818401915084601f830112613fd757600080fd5b815181811115613fe957613fe9613bd2565b613ffc601f8201601f1916602001613cc4565b915080825285602082850101111561401357600080fd5b6140248160208401602086016135f7565b50949350505050565b6702b37ba32902621160c51b8152600084516140508160088501602089016135f7565b602d60f81b60089184019182015284516140718160098401602089016135f7565b601d60f91b60099290910191820152835161409381600a8401602088016135f7565b01600a0195945050505050565b634e487b7160e01b600052601260045260246000fd5b60006001600160a01b03808a168352808916602084015280881660408401525060a060608301526140eb60a083018688613ea0565b82810360808401526140fe818587613ea0565b9a9950505050505050505050565b60008261412957634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561414057600080fd5b8151610a72816138a4565b601f821115610c4957600081815260208120601f850160051c810160208610156141725750805b601f850160051c820191505b8181101561257d5782815560010161417e565b815167ffffffffffffffff8111156141ab576141ab613bd2565b6141bf816141b98454613a83565b8461414b565b602080601f8311600181146141f457600084156141dc5750858301515b600019600386901b1c1916600185901b17855561257d565b600085815260208120601f198616915b8281101561422357888601518255948401946001909101908401614204565b50858210156142415787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600082516142638184602087016135f7565b919091019291505056fea2646970667358221220256ea07fe364c2616c75e449a345c12a5fb91690ac0df78f3ba5dde2b3333d9e64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000021428f5e261543bdd441db00fe266b60b3c7cf6600000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea000000000000000000000000f9c49d96dca71eeb655e89cf4d19351aad6cdace
-----Decoded View---------------
Arg [0] : lbHooksManager (address): 0x21428f5e261543BDd441Db00fE266b60b3C7Cf66
Arg [1] : masterChef (address): 0x72a42e8a344eB66ACA9eD13d5C633731cF54EeEa
Arg [2] : metro (address): 0xF9c49d96DCA71eeB655e89cF4d19351aAD6CDaCe
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000021428f5e261543bdd441db00fe266b60b3c7cf66
Arg [1] : 00000000000000000000000072a42e8a344eb66aca9ed13d5c633731cf54eeea
Arg [2] : 000000000000000000000000f9c49d96dca71eeb655e89cf4d19351aad6cdace
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.