creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/CatERC20Factory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.22;\n\nimport { IXERC20Factory } from './interfaces/IXERC20Factory.sol';\n\nimport { CatERC20 } from './CatERC20.sol';\nimport { CatLockbox } from './CatLockbox.sol';\n\n/**\n * @notice CatERC20 Factory. Helps with deploying CatERC20 to the same address across-chains.\n * @dev This contract has differences to CatERC20 including:\n * 1. Usage of CREATE2 instead of CREATE3. This makes CatERC20 cheaper to use but more expensive to deploy.\n * 2. No burn limits, CatERC20 tokens do not have burn limits and as a result, the burn arguments are not needed.\n * 3. Ability to deploy a token on behalf of another account.\n */\ncontract CatERC20Factory is IXERC20Factory {\n\n  /**\n   * @notice Deploys an CatERC20 contract using CREATE2.\n   * @dev limits and minters must be the same length.\n   * @param name The name of the token.\n   * @param symbol The symbol of the token.\n   * @param owner The owner of the token.\n   * @return caterc20 The address of the xerc20.\n   */\n  function deployXERC20(\n    string calldata name,\n    string calldata symbol,\n    address owner,\n    bytes12 salt\n  ) external returns (address caterc20) {\n    caterc20 = _deployXERC20(name, symbol, owner, salt);\n\n    CatERC20(caterc20).transferOwnership(owner);\n\n    emit XERC20Deployed(caterc20);\n  }\n\n  /**\n   * @notice Deploys an CatERC20 contract using CREATE2.\n   * @dev limits and minters must be the same length.\n   * @param name The name of the token.\n   * @param symbol The symbol of the token.\n   * @param minterLimits The array of limits that you are adding (optional, can be an empty array).\n   * @param bridges The array of bridges that you are adding (optional, can be an empty array).\n   * @return caterc20 The address of the xerc20.\n   */\n  function deployXERC20(\n    string calldata name,\n    string calldata symbol,\n    uint256[] calldata minterLimits,\n    address[] calldata bridges\n  ) external returns (address caterc20) {\n\n    caterc20 = _deployXERC20(name, symbol, msg.sender, bytes12(0));\n\n    _setBridgeLimits(caterc20, minterLimits, bridges);\n\n    CatERC20(caterc20).transferOwnership(msg.sender);\n\n    emit XERC20Deployed(caterc20);\n  }\n\n  /**\n   * @notice Deploys an XERC20Lockbox contract using CREATE2.\n   *\n   * @dev When deploying a lockbox for the gas token of the chain, then, the base token needs to be address(0).\n   * @param caterc20 The address of the caterc20 that you want to deploy a lockbox for.\n   * @param baseToken The address of the base token that you want to lock.\n   * @param isNative Whether or not the base token is the native (gas) token of the chain. Eg: MATIC for polygon chain.\n   * @return lockbox The address of the lockbox.\n   */\n  function deployLockbox(\n    address caterc20,\n    address baseToken,\n    bool isNative\n  ) external returns (address payable lockbox) {\n    if ((baseToken == address(0) && !isNative) || (isNative && baseToken != address(0))) {\n      revert IXERC20Factory_BadTokenAddress();\n    }\n\n    lockbox = _deployLockbox(caterc20, baseToken, isNative);\n\n    emit LockboxDeployed(lockbox);\n  }\n\n  function deployXERC20WithLockbox(\n    string calldata name,\n    string calldata symbol,\n    uint256[] calldata minterLimits,\n    address[] calldata bridges,\n    address baseToken,\n    bool isNative\n  ) external returns (address caterc20, address payable lockbox) {\n    if ((baseToken == address(0) && !isNative) || (isNative && baseToken != address(0))) {\n      revert IXERC20Factory_BadTokenAddress();\n    }\n    caterc20 = _deployXERC20(name, symbol, msg.sender, bytes12(0));\n\n    _setBridgeLimits(caterc20, minterLimits, bridges);\n\n    emit XERC20Deployed(caterc20);\n\n    lockbox = _deployLockbox(caterc20, baseToken, isNative);\n\n    CatERC20(caterc20).setLockbox(lockbox);\n\n    emit LockboxDeployed(lockbox);\n\n    CatERC20(caterc20).transferOwnership(msg.sender);\n  }\n\n  /**\n   * @notice Deploys an XERC20 contract using CREATE2.\n   * @dev _limits and _minters must be the same length.\n   * @param name The name of the token.\n   * @param symbol The symbol of the token.\n   * @param owner The owner of the address, used in the salt. It is expected.\n   * that ownership is transferred to this address.\n   * @return caterc20 The address of the xerc20.\n   */\n  function _deployXERC20(\n    string calldata name,\n    string calldata symbol,\n    address owner,\n    bytes12 salt\n  ) internal returns (address caterc20) {\n    // concat owner and salt. Owner is in first 20 bytes of the salt\n    // where salt is in the last 12.\n    bytes32 fullySalt = bytes32(uint256(bytes32(bytes20(owner))) + uint256(uint96(salt)));\n\n    caterc20 = address(new CatERC20{salt: fullySalt}(name, symbol, address(this)));\n  }\n\n  /**\n   * @notice Deploys an XERC20Lockbox contract using CREATE2.\n   *\n   * @dev When deploying a lockbox for the gas token of the chain, then, the base token needs to be address(0).\n   * Does not set the lockbox on the CatERC20 token, only deploying the \n   * lockbox itself.\n   * msg.sender is not included in the lockbox salt. This is not needed.\n   * since a lockbox is a non-ownable contract and is pure logic.\n   * @param caterc20 The address of the caterc20 that you want to deploy a lockbox for.\n   * @param baseToken The address of the base token that you want to lock.\n   * @param isNative Whether or not the base token is the native (gas) token of the chain. Eg: MATIC for polygon chain.\n   * @return lockbox The address of the lockbox.\n   */\n  function _deployLockbox(\n    address caterc20,\n    address baseToken,\n    bool isNative\n  ) internal returns (address payable lockbox) {\n    bytes32 salt = keccak256(abi.encodePacked(caterc20, baseToken, isNative)); // We technically don't have to include isNative in the salt since the baseToken does that. But for simplicity we do it anyway.\n\n    lockbox = payable(new CatLockbox{salt: salt}(caterc20, baseToken, isNative));\n\n    return lockbox;\n  }\n\n  /**\n   * @notice Set bridge limits.\n   *\n   * @param minterLimits The array of limits that you are adding (optional, can be an empty array).\n   * @param bridges The array of bridges that you are adding (optional, can be an empty array). \n   */\n  function _setBridgeLimits(\n    address caterc20,\n    uint256[] calldata minterLimits,\n    address[] calldata bridges\n  ) internal {\n    uint256 _bridgesLength = bridges.length;\n    if (minterLimits.length != _bridgesLength) {\n      revert IXERC20Factory_InvalidLength();\n    }\n\n    for (uint256 i; i < _bridgesLength; ++i) {\n      CatERC20(caterc20).setLimits(bridges[i], minterLimits[i], 0);\n    }\n  }\n}"
      },
      "src/interfaces/IXERC20Factory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4 <0.9.0;\n\ninterface IXERC20Factory {\n  /**\n   * @notice Emitted when a new XERC20 is deployed\n   *\n   * @param _xerc20 The address of the xerc20\n   */\n\n  event XERC20Deployed(address _xerc20);\n\n  /**\n   * @notice Emitted when a new XERC20Lockbox is deployed\n   *\n   * @param _lockbox The address of the lockbox\n   */\n\n  event LockboxDeployed(address _lockbox);\n\n  /**\n   * @notice Reverts when a non-owner attempts to call\n   */\n\n  error IXERC20Factory_NotOwner();\n\n  /**\n   * @notice Reverts when a lockbox is trying to be deployed from a malicious address\n   */\n\n  error IXERC20Factory_BadTokenAddress();\n\n  /**\n   * @notice Reverts when a lockbox is already deployed\n   */\n\n  error IXERC20Factory_LockboxAlreadyDeployed();\n\n  /**\n   * @notice Reverts when a the length of arrays sent is incorrect\n   */\n  error IXERC20Factory_InvalidLength();\n\n  /**\n   * @notice Deploys an XERC20 contract using CREATE2\n   * @dev _limits and _minters must be the same length\n   * @param _name The name of the token\n   * @param _symbol The symbol of the token\n   * @param _minterLimits The array of minter limits that you are adding (optional, can be an empty array)\n   * @param _bridges The array of burners that you are adding (optional, can be an empty array)\n   * @return _xerc20 The address of the xerc20\n   */\n\n  function deployXERC20(\n    string memory _name,\n    string memory _symbol,\n    uint256[] memory _minterLimits,\n    address[] memory _bridges\n  ) external returns (address _xerc20);\n\n  /**\n   * @notice Deploys an XERC20Lockbox contract using CREATE2\n   *\n   * @param _xerc20 The address of the xerc20 that you want to deploy a lockbox for\n   * @param _baseToken The address of the base token that you want to lock\n   * @param _isNative Whether or not the base token is native\n   * @return _lockbox The address of the lockbox\n   */\n\n  function deployLockbox(\n    address _xerc20,\n    address _baseToken,\n    bool _isNative\n  ) external returns (address payable _lockbox);\n}"
      },
      "src/CatERC20.sol": {
        "content": "/*\n                           ＿\n                       ／´    ｀フ\n           ,  '' ｀ ｀/          ,!\n        , '          レ    O    Oミ  \n        ;               `ミ __,xノﾞ､   A Catalyst for Cross-chain?\n        i         ﾐ      ; ,､､､、  ヽ、  \n    ,.-‐!          ﾐ    i        ｀ヽ.._,,)\n  / /´｀｀､        ミ  ヽ.           @@@  @\n  ヽ.ー─'´) ｰｰ -‐''ゝ､,,))          @@@@@  @@@\n   ''''''                      @@@  @@@@@  @@@@@\n                               @@@@@ @@@@@ @@@@@@@  \n                            @@  @@@@@  @@@  @@@@@@@   \n                             @@@   @@@@ @@@  @@@@@    \n                               @@@@  @@@  @@  @@      \n                                  @@@  @@@ @@         \n                                     @@@            \n*/\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.22;\n\n\nimport { IXERC20 } from \"./interfaces/IXERC20.sol\";\n\nimport { ERC20 } from \"solady/tokens/ERC20.sol\";\nimport { Ownable } from \"solady/auth/Ownable.sol\";\n\n/** @notice Optimised for storage, fits into a single slot: 6 + 13 + 13 = 32 */\nstruct Bridge {\n    uint48 lastTouched;\n    uint104 maxLimit;\n    uint104 currentLimit;\n}\n\n/** \n * @notice Optimised xERC20 token implementation\n * This xERC20 implementation does not use a burn limit but rather implements a combined\n * burn and mint limit where burns are subtracted from mints. This protects the contract\n * against DoS attacks and improves security by allowing administrators to generally\n * set a lower limit.\n *\n * xERC20 is a standard for cross-chain tokens where any bridge can burn and mint these\n * tokens by the owner setting bridge limits. It exists in conjunction with a lockbox\n * that allows non-cross-chain native tokens to be wrapped into a xERC20 compliant token.\n *\n * This contract can be used with or without a Factory to allow users to easily\n * deploy their token to any chain while maintaining the same address. Likewise, a lockbox\n * is not required and the token can be used as a token on its own.\n *\n * The implementation is inspired by https://github.com/defi-wonderland/xERC20.\n * @dev For optimisation purposes, the bridge limits can't be larger than uint104.\n * type(uint104).max is a magic number in this contract and implies unlimited mints.\n * The designated Lockbox is set as a Bridge with unlimited mints rather than\n * implementing dedicated logic if the sender is the lockbox.\n * \n * While the mint limit can maximum be type(uint104).max, bridges can limit more IFF \n * their limit is set to type(uint104).max as then any mint is ignored.\n */\ncontract CatERC20 is ERC20, Ownable, IXERC20 {\n\n  /** \n   * @notice Allow unlimited mints.\n   * @dev This is the max size of the Bridge struct.\n   */\n  uint256 constant UNLIMITED_MINTS = type(uint104).max;\n\n  /**\n   * @notice The duration it takes for the limits to fully replenish.\n   */\n  uint256 constant DURATION = 1 days;\n\n  error AmountTooHigh(); // 0xfd7850ad\n  error LockboxAlreadySet(); // 0xa7d05b56\n  error Lockbox0(); // 0x3f528d68\n\n  /**\n   * @notice Maps bridge address to bridge configurations.\n   */\n  mapping(address bridgeAddress => Bridge bridgeContext) public bridges;\n  \n\n  /**\n   * @notice The address of the lockbox contract.\n   */\n  address public lockbox;\n\n\n  // Set name and symbol.\n  // _Immutable variables cannot have a non-value type_, so they are just storage variables.\n  string NAME;\n  string SYMBOL;\n\n  constructor(string memory name_, string memory symbol_, address owner) {\n      NAME = name_;\n      SYMBOL = symbol_;\n      _initializeOwner(owner);\n\n      CONSTANT_NAME_HASH = keccak256(bytes(name_));\n  }\n\n  bytes32 immutable CONSTANT_NAME_HASH;\n  \n  /** \n   * @dev For more performance, override to return the constant value\n   * of `keccak256(bytes(name()))` if `name()` will never change.\n   */\n  function _constantNameHash() internal view override returns (bytes32 result) {\n    return result = CONSTANT_NAME_HASH;\n  }\n\n  /// @dev Returns the name of the token.\n  function name() public view override returns (string memory) {\n      return NAME;\n  }\n\n  /// @dev Returns the symbol of the token.\n  function symbol() public view override returns (string memory) {\n      return SYMBOL;\n  }\n\n  //--- Admin Set Functions ---//\n\n  /**\n   * @notice Sets the lockbox address.\n   * @dev Sets unlimited limits for the lockbox.\n   * @param lockbox_ The address of the lockbox.\n   */\n  function setLockbox(address lockbox_) public onlyOwner {\n    if (lockbox_ == address(0)) revert Lockbox0();\n    if (lockbox != address(0)) revert LockboxAlreadySet();\n    lockbox = lockbox_;\n    _changeLimit(lockbox_, UNLIMITED_MINTS);\n    emit LockboxSet(lockbox_);\n  }\n\n  /**\n   * @notice Updates the limits of any bridge.\n   * @dev Can only be called by the owner.\n   * type(uint104).max is a magic number, it is unlimited.\n   * @param bridge The address of the bridge we are setting the limits to.\n   * @param mintingLimit The updated minting limit we are setting to the bridge.\n   */\n  function setLimits(address bridge, uint256 mintingLimit, uint256 /* burningLimit */) public onlyOwner {\n    if (bridge == lockbox) revert Lockbox0();\n    // UNLIMITED_MINTS == type(uint104).max.\n    if (mintingLimit > UNLIMITED_MINTS) revert IXERC20_LimitsTooHigh();\n    _changeLimit(bridge, mintingLimit);\n    emit BridgeLimitsSet(mintingLimit, type(uint256).max, bridge);\n  }\n\n  //--- Bridge functions ---//\n\n  /**\n   * @notice Mints tokens for a user.\n   * @dev Can only be called by a minter: Bridge, Lockbox, or owner.\n   * @param user The address of the user who needs tokens minted.\n   * @param amount The amount of tokens being minted.\n   */\n  function mint(address user, uint256 amount) public {\n    if (amount > uint256(type(int256).max)) revert AmountTooHigh();\n\n    _useBridgeLimits(msg.sender, int256(amount));\n    _mint(user, amount);\n  }\n\n  /**\n   * @notice Let the owner mint tokens.\n   * This function exists to make it easier for owners to mint tokens.\n   * The XERC20 standard is a \"mintable token\", since the owner.\n   * can register themselves as a bridge and mint tokens that way.\n   * @dev Can only be called by the owner.\n   * @param user The address of the user who needs tokens minted.\n   * @param amount The amount of tokens being minted.\n   */\n  function ownableMint(address user, uint256 amount) external onlyOwner {\n    _mint(user, amount);\n  }\n\n  /**\n   * @notice Burns tokens for a user.\n   * @dev Can only be called by a minter.\n   * @param user The address of the user who needs tokens burned.\n   * @param amount The amount of tokens being burned.\n   */\n  function burn(address user, uint256 amount) public {\n    // if amount > -type(int256).min then it would overflow. int256 contains 1 more negative integer:\n    // -type(int256).min == type(int256).max - 1. The comparison amount > type(int256).max - 1 is\n    //  equiv.: amount >= type(int256).max because amount is discrete.\n    if (amount >= uint256(type(int256).max)) revert AmountTooHigh();\n    if (user != msg.sender) _spendAllowance(user, msg.sender, amount);\n\n    _useBridgeLimits(msg.sender, -int256(amount));\n    _burn(user, amount);\n  }\n\n  //--- View Bridge Limits ---//\n\n  /**\n   * @notice Returns the max limit of a bridge.\n   *\n   * @param bridge the bridge we are viewing the limits of.\n   * @return limit The limit the bridge has.\n   */\n  function mintingMaxLimitOf(address bridge) public view returns (uint256 limit) {\n    return limit = bridges[bridge].maxLimit;\n  }\n\n  /**\n   * @notice Returns the max limit of a bridge.\n   *\n   * @return limit The limit the bridge has.\n   */\n  function burningMaxLimitOf(address /* bridge */) public pure returns (uint256 limit) {\n    return limit = type(uint256).max;\n  }\n\n  /**\n   * @notice Returns the current mint limit of a bridge.\n   *\n   * @param bridge the bridge we are viewing the limits of.\n   * @return limit The limit the bridge has.\n   */\n  function mintingCurrentLimitOf(address bridge) public view returns (uint256 limit) {\n    Bridge storage bridgeContext = bridges[bridge];\n    return limit = _calcNewCurrentLimit(\n      bridgeContext.maxLimit,\n      bridgeContext.currentLimit,\n      bridgeContext.lastTouched,\n      block.timestamp,\n      0\n    );\n  }\n\n  /**\n   * @notice Returns the current burn limit of a bridge.\n   * @dev We have no defined burn limit and anyone is able to burn someone else's tokens\n   * if they have allowance.\n   * @return limit The limit the bridge has.\n   */\n  function burningCurrentLimitOf(address /* bridge */) public pure returns (uint256 limit) {\n    return limit = type(uint256).max;\n  }\n\n  //--- Change Bridge Limits ---//\n\n  /**\n   * @notice Spends from limits of a bridge.\n   * @dev Subtracts when minted (deltaLimit > 0), adds when burned (deltaLimit < 0).\n   * @param bridge The address of the bridge to change limits for.\n   * @param deltaLimit The change in the limit.\n   */\n  function _useBridgeLimits(address bridge, int256 deltaLimit) internal {\n    Bridge storage bridgeContext = bridges[bridge];\n\n    uint256 currentTime = block.timestamp;\n\n    uint256 newCurrentLimit = _calcNewCurrentLimit(\n      bridgeContext.maxLimit,\n      bridgeContext.currentLimit,\n      bridgeContext.lastTouched,\n      currentTime,\n      deltaLimit\n    );\n    \n    bridgeContext.lastTouched = uint40(currentTime);\n    bridgeContext.currentLimit = uint104(newCurrentLimit);\n  }\n\n  /**\n   * @notice Updates the limit of any bridge.\n   * @param bridge The address of the bridge we are setting the limit too.\n   * @param newMaxLimit The updated limit we are setting to the bridge.\n   */\n  function _changeLimit(address bridge, uint256 newMaxLimit) internal {\n    Bridge storage bridgeContext = bridges[bridge];\n\n    uint256 currentTime = block.timestamp;\n\n    uint256 newCurrentLimit = _calcNewCurrentLimit(\n      bridgeContext.maxLimit,\n      bridgeContext.currentLimit,\n      bridgeContext.lastTouched,\n      currentTime,\n      0\n    );\n\n    bridgeContext.lastTouched = uint40(currentTime);\n    bridgeContext.maxLimit = uint104(newMaxLimit);\n    bridgeContext.currentLimit = uint104(newCurrentLimit);\n  }\n\n  /**\n   * @notice Calculates the new limit based on decay in time.\n   * @dev Reverts if extraDifference cannot fit into the limit.\n   * \n   * Function constraints:\n   * maxLimit <= type(uint104).max.\n   * currentLimit <= type(uint104).max but may be larger than currentLimit.\n   * lastTouched <= reasonable timestamp <= type(uint48).max.\n   * currentTime <= reasonable timestamp <= type(uint48).max.\n   *  type(int256).min <= deltaLimit <= type(int256).max.\n   * \n   * @param maxLimit The maximum for the bridge.\n   * @param currentLimit The current used limit.\n   * @param lastTouched When the last change to the limit was made\n   * @param currentTime The current time. Please provide block.timestamp.\n   * @param deltaLimit The delta that has to be applied to the limit.\n   * @return newCurrentLimit The new current limit.\n   */\n  function _calcNewCurrentLimit(\n    uint256 maxLimit,\n    uint256 currentLimit,\n    uint256 lastTouched,\n    uint256 currentTime,\n    int256 deltaLimit\n  ) internal pure returns (uint256 newCurrentLimit) {\n    // Check if maxLimit is a magic number.\n    if (maxLimit == UNLIMITED_MINTS) return 0;\n    // Check that extraDifference < maxLimit.\n    // int256(maxLimit) cannot overflow in casting since maxLimit < type(uint104).max < type(int256).max\n    if (int256(maxLimit) < deltaLimit) revert IXERC20_NotHighEnoughLimits();\n\n    uint256 deltaTime;\n    unchecked {\n      // Current time is always greater than the last time it was touched.\n      deltaTime = currentTime - lastTouched;\n    }\n\n    // if deltaTime > DURATION: Then the new limit is deltaLimit since we know deltaLimit < maxLimit.\n    if (deltaTime >= DURATION) return deltaLimit > 0 ? uint256(deltaLimit) : 0;\n    \n    // Let us compute the decay.\n    uint256 decay = maxLimit * deltaTime / DURATION;\n    \n    newCurrentLimit = currentLimit > decay ? currentLimit - decay : 0;\n\n    // If deltaLimit < 0, then we don't have to check if it matches the limit.\n    // Likewise when deltaLimit = 0. \n    // The deltaLimit = 0 check is important when newCurrentLimit > maxLimit.\n    unchecked {\n      // Unchecked is important for uint256(-deltaLimit).\n      // If deltaLimit = type(int256).min then -deltaLimit overflows since signed integers\n      // are larger negative than positive by exactly 1.\n      // type(int256).min == [100000...00000]. We change the sign by taking the compliment and adding 1: -type(int256).min === [0111111...11111] + 1 = type(int256).max + 1 = uint256(-type(int256).min)\n      if (deltaLimit <= 0)\n        return newCurrentLimit > uint256(-deltaLimit) ? newCurrentLimit - uint256(-deltaLimit) : 0;\n    }\n\n    unchecked {\n      // deltaLimit is bounded by maxLimit. newCurrentLimit is bounded by type(uint104).max. Each of which is bounded by type(uint256).max / 2.\n      if (maxLimit < uint256(deltaLimit) + newCurrentLimit) revert IXERC20_NotHighEnoughLimits();\n      // Same bounded argument: newCurrentLimit + deltaLimit < type(104).max + maxLimit < type(104).max * 2.\n      // We also know that deltaLimit > 0 so it can be casted to uint256.\n      return newCurrentLimit + uint256(deltaLimit);\n    }\n  }\n}\n"
      },
      "src/CatLockbox.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.22;\n\nimport { IXERC20 } from './interfaces/IXERC20.sol';\nimport { IXERC20Lockbox } from './interfaces/IXERC20Lockbox.sol';\n\nimport { SafeTransferLib } from \"solady/utils/SafeTransferLib.sol\";\n\n/**\n * @notice XERC20 compatible lockbox.\n */\ncontract CatLockbox is IXERC20Lockbox {\n\n  error BaseTokenNotContract(); // 0x3577a588\n  error BadTokenAddress(); // 0xa3eecea2\n\n  /**\n   * @notice The XERC20 token of this contract\n   */\n  IXERC20 public immutable XERC20;\n\n  /**\n   * @notice The ERC20 token of this contract\n   */\n  address public immutable ERC20;\n\n  /**\n   * @notice Whether the ERC20 token is the native gas token of this chain\n   */\n  bool public immutable IS_NATIVE;\n\n  /**\n   * @notice Constructor\n   * @dev To use the lockbox properly, the lockbox has to be added to the XERC20 token.\n   *\n   * @param xerc20 The address of the CatERC20 contract\n   * @param baseToken The address of the ERC20 contract.\n   *  If isNative is false, then baseToken has to be a contract.\n   * @param isNative Whether the ERC20 token is the native gas token of this chain or not\n   */\n  constructor(address xerc20, address baseToken, bool isNative) {\n    if ((baseToken == address(0) && !isNative) || (isNative && baseToken != address(0))) {\n      revert BadTokenAddress();\n    }\n    // We use Solady safeTransfer library. The safeTransferFrom library does not check\n    // if baseToken has code before calling. As a result, if this lockbox is added as\n    // a lockbox for an xERC20 token deposit will pass (not collect tokens) for any value.\n    if (!isNative) if (baseToken.code.length == 0) revert BaseTokenNotContract();\n    \n    XERC20 = IXERC20(xerc20);\n    ERC20 = baseToken;\n    IS_NATIVE = isNative;\n  }\n\n  /**\n   * @notice Deposit native tokens into the lockbox\n   */\n\n  function depositNative() public payable {\n    if (!IS_NATIVE) revert IXERC20Lockbox_NotNative();\n\n    _deposit(msg.sender, msg.value);\n  }\n\n  /**\n   * @notice Deposit ERC20 tokens into the lockbox\n   *\n   * @param amount The amount of tokens to deposit\n   */\n  function deposit(uint256 amount) external {\n    if (IS_NATIVE) revert IXERC20Lockbox_Native();\n\n    _deposit(msg.sender, amount);\n  }\n\n  /**\n   * @notice Deposit ERC20 tokens into the lockbox, and send the CatERC20 to a user\n   *\n   * @param to The user to send the CatERC20 to\n   * @param amount The amount of tokens to deposit\n   */\n\n  function depositTo(address to, uint256 amount) external {\n    if (IS_NATIVE) revert IXERC20Lockbox_Native();\n\n    _deposit(to, amount);\n  }\n\n  /**\n   * @notice Deposit the native asset into the lockbox, and send the CatERC20 to a user\n   *\n   * @param to The user to send the CatERC20 to\n   */\n  function depositNativeTo(address to) public payable {\n    if (!IS_NATIVE) revert IXERC20Lockbox_NotNative();\n\n    _deposit(to, msg.value);\n  }\n\n  /**\n   * @notice Withdraw ERC20 tokens from the lockbox\n   *\n   * @param amount The amount of tokens to withdraw\n   */\n\n  function withdraw(uint256 amount) external {\n    _withdraw(msg.sender, amount);\n  }\n\n  /**\n   * @notice Withdraw tokens from the lockbox\n   *\n   * @param to The user to withdraw to\n   * @param amount The amount of tokens to withdraw\n   */\n\n  function withdrawTo(address to, uint256 amount) external {\n    _withdraw(to, amount);\n  }\n\n  /**\n   * @notice Withdraw tokens from the lockbox\n   *\n   * @param to The user to withdraw to\n   * @param amount The amount of tokens to withdraw\n   */\n  function _withdraw(address to, uint256 amount) internal {\n    XERC20.burn(msg.sender, amount);\n\n    if (IS_NATIVE) {\n      SafeTransferLib.safeTransferETH(to, amount);\n    } else {\n      SafeTransferLib.safeTransfer(ERC20, to, amount);\n    }\n    emit Withdraw(to, amount);\n  }\n\n  /**\n   * @notice Deposit tokens into the lockbox\n   *\n   * @param to The address to send the xerc20 to\n   * @param amount The amount of tokens to deposit\n   */\n  function _deposit(address to, uint256 amount) internal {\n    if (!IS_NATIVE) {\n      SafeTransferLib.safeTransferFrom(ERC20, msg.sender, address(this), amount);\n    }\n\n    XERC20.mint(to, amount);\n    emit Deposit(to, amount);\n  }\n\n  /**\n   * @notice Fallback function to deposit native tokens\n   */\n  receive() external payable {\n    depositNative();\n  }\n}"
      },
      "src/interfaces/IXERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4 <0.9.0;\n\ninterface IXERC20 {\n  /**\n   * @notice Emits when a lockbox is set\n   *\n   * @param lockbox The address of the lockbox\n   */\n  event LockboxSet(address lockbox);\n\n  /**\n   * @notice Emits when a limit is set\n   *\n   * @param mintingLimit The updated minting limit we are setting to the bridge\n   * @param burningLimit The updated burning limit we are setting to the bridge\n   * @param bridge The address of the bridge we are setting the limit too\n   */\n  event BridgeLimitsSet(uint256 mintingLimit, uint256 burningLimit, address indexed bridge);\n\n  /**\n   * @notice Reverts when a user with too low of a limit tries to call mint/burn\n   */\n  error IXERC20_NotHighEnoughLimits();\n\n  /**\n   * @notice Reverts when caller is not the factory\n   */\n  error IXERC20_NotFactory();\n\n  /**\n   * @notice Reverts when limits are too high\n   */\n  error IXERC20_LimitsTooHigh();\n\n  /**\n   * @notice Sets the lockbox address\n   *\n   * @param lockbox The address of the lockbox\n   */\n  function setLockbox(address lockbox) external;\n\n  /**\n   * @notice Updates the limits of any bridge\n   * @dev Can only be called by the owner\n   * @param mintingLimit The updated minting limit we are setting to the bridge\n   * @param burningLimit The updated burning limit we are setting to the bridge\n   * @param bridge The address of the bridge we are setting the limits too\n   */\n  function setLimits(address bridge, uint256 mintingLimit, uint256 burningLimit) external;\n\n  /**\n   * @notice Returns the max limit of a minter\n   *\n   * @param _minter The minter we are viewing the limits of\n   *  @return limit The limit the minter has\n   */\n  function mintingMaxLimitOf(address _minter) external view returns (uint256 limit);\n\n  /**\n   * @notice Returns the max limit of a bridge\n   *\n   * @param bridge the bridge we are viewing the limits of\n   * @return limit The limit the bridge has\n   */\n  function burningMaxLimitOf(address bridge) external view returns (uint256 limit);\n\n  /**\n   * @notice Returns the current limit of a minter\n   *\n   * @param minter The minter we are viewing the limits of\n   * @return limit The limit the minter has\n   */\n  function mintingCurrentLimitOf(address minter) external view returns (uint256 limit);\n\n  /**\n   * @notice Returns the current limit of a bridge\n   *\n   * @param bridge the bridge we are viewing the limits of\n   * @return limit The limit the bridge has\n   */\n  function burningCurrentLimitOf(address bridge) external view returns (uint256 limit);\n\n  /**\n   * @notice Mints tokens for a user\n   * @dev Can only be called by a minter\n   * @param user The address of the user who needs tokens minted\n   * @param amount The amount of tokens being minted\n   */\n  function mint(address user, uint256 amount) external;\n\n  /**\n   * @notice Burns tokens for a user\n   * @dev Can only be called by a minter\n   * @param user The address of the user who needs tokens burned\n   * @param amount The amount of tokens being burned\n   */\n  function burn(address user, uint256 amount) external;\n}"
      },
      "lib/solady/src/tokens/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Simple ERC20 + EIP-2612 implementation.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)\n///\n/// @dev Note:\n/// - The ERC20 standard allows minting and transferring to and from the zero address,\n///   minting and transferring zero tokens, as well as self-approvals.\n///   For performance, this implementation WILL NOT revert for such actions.\n///   Please add any checks with overrides if desired.\n/// - The `permit` function uses the ecrecover precompile (0x1).\n///\n/// If you are overriding:\n/// - NEVER violate the ERC20 invariant:\n///   the total sum of all balances must be equal to `totalSupply()`.\n/// - Check that the overridden function is actually used in the function you want to\n///   change the behavior of. Much of the code has been manually inlined for performance.\nabstract contract ERC20 {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The total supply has overflowed.\n    error TotalSupplyOverflow();\n\n    /// @dev The allowance has overflowed.\n    error AllowanceOverflow();\n\n    /// @dev The allowance has underflowed.\n    error AllowanceUnderflow();\n\n    /// @dev Insufficient balance.\n    error InsufficientBalance();\n\n    /// @dev Insufficient allowance.\n    error InsufficientAllowance();\n\n    /// @dev The permit is invalid.\n    error InvalidPermit();\n\n    /// @dev The permit has expired.\n    error PermitExpired();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                           EVENTS                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Emitted when `amount` tokens is transferred from `from` to `to`.\n    event Transfer(address indexed from, address indexed to, uint256 amount);\n\n    /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n    /// @dev `keccak256(bytes(\"Transfer(address,address,uint256)\"))`.\n    uint256 private constant _TRANSFER_EVENT_SIGNATURE =\n        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;\n\n    /// @dev `keccak256(bytes(\"Approval(address,address,uint256)\"))`.\n    uint256 private constant _APPROVAL_EVENT_SIGNATURE =\n        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                          STORAGE                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The storage slot for the total supply.\n    uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;\n\n    /// @dev The balance slot of `owner` is given by:\n    /// ```\n    ///     mstore(0x0c, _BALANCE_SLOT_SEED)\n    ///     mstore(0x00, owner)\n    ///     let balanceSlot := keccak256(0x0c, 0x20)\n    /// ```\n    uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;\n\n    /// @dev The allowance slot of (`owner`, `spender`) is given by:\n    /// ```\n    ///     mstore(0x20, spender)\n    ///     mstore(0x0c, _ALLOWANCE_SLOT_SEED)\n    ///     mstore(0x00, owner)\n    ///     let allowanceSlot := keccak256(0x0c, 0x34)\n    /// ```\n    uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20;\n\n    /// @dev The nonce slot of `owner` is given by:\n    /// ```\n    ///     mstore(0x0c, _NONCES_SLOT_SEED)\n    ///     mstore(0x00, owner)\n    ///     let nonceSlot := keccak256(0x0c, 0x20)\n    /// ```\n    uint256 private constant _NONCES_SLOT_SEED = 0x38377508;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         CONSTANTS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`.\n    uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901;\n\n    /// @dev `keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\")`.\n    bytes32 private constant _DOMAIN_TYPEHASH =\n        0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;\n\n    /// @dev `keccak256(\"1\")`.\n    bytes32 private constant _VERSION_HASH =\n        0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;\n\n    /// @dev `keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\")`.\n    bytes32 private constant _PERMIT_TYPEHASH =\n        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       ERC20 METADATA                       */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns the name of the token.\n    function name() public view virtual returns (string memory);\n\n    /// @dev Returns the symbol of the token.\n    function symbol() public view virtual returns (string memory);\n\n    /// @dev Returns the decimals places of the token.\n    function decimals() public view virtual returns (uint8) {\n        return 18;\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                           ERC20                            */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns the amount of tokens in existence.\n    function totalSupply() public view virtual returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := sload(_TOTAL_SUPPLY_SLOT)\n        }\n    }\n\n    /// @dev Returns the amount of tokens owned by `owner`.\n    function balanceOf(address owner) public view virtual returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x0c, _BALANCE_SLOT_SEED)\n            mstore(0x00, owner)\n            result := sload(keccak256(0x0c, 0x20))\n        }\n    }\n\n    /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.\n    function allowance(address owner, address spender)\n        public\n        view\n        virtual\n        returns (uint256 result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x20, spender)\n            mstore(0x0c, _ALLOWANCE_SLOT_SEED)\n            mstore(0x00, owner)\n            result := sload(keccak256(0x0c, 0x34))\n        }\n    }\n\n    /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n    ///\n    /// Emits a {Approval} event.\n    function approve(address spender, uint256 amount) public virtual returns (bool) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute the allowance slot and store the amount.\n            mstore(0x20, spender)\n            mstore(0x0c, _ALLOWANCE_SLOT_SEED)\n            mstore(0x00, caller())\n            sstore(keccak256(0x0c, 0x34), amount)\n            // Emit the {Approval} event.\n            mstore(0x00, amount)\n            log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c)))\n        }\n        return true;\n    }\n\n    /// @dev Transfer `amount` tokens from the caller to `to`.\n    ///\n    /// Requirements:\n    /// - `from` must at least have `amount`.\n    ///\n    /// Emits a {Transfer} event.\n    function transfer(address to, uint256 amount) public virtual returns (bool) {\n        _beforeTokenTransfer(msg.sender, to, amount);\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute the balance slot and load its value.\n            mstore(0x0c, _BALANCE_SLOT_SEED)\n            mstore(0x00, caller())\n            let fromBalanceSlot := keccak256(0x0c, 0x20)\n            let fromBalance := sload(fromBalanceSlot)\n            // Revert if insufficient balance.\n            if gt(amount, fromBalance) {\n                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n                revert(0x1c, 0x04)\n            }\n            // Subtract and store the updated balance.\n            sstore(fromBalanceSlot, sub(fromBalance, amount))\n            // Compute the balance slot of `to`.\n            mstore(0x00, to)\n            let toBalanceSlot := keccak256(0x0c, 0x20)\n            // Add and store the updated balance of `to`.\n            // Will not overflow because the sum of all user balances\n            // cannot exceed the maximum uint256 value.\n            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))\n            // Emit the {Transfer} event.\n            mstore(0x20, amount)\n            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))\n        }\n        _afterTokenTransfer(msg.sender, to, amount);\n        return true;\n    }\n\n    /// @dev Transfers `amount` tokens from `from` to `to`.\n    ///\n    /// Note: Does not update the allowance if it is the maximum uint256 value.\n    ///\n    /// Requirements:\n    /// - `from` must at least have `amount`.\n    /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.\n    ///\n    /// Emits a {Transfer} event.\n    function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {\n        _beforeTokenTransfer(from, to, amount);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let from_ := shl(96, from)\n            // Compute the allowance slot and load its value.\n            mstore(0x20, caller())\n            mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED))\n            let allowanceSlot := keccak256(0x0c, 0x34)\n            let allowance_ := sload(allowanceSlot)\n            // If the allowance is not the maximum uint256 value.\n            if add(allowance_, 1) {\n                // Revert if the amount to be transferred exceeds the allowance.\n                if gt(amount, allowance_) {\n                    mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.\n                    revert(0x1c, 0x04)\n                }\n                // Subtract and store the updated allowance.\n                sstore(allowanceSlot, sub(allowance_, amount))\n            }\n            // Compute the balance slot and load its value.\n            mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))\n            let fromBalanceSlot := keccak256(0x0c, 0x20)\n            let fromBalance := sload(fromBalanceSlot)\n            // Revert if insufficient balance.\n            if gt(amount, fromBalance) {\n                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n                revert(0x1c, 0x04)\n            }\n            // Subtract and store the updated balance.\n            sstore(fromBalanceSlot, sub(fromBalance, amount))\n            // Compute the balance slot of `to`.\n            mstore(0x00, to)\n            let toBalanceSlot := keccak256(0x0c, 0x20)\n            // Add and store the updated balance of `to`.\n            // Will not overflow because the sum of all user balances\n            // cannot exceed the maximum uint256 value.\n            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))\n            // Emit the {Transfer} event.\n            mstore(0x20, amount)\n            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))\n        }\n        _afterTokenTransfer(from, to, amount);\n        return true;\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                          EIP-2612                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev For more performance, override to return the constant value\n    /// of `keccak256(bytes(name()))` if `name()` will never change.\n    function _constantNameHash() internal view virtual returns (bytes32 result) {}\n\n    /// @dev Returns the current nonce for `owner`.\n    /// This value is used to compute the signature for EIP-2612 permit.\n    function nonces(address owner) public view virtual returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute the nonce slot and load its value.\n            mstore(0x0c, _NONCES_SLOT_SEED)\n            mstore(0x00, owner)\n            result := sload(keccak256(0x0c, 0x20))\n        }\n    }\n\n    /// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`,\n    /// authorized by a signed approval by `owner`.\n    ///\n    /// Emits a {Approval} event.\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public virtual {\n        bytes32 nameHash = _constantNameHash();\n        //  We simply calculate it on-the-fly to allow for cases where the `name` may change.\n        if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Revert if the block timestamp is greater than `deadline`.\n            if gt(timestamp(), deadline) {\n                mstore(0x00, 0x1a15a3cc) // `PermitExpired()`.\n                revert(0x1c, 0x04)\n            }\n            let m := mload(0x40) // Grab the free memory pointer.\n            // Clean the upper 96 bits.\n            owner := shr(96, shl(96, owner))\n            spender := shr(96, shl(96, spender))\n            // Compute the nonce slot and load its value.\n            mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX)\n            mstore(0x00, owner)\n            let nonceSlot := keccak256(0x0c, 0x20)\n            let nonceValue := sload(nonceSlot)\n            // Prepare the domain separator.\n            mstore(m, _DOMAIN_TYPEHASH)\n            mstore(add(m, 0x20), nameHash)\n            mstore(add(m, 0x40), _VERSION_HASH)\n            mstore(add(m, 0x60), chainid())\n            mstore(add(m, 0x80), address())\n            mstore(0x2e, keccak256(m, 0xa0))\n            // Prepare the struct hash.\n            mstore(m, _PERMIT_TYPEHASH)\n            mstore(add(m, 0x20), owner)\n            mstore(add(m, 0x40), spender)\n            mstore(add(m, 0x60), value)\n            mstore(add(m, 0x80), nonceValue)\n            mstore(add(m, 0xa0), deadline)\n            mstore(0x4e, keccak256(m, 0xc0))\n            // Prepare the ecrecover calldata.\n            mstore(0x00, keccak256(0x2c, 0x42))\n            mstore(0x20, and(0xff, v))\n            mstore(0x40, r)\n            mstore(0x60, s)\n            let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)\n            // If the ecrecover fails, the returndatasize will be 0x00,\n            // `owner` will be checked if it equals the hash at 0x00,\n            // which evaluates to false (i.e. 0), and we will revert.\n            // If the ecrecover succeeds, the returndatasize will be 0x20,\n            // `owner` will be compared against the returned address at 0x20.\n            if iszero(eq(mload(returndatasize()), owner)) {\n                mstore(0x00, 0xddafbaef) // `InvalidPermit()`.\n                revert(0x1c, 0x04)\n            }\n            // Increment and store the updated nonce.\n            sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds.\n            // Compute the allowance slot and store the value.\n            // The `owner` is already at slot 0x20.\n            mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender))\n            sstore(keccak256(0x2c, 0x34), value)\n            // Emit the {Approval} event.\n            log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender)\n            mstore(0x40, m) // Restore the free memory pointer.\n            mstore(0x60, 0) // Restore the zero pointer.\n        }\n    }\n\n    /// @dev Returns the EIP-712 domain separator for the EIP-2612 permit.\n    function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) {\n        bytes32 nameHash = _constantNameHash();\n        //  We simply calculate it on-the-fly to allow for cases where the `name` may change.\n        if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40) // Grab the free memory pointer.\n            mstore(m, _DOMAIN_TYPEHASH)\n            mstore(add(m, 0x20), nameHash)\n            mstore(add(m, 0x40), _VERSION_HASH)\n            mstore(add(m, 0x60), chainid())\n            mstore(add(m, 0x80), address())\n            result := keccak256(m, 0xa0)\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                  INTERNAL MINT FUNCTIONS                   */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Mints `amount` tokens to `to`, increasing the total supply.\n    ///\n    /// Emits a {Transfer} event.\n    function _mint(address to, uint256 amount) internal virtual {\n        _beforeTokenTransfer(address(0), to, amount);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT)\n            let totalSupplyAfter := add(totalSupplyBefore, amount)\n            // Revert if the total supply overflows.\n            if lt(totalSupplyAfter, totalSupplyBefore) {\n                mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`.\n                revert(0x1c, 0x04)\n            }\n            // Store the updated total supply.\n            sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter)\n            // Compute the balance slot and load its value.\n            mstore(0x0c, _BALANCE_SLOT_SEED)\n            mstore(0x00, to)\n            let toBalanceSlot := keccak256(0x0c, 0x20)\n            // Add and store the updated balance.\n            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))\n            // Emit the {Transfer} event.\n            mstore(0x20, amount)\n            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))\n        }\n        _afterTokenTransfer(address(0), to, amount);\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                  INTERNAL BURN FUNCTIONS                   */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Burns `amount` tokens from `from`, reducing the total supply.\n    ///\n    /// Emits a {Transfer} event.\n    function _burn(address from, uint256 amount) internal virtual {\n        _beforeTokenTransfer(from, address(0), amount);\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute the balance slot and load its value.\n            mstore(0x0c, _BALANCE_SLOT_SEED)\n            mstore(0x00, from)\n            let fromBalanceSlot := keccak256(0x0c, 0x20)\n            let fromBalance := sload(fromBalanceSlot)\n            // Revert if insufficient balance.\n            if gt(amount, fromBalance) {\n                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n                revert(0x1c, 0x04)\n            }\n            // Subtract and store the updated balance.\n            sstore(fromBalanceSlot, sub(fromBalance, amount))\n            // Subtract and store the updated total supply.\n            sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount))\n            // Emit the {Transfer} event.\n            mstore(0x00, amount)\n            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)\n        }\n        _afterTokenTransfer(from, address(0), amount);\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                INTERNAL TRANSFER FUNCTIONS                 */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Moves `amount` of tokens from `from` to `to`.\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        _beforeTokenTransfer(from, to, amount);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let from_ := shl(96, from)\n            // Compute the balance slot and load its value.\n            mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))\n            let fromBalanceSlot := keccak256(0x0c, 0x20)\n            let fromBalance := sload(fromBalanceSlot)\n            // Revert if insufficient balance.\n            if gt(amount, fromBalance) {\n                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n                revert(0x1c, 0x04)\n            }\n            // Subtract and store the updated balance.\n            sstore(fromBalanceSlot, sub(fromBalance, amount))\n            // Compute the balance slot of `to`.\n            mstore(0x00, to)\n            let toBalanceSlot := keccak256(0x0c, 0x20)\n            // Add and store the updated balance of `to`.\n            // Will not overflow because the sum of all user balances\n            // cannot exceed the maximum uint256 value.\n            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))\n            // Emit the {Transfer} event.\n            mstore(0x20, amount)\n            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))\n        }\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                INTERNAL ALLOWANCE FUNCTIONS                */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Updates the allowance of `owner` for `spender` based on spent `amount`.\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute the allowance slot and load its value.\n            mstore(0x20, spender)\n            mstore(0x0c, _ALLOWANCE_SLOT_SEED)\n            mstore(0x00, owner)\n            let allowanceSlot := keccak256(0x0c, 0x34)\n            let allowance_ := sload(allowanceSlot)\n            // If the allowance is not the maximum uint256 value.\n            if add(allowance_, 1) {\n                // Revert if the amount to be transferred exceeds the allowance.\n                if gt(amount, allowance_) {\n                    mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.\n                    revert(0x1c, 0x04)\n                }\n                // Subtract and store the updated allowance.\n                sstore(allowanceSlot, sub(allowance_, amount))\n            }\n        }\n    }\n\n    /// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.\n    ///\n    /// Emits a {Approval} event.\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let owner_ := shl(96, owner)\n            // Compute the allowance slot and store the amount.\n            mstore(0x20, spender)\n            mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED))\n            sstore(keccak256(0x0c, 0x34), amount)\n            // Emit the {Approval} event.\n            mstore(0x00, amount)\n            log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c)))\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                     HOOKS TO OVERRIDE                      */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Hook that is called before any transfer of tokens.\n    /// This includes minting and burning.\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /// @dev Hook that is called after any transfer of tokens.\n    /// This includes minting and burning.\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n"
      },
      "lib/solady/src/auth/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)\n///\n/// @dev Note:\n/// This implementation does NOT auto-initialize the owner to `msg.sender`.\n/// You MUST call the `_initializeOwner` in the constructor / initializer.\n///\n/// While the ownable portion follows\n/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,\n/// the nomenclature for the 2-step ownership handover may be unique to this codebase.\nabstract contract Ownable {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The caller is not authorized to call the function.\n    error Unauthorized();\n\n    /// @dev The `newOwner` cannot be the zero address.\n    error NewOwnerIsZeroAddress();\n\n    /// @dev The `pendingOwner` does not have a valid handover request.\n    error NoHandoverRequest();\n\n    /// @dev Cannot double-initialize.\n    error AlreadyInitialized();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                           EVENTS                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.\n    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be\n    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),\n    /// despite it not being as lightweight as a single argument event.\n    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);\n\n    /// @dev An ownership handover to `pendingOwner` has been requested.\n    event OwnershipHandoverRequested(address indexed pendingOwner);\n\n    /// @dev The ownership handover to `pendingOwner` has been canceled.\n    event OwnershipHandoverCanceled(address indexed pendingOwner);\n\n    /// @dev `keccak256(bytes(\"OwnershipTransferred(address,address)\"))`.\n    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =\n        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;\n\n    /// @dev `keccak256(bytes(\"OwnershipHandoverRequested(address)\"))`.\n    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =\n        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;\n\n    /// @dev `keccak256(bytes(\"OwnershipHandoverCanceled(address)\"))`.\n    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =\n        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                          STORAGE                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The owner slot is given by:\n    /// `bytes32(~uint256(uint32(bytes4(keccak256(\"_OWNER_SLOT_NOT\")))))`.\n    /// It is intentionally chosen to be a high value\n    /// to avoid collision with lower slots.\n    /// The choice of manual storage layout is to enable compatibility\n    /// with both regular and upgradeable contracts.\n    bytes32 internal constant _OWNER_SLOT =\n        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;\n\n    /// The ownership handover slot of `newOwner` is given by:\n    /// ```\n    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))\n    ///     let handoverSlot := keccak256(0x00, 0x20)\n    /// ```\n    /// It stores the expiry timestamp of the two-step ownership handover.\n    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                     INTERNAL FUNCTIONS                     */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.\n    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}\n\n    /// @dev Initializes the owner directly without authorization guard.\n    /// This function must be called upon initialization,\n    /// regardless of whether the contract is upgradeable or not.\n    /// This is to enable generalization to both regular and upgradeable contracts,\n    /// and to save gas in case the initial owner is not the caller.\n    /// For performance reasons, this function will not check if there\n    /// is an existing owner.\n    function _initializeOwner(address newOwner) internal virtual {\n        if (_guardInitializeOwner()) {\n            /// @solidity memory-safe-assembly\n            assembly {\n                let ownerSlot := _OWNER_SLOT\n                if sload(ownerSlot) {\n                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.\n                    revert(0x1c, 0x04)\n                }\n                // Clean the upper 96 bits.\n                newOwner := shr(96, shl(96, newOwner))\n                // Store the new value.\n                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))\n                // Emit the {OwnershipTransferred} event.\n                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)\n            }\n        } else {\n            /// @solidity memory-safe-assembly\n            assembly {\n                // Clean the upper 96 bits.\n                newOwner := shr(96, shl(96, newOwner))\n                // Store the new value.\n                sstore(_OWNER_SLOT, newOwner)\n                // Emit the {OwnershipTransferred} event.\n                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)\n            }\n        }\n    }\n\n    /// @dev Sets the owner directly without authorization guard.\n    function _setOwner(address newOwner) internal virtual {\n        if (_guardInitializeOwner()) {\n            /// @solidity memory-safe-assembly\n            assembly {\n                let ownerSlot := _OWNER_SLOT\n                // Clean the upper 96 bits.\n                newOwner := shr(96, shl(96, newOwner))\n                // Emit the {OwnershipTransferred} event.\n                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)\n                // Store the new value.\n                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))\n            }\n        } else {\n            /// @solidity memory-safe-assembly\n            assembly {\n                let ownerSlot := _OWNER_SLOT\n                // Clean the upper 96 bits.\n                newOwner := shr(96, shl(96, newOwner))\n                // Emit the {OwnershipTransferred} event.\n                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)\n                // Store the new value.\n                sstore(ownerSlot, newOwner)\n            }\n        }\n    }\n\n    /// @dev Throws if the sender is not the owner.\n    function _checkOwner() internal view virtual {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // If the caller is not the stored owner, revert.\n            if iszero(eq(caller(), sload(_OWNER_SLOT))) {\n                mstore(0x00, 0x82b42900) // `Unauthorized()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n\n    /// @dev Returns how long a two-step ownership handover is valid for in seconds.\n    /// Override to return a different value if needed.\n    /// Made internal to conserve bytecode. Wrap it in a public function if needed.\n    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {\n        return 48 * 3600;\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                  PUBLIC UPDATE FUNCTIONS                   */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Allows the owner to transfer the ownership to `newOwner`.\n    function transferOwnership(address newOwner) public payable virtual onlyOwner {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(shl(96, newOwner)) {\n                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.\n                revert(0x1c, 0x04)\n            }\n        }\n        _setOwner(newOwner);\n    }\n\n    /// @dev Allows the owner to renounce their ownership.\n    function renounceOwnership() public payable virtual onlyOwner {\n        _setOwner(address(0));\n    }\n\n    /// @dev Request a two-step ownership handover to the caller.\n    /// The request will automatically expire in 48 hours (172800 seconds) by default.\n    function requestOwnershipHandover() public payable virtual {\n        unchecked {\n            uint256 expires = block.timestamp + _ownershipHandoverValidFor();\n            /// @solidity memory-safe-assembly\n            assembly {\n                // Compute and set the handover slot to `expires`.\n                mstore(0x0c, _HANDOVER_SLOT_SEED)\n                mstore(0x00, caller())\n                sstore(keccak256(0x0c, 0x20), expires)\n                // Emit the {OwnershipHandoverRequested} event.\n                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())\n            }\n        }\n    }\n\n    /// @dev Cancels the two-step ownership handover to the caller, if any.\n    function cancelOwnershipHandover() public payable virtual {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute and set the handover slot to 0.\n            mstore(0x0c, _HANDOVER_SLOT_SEED)\n            mstore(0x00, caller())\n            sstore(keccak256(0x0c, 0x20), 0)\n            // Emit the {OwnershipHandoverCanceled} event.\n            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())\n        }\n    }\n\n    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.\n    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.\n    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute and set the handover slot to 0.\n            mstore(0x0c, _HANDOVER_SLOT_SEED)\n            mstore(0x00, pendingOwner)\n            let handoverSlot := keccak256(0x0c, 0x20)\n            // If the handover does not exist, or has expired.\n            if gt(timestamp(), sload(handoverSlot)) {\n                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.\n                revert(0x1c, 0x04)\n            }\n            // Set the handover slot to 0.\n            sstore(handoverSlot, 0)\n        }\n        _setOwner(pendingOwner);\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                   PUBLIC READ FUNCTIONS                    */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns the owner of the contract.\n    function owner() public view virtual returns (address result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := sload(_OWNER_SLOT)\n        }\n    }\n\n    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.\n    function ownershipHandoverExpiresAt(address pendingOwner)\n        public\n        view\n        virtual\n        returns (uint256 result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute the handover slot.\n            mstore(0x0c, _HANDOVER_SLOT_SEED)\n            mstore(0x00, pendingOwner)\n            // Load the handover slot.\n            result := sload(keccak256(0x0c, 0x20))\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         MODIFIERS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Marks a function as only callable by the owner.\n    modifier onlyOwner() virtual {\n        _checkOwner();\n        _;\n    }\n}\n"
      },
      "src/interfaces/IXERC20Lockbox.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4 <0.9.0;\n\ninterface IXERC20Lockbox {\n  /**\n   * @notice Emitted when tokens are deposited into the lockbox\n   *\n   * @param _sender The address of the user who deposited\n   * @param _amount The amount of tokens deposited\n   */\n\n  event Deposit(address _sender, uint256 _amount);\n\n  /**\n   * @notice Emitted when tokens are withdrawn from the lockbox\n   *\n   * @param _sender The address of the user who withdrew\n   * @param _amount The amount of tokens withdrawn\n   */\n\n  event Withdraw(address _sender, uint256 _amount);\n\n  /**\n   * @notice Reverts when a user tries to deposit native tokens on a non-native lockbox\n   */\n\n  error IXERC20Lockbox_NotNative();\n\n  /**\n   * @notice Reverts when a user tries to deposit non-native tokens on a native lockbox\n   */\n\n  error IXERC20Lockbox_Native();\n\n  /**\n   * @notice Reverts when a user tries to withdraw and the call fails\n   */\n\n  error IXERC20Lockbox_WithdrawFailed();\n\n  /**\n   * @notice Deposit ERC20 tokens into the lockbox\n   *\n   * @param _amount The amount of tokens to deposit\n   */\n\n  function deposit(uint256 _amount) external;\n\n  /**\n   * @notice Deposit ERC20 tokens into the lockbox, and send the XERC20 to a user\n   *\n   * @param _user The user to send the XERC20 to\n   * @param _amount The amount of tokens to deposit\n   */\n\n  function depositTo(address _user, uint256 _amount) external;\n\n  /**\n   * @notice Deposit the native asset into the lockbox, and send the XERC20 to a user\n   *\n   * @param _user The user to send the XERC20 to\n   */\n\n  function depositNativeTo(address _user) external payable;\n\n  /**\n   * @notice Withdraw ERC20 tokens from the lockbox\n   *\n   * @param _amount The amount of tokens to withdraw\n   */\n\n  function withdraw(uint256 _amount) external;\n\n  /**\n   * @notice Withdraw ERC20 tokens from the lockbox\n   *\n   * @param _user The user to withdraw to\n   * @param _amount The amount of tokens to withdraw\n   */\n\n  function withdrawTo(address _user, uint256 _amount) external;\n}"
      },
      "lib/solady/src/utils/SafeTransferLib.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)\n/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)\n///\n/// @dev Note:\n/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.\n/// - For ERC20s, this implementation won't check that a token has code,\n///   responsibility is delegated to the caller.\nlibrary SafeTransferLib {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The ETH transfer has failed.\n    error ETHTransferFailed();\n\n    /// @dev The ERC20 `transferFrom` has failed.\n    error TransferFromFailed();\n\n    /// @dev The ERC20 `transfer` has failed.\n    error TransferFailed();\n\n    /// @dev The ERC20 `approve` has failed.\n    error ApproveFailed();\n\n    /// @dev The Permit2 operation has failed.\n    error Permit2Failed();\n\n    /// @dev The Permit2 amount must be less than `2**160 - 1`.\n    error Permit2AmountOverflow();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         CONSTANTS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.\n    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;\n\n    /// @dev Suggested gas stipend for contract receiving ETH to perform a few\n    /// storage reads and writes, but low enough to prevent griefing.\n    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;\n\n    /// @dev The unique EIP-712 domain domain separator for the DAI token contract.\n    bytes32 internal constant DAI_DOMAIN_SEPARATOR =\n        0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;\n\n    /// @dev The address for the WETH9 contract on Ethereum mainnet.\n    address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n    /// @dev The canonical Permit2 address.\n    /// [Github](https://github.com/Uniswap/permit2)\n    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)\n    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       ETH OPERATIONS                       */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.\n    //\n    // The regular variants:\n    // - Forwards all remaining gas to the target.\n    // - Reverts if the target reverts.\n    // - Reverts if the current contract has insufficient balance.\n    //\n    // The force variants:\n    // - Forwards with an optional gas stipend\n    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).\n    // - If the target reverts, or if the gas stipend is exhausted,\n    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.\n    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.\n    // - Reverts if the current contract has insufficient balance.\n    //\n    // The try variants:\n    // - Forwards with a mandatory gas stipend.\n    // - Instead of reverting, returns whether the transfer succeeded.\n\n    /// @dev Sends `amount` (in wei) ETH to `to`.\n    function safeTransferETH(address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n\n    /// @dev Sends all the ETH in the current contract to `to`.\n    function safeTransferAllETH(address to) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Transfer all the ETH and check if it succeeded or not.\n            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n\n    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.\n    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if lt(selfbalance(), amount) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.\n    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.\n    function forceSafeTransferETH(address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if lt(selfbalance(), amount) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.\n    function forceSafeTransferAllETH(address to) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // forgefmt: disable-next-item\n            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.\n    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)\n        internal\n        returns (bool success)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)\n        }\n    }\n\n    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.\n    function trySafeTransferAllETH(address to, uint256 gasStipend)\n        internal\n        returns (bool success)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                      ERC20 OPERATIONS                      */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n    /// Reverts upon failure.\n    ///\n    /// The `from` account must have at least `amount` approved for\n    /// the current contract to manage.\n    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40) // Cache the free memory pointer.\n            mstore(0x60, amount) // Store the `amount` argument.\n            mstore(0x40, to) // Store the `to` argument.\n            mstore(0x2c, shl(96, from)) // Store the `from` argument.\n            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x60, 0) // Restore the zero slot to zero.\n            mstore(0x40, m) // Restore the free memory pointer.\n        }\n    }\n\n    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n    ///\n    /// The `from` account must have at least `amount` approved for the current contract to manage.\n    function trySafeTransferFrom(address token, address from, address to, uint256 amount)\n        internal\n        returns (bool success)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40) // Cache the free memory pointer.\n            mstore(0x60, amount) // Store the `amount` argument.\n            mstore(0x40, to) // Store the `to` argument.\n            mstore(0x2c, shl(96, from)) // Store the `from` argument.\n            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.\n            success :=\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n                )\n            mstore(0x60, 0) // Restore the zero slot to zero.\n            mstore(0x40, m) // Restore the free memory pointer.\n        }\n    }\n\n    /// @dev Sends all of ERC20 `token` from `from` to `to`.\n    /// Reverts upon failure.\n    ///\n    /// The `from` account must have their entire balance approved for the current contract to manage.\n    function safeTransferAllFrom(address token, address from, address to)\n        internal\n        returns (uint256 amount)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40) // Cache the free memory pointer.\n            mstore(0x40, to) // Store the `to` argument.\n            mstore(0x2c, shl(96, from)) // Store the `from` argument.\n            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.\n            // Read the balance, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.\n            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x60, 0) // Restore the zero slot to zero.\n            mstore(0x40, m) // Restore the free memory pointer.\n        }\n    }\n\n    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.\n    /// Reverts upon failure.\n    function safeTransfer(address token, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, amount) // Store the `amount` argument.\n            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Sends all of ERC20 `token` from the current contract to `to`.\n    /// Reverts upon failure.\n    function safeTransferAll(address token, address to) internal returns (uint256 amount) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.\n            mstore(0x20, address()) // Store the address of the current contract.\n            // Read the balance, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x14, to) // Store the `to` argument.\n            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.\n            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.\n    /// Reverts upon failure.\n    function safeApprove(address token, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, amount) // Store the `amount` argument.\n            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n            // Perform the approval, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.\n    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,\n    /// then retries the approval again (some tokens, e.g. USDT, requires this).\n    /// Reverts upon failure.\n    function safeApproveWithRetry(address token, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, amount) // Store the `amount` argument.\n            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n            // Perform the approval, retrying upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x34, 0) // Store 0 for the `amount`.\n                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.\n                mstore(0x34, amount) // Store back the original `amount`.\n                // Retry the approval, reverting upon failure.\n                if iszero(\n                    and(\n                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                    )\n                ) {\n                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.\n                    revert(0x1c, 0x04)\n                }\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Returns the amount of ERC20 `token` owned by `account`.\n    /// Returns zero if the `token` does not exist.\n    function balanceOf(address token, address account) internal view returns (uint256 amount) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, account) // Store the `account` argument.\n            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.\n            amount :=\n                mul( // The arguments of `mul` are evaluated from right to left.\n                    mload(0x20),\n                    and( // The arguments of `and` are evaluated from right to left.\n                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)\n                    )\n                )\n        }\n    }\n\n    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n    /// If the initial attempt fails, try to use Permit2 to transfer the token.\n    /// Reverts upon failure.\n    ///\n    /// The `from` account must have at least `amount` approved for the current contract to manage.\n    function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {\n        if (!trySafeTransferFrom(token, from, to, amount)) {\n            permit2TransferFrom(token, from, to, amount);\n        }\n    }\n\n    /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.\n    /// Reverts upon failure.\n    function permit2TransferFrom(address token, address from, address to, uint256 amount)\n        internal\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40)\n            mstore(add(m, 0x74), shr(96, shl(96, token)))\n            mstore(add(m, 0x54), amount)\n            mstore(add(m, 0x34), to)\n            mstore(add(m, 0x20), shl(96, from))\n            // `transferFrom(address,address,uint160,address)`.\n            mstore(m, 0x36c78516000000000000000000000000)\n            let p := PERMIT2\n            let exists := eq(chainid(), 1)\n            if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }\n            if iszero(and(call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00), exists)) {\n                mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.\n                revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)\n            }\n        }\n    }\n\n    /// @dev Permit a user to spend a given amount of\n    /// another user's tokens via native EIP-2612 permit if possible, falling\n    /// back to Permit2 if native permit fails or is not implemented on the token.\n    function permit2(\n        address token,\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        bool success;\n        /// @solidity memory-safe-assembly\n        assembly {\n            for {} shl(96, xor(token, WETH9)) {} {\n                mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.\n                if iszero(\n                    and( // The arguments of `and` are evaluated from right to left.\n                        lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.\n                        // Gas stipend to limit gas burn for tokens that don't refund gas when\n                        // an non-existing function is called. 5K should be enough for a SLOAD.\n                        staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)\n                    )\n                ) { break }\n                // After here, we can be sure that token is a contract.\n                let m := mload(0x40)\n                mstore(add(m, 0x34), spender)\n                mstore(add(m, 0x20), shl(96, owner))\n                mstore(add(m, 0x74), deadline)\n                if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {\n                    mstore(0x14, owner)\n                    mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.\n                    mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))\n                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.\n                    // `nonces` is already at `add(m, 0x54)`.\n                    // `1` is already stored at `add(m, 0x94)`.\n                    mstore(add(m, 0xb4), and(0xff, v))\n                    mstore(add(m, 0xd4), r)\n                    mstore(add(m, 0xf4), s)\n                    success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)\n                    break\n                }\n                mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.\n                mstore(add(m, 0x54), amount)\n                mstore(add(m, 0x94), and(0xff, v))\n                mstore(add(m, 0xb4), r)\n                mstore(add(m, 0xd4), s)\n                success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)\n                break\n            }\n        }\n        if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);\n    }\n\n    /// @dev Simple permit on the Permit2 contract.\n    function simplePermit2(\n        address token,\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40)\n            mstore(m, 0x927da105) // `allowance(address,address,address)`.\n            {\n                let addressMask := shr(96, not(0))\n                mstore(add(m, 0x20), and(addressMask, owner))\n                mstore(add(m, 0x40), and(addressMask, token))\n                mstore(add(m, 0x60), and(addressMask, spender))\n                mstore(add(m, 0xc0), and(addressMask, spender))\n            }\n            let p := mul(PERMIT2, iszero(shr(160, amount)))\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.\n                    staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)\n                )\n            ) {\n                mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.\n                revert(add(0x18, shl(2, iszero(p))), 0x04)\n            }\n            mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).\n            // `owner` is already `add(m, 0x20)`.\n            // `token` is already at `add(m, 0x40)`.\n            mstore(add(m, 0x60), amount)\n            mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.\n            // `nonce` is already at `add(m, 0xa0)`.\n            // `spender` is already at `add(m, 0xc0)`.\n            mstore(add(m, 0xe0), deadline)\n            mstore(add(m, 0x100), 0x100) // `signature` offset.\n            mstore(add(m, 0x120), 0x41) // `signature` length.\n            mstore(add(m, 0x140), r)\n            mstore(add(m, 0x160), s)\n            mstore(add(m, 0x180), shl(248, v))\n            if iszero(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) {\n                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "forge-std/=lib/forge-std/src/",
        "solady/=lib/solady/src/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 10000
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": true,
      "libraries": {}
    }
  }}