@ohgeez/fsushi
Version:
fSUSHI is a protocol built on top of [FlashStake](http://flashstake.io/) and [SushiSwap](https://sushi.com) that enables stakers to get instant, upfront yield without waiting for it to accrue.
313 lines • 382 kB
JSON
{
"language": "Solidity",
"sources": {
"contracts/FSushi.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"./interfaces/IFSushi.sol\";\nimport \"./libraries/DateUtils.sol\";\n\ncontract FSushi is Ownable, ERC20, IFSushi {\n using DateUtils for uint256;\n\n bytes32 private constant _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n uint256 private immutable _CACHED_CHAIN_ID;\n address private immutable _CACHED_THIS;\n\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n uint256 public immutable override startWeek;\n\n mapping(address => bool) public override isMinter;\n bool public override mintersLocked;\n\n mapping(address => uint256) public override nonces;\n /**\n * @return minimum number of minted total supply during the whole week (only available >= startWeek)\n */\n mapping(uint256 => uint256) public override totalSupplyDuring;\n /**\n * @notice totalSupplyDuring is guaranteed to be correct before this week (exclusive)\n */\n uint256 public override lastCheckpoint;\n\n modifier onlyMinter() {\n if (!isMinter[msg.sender]) revert Forbidden();\n _;\n }\n\n constructor() ERC20(\"Flash Sushi Token\", \"fSUSHI\") {\n uint256 nextWeek = block.timestamp.toWeekNumber() + 1;\n startWeek = nextWeek;\n lastCheckpoint = nextWeek;\n\n bytes32 hashedName = keccak256(bytes(\"Flash Sushi Token\"));\n bytes32 hashedVersion = keccak256(bytes(\"1\"));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n\n function setMinter(address account, bool _isMinter) external override onlyOwner {\n if (mintersLocked) revert MintersLocked();\n\n isMinter[account] = _isMinter;\n\n emit SetMinter(account, _isMinter);\n }\n\n function lockMinters() external onlyOwner {\n mintersLocked = true;\n\n emit LockMinters();\n }\n\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 ) external override {\n if (block.timestamp > deadline) revert Expired();\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n if (signer != owner) revert InvalidSignature();\n\n _approve(owner, spender, value);\n }\n\n function mint(address to, uint256 amount) external onlyMinter {\n _mint(to, amount);\n\n checkpoint();\n }\n\n function checkpointedTotalSupplyDuring(uint256 week) external override returns (uint256) {\n checkpoint();\n return totalSupplyDuring[week];\n }\n\n /**\n * @dev if this function doesn't get called for 512 weeks (around 9.8 years) this contract breaks\n */\n function checkpoint() public {\n uint256 from = lastCheckpoint;\n uint256 until = block.timestamp.toWeekNumber();\n if (until < from) return;\n\n for (uint256 i; i < 512; ) {\n uint256 week = from + i;\n uint256 old = totalSupplyDuring[week];\n if (week == until) {\n uint256 current = totalSupply();\n if (current > old) {\n totalSupplyDuring[week] = current;\n }\n break;\n } else if (startWeek < week && old == 0) {\n totalSupplyDuring[week] = totalSupplyDuring[week - 1];\n }\n\n unchecked {\n ++i;\n }\n }\n\n lastCheckpoint = until;\n\n emit Checkpoint(until);\n }\n}\n"
},
"contracts/interfaces/IFSushi.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IFSushi is IERC20Metadata {\n error Forbidden();\n error Expired();\n error MintersLocked();\n error InvalidSignature();\n\n event SetMinter(address indexed account, bool indexed isMinter);\n event LockMinters();\n event Checkpoint(uint256 lastCheckpoint);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function startWeek() external view returns (uint256);\n\n function isMinter(address account) external view returns (bool);\n\n function mintersLocked() external view returns (bool);\n\n function nonces(address account) external view returns (uint256);\n\n function totalSupplyDuring(uint256 time) external view returns (uint256);\n\n function lastCheckpoint() external view returns (uint256);\n\n function setMinter(address account, bool _isMinter) external;\n\n function lockMinters() external;\n\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 ) external;\n\n function mint(address to, uint256 amount) external;\n\n function checkpointedTotalSupplyDuring(uint256 week) external returns (uint256);\n\n function checkpoint() external;\n}\n"
},
"contracts/libraries/DateUtils.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nuint256 constant WEEK = 1 weeks;\n\nlibrary DateUtils {\n function toWeekNumber(uint256 timestamp) internal pure returns (uint256) {\n return timestamp / WEEK;\n }\n\n function toTimestamp(uint256 weekNumber) internal pure returns (uint256) {\n return weekNumber * WEEK;\n }\n}\n"
},
"@openzeppelin/contracts/access/Ownable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"
},
"@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV // Deprecated in v4.8\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC20/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n // decrementing then incrementing.\n _balances[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n unchecked {\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n _balances[account] += amount;\n }\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n // Overflow not possible: amount <= accountBalance <= totalSupply.\n _totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n"
},
"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n"
},
"@openzeppelin/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n"
},
"@openzeppelin/contracts/utils/Strings.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n"
},
"@openzeppelin/contracts/utils/math/Math.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10**64) {\n value /= 10**64;\n result += 64;\n }\n if (value >= 10**32) {\n value /= 10**32;\n result += 32;\n }\n if (value >= 10**16) {\n value /= 10**16;\n result += 16;\n }\n if (value >= 10**8) {\n value /= 10**8;\n result += 8;\n }\n if (value >= 10**4) {\n value /= 10**4;\n result += 4;\n }\n if (value >= 10**2) {\n value /= 10**2;\n result += 2;\n }\n if (value >= 10**1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n }\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC20.sol\";\nimport \"../../../utils/Context.sol\";\n\n/**\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\n * tokens and those that they have an allowance for, in a way that can be\n * recognized off-chain (via event analysis).\n */\nabstract contract ERC20Burnable is Context, ERC20 {\n /**\n * @dev Destroys `amount` tokens from the caller.\n *\n * See {ERC20-_burn}.\n */\n function burn(uint256 amount) public virtual {\n _burn(_msgSender(), amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, deducting from the caller's\n * allowance.\n *\n * See {ERC20-_burn} and {ERC20-allowance}.\n *\n * Requirements:\n *\n * - the caller must have allowance for ``accounts``'s tokens of at least\n * `amount`.\n */\n function burnFrom(address account, uint256 amount) public virtual {\n _spendAllowance(account, _msgSender(), amount);\n _burn(account, amount);\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC721/ERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n using Address for address;\n using Strings for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n interfaceId == type(IERC721).interfaceId ||\n interfaceId == type(IERC721Metadata).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: address zero is not a valid owner\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _ownerOf(tokenId);\n require(owner != address(0), \"ERC721: invalid token ID\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n _requireMinted(tokenId);\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overridden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not token owner or approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n _requireMinted(tokenId);\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner or approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner or approved\");\n _safeTransfer(from, to, tokenId, data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist\n */\n function _ownerOf(uint256 tokenId) internal view virtual returns (address) {\n return _owners[tokenId];\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _ownerOf(tokenId) != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n address owner = ERC721.ownerOf(tokenId);\n return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId, 1);\n\n // Check that tokenId was not minted by `_beforeTokenTransfer` hook\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n unchecked {\n // Will not overflow unless all 2**256 token ids are minted to the same owner.\n // Given that tokens are minted one by one, it is impossible in practice that\n // this ever happens. Might change if we allow batch minting.\n // The ERC fails to describe this case.\n _balances[to] += 1;\n }\n\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n\n _afterTokenTransfer(address(0), to, tokenId, 1);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n * This is an internal function that does not check if the sender is authorized to operate on the token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId, 1);\n\n // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook\n owner = ERC721.ownerOf(tokenId);\n\n // Clear approvals\n delete _tokenApprovals[tokenId];\n\n unchecked {\n // Cannot overflow, as that would require more tokens to be burned/transferred\n // out than the owner initially received through minting and transferring in.\n _balances[owner] -= 1;\n }\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n\n _afterTokenTransfer(owner, address(0), tokenId, 1);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId, 1);\n\n // Check that tokenId was not transferred by `_beforeTokenTransfer` hook\n require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n\n // Clear approvals from the previous owner\n delete _tokenApprovals[tokenId];\n\n unchecked {\n // `_balances[from]` cannot overflow for the same reason as described in `_burn`:\n // `from`'s balance is the number of token held, which is at least one before the current\n // transfer.\n // `_balances[to]` could overflow in the conditions described in `_mint`. That would require\n // all 2**256 token ids to be minted, which in practice is impossible.\n _balances[from] -= 1;\n _balances[to] += 1;\n }\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n\n _afterTokenTransfer(from, to, tokenId, 1);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits an {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits an {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Reverts if the `tokenId` has not been minted yet.\n */\n function _requireMinted(uint256 tokenId) internal view virtual {\n require(_exists(tokenId), \"ERC721: invalid token ID\");\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {\n return retval == IERC721Receiver.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n /// @solidity memory-safe-assembly\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is\n * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.\n * - When `from` is zero, the tokens will be minted for `to`.\n * - When `to` is zero, ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n * - `batchSize` is non-zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256, /* firstTokenId */\n uint256 batchSize\n ) internal virtual {\n if (batchSize > 1) {\n if (from != address(0)) {\n _balances[from] -= batchSize;\n }\n if (to != address(0)) {\n _balances[to] += batchSize;\n }\n }\n }\n\n /**\n * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is\n * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.\n * - When `from` is zero, the tokens were minted for `to`.\n * - When `to` is zero, ``from``'s tokens were burned.\n * - `from` and `to` are never both zero.\n * - `batchSize` is non-zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 firstTokenId,\n uint256 batchSize\n ) internal virtual {}\n}\n"
},
"@openzeppelin/contracts/utils/Address.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC721/IERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
},
"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"
},
"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n"
},
"@openzeppelin/contracts/utils/introspection/ERC165.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n"
},
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
},
"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/extensions/ERC721URIStorage.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC721.sol\";\n\n/**\n * @dev ERC721 token with storage based token URI management.\n */\nabstract contract ERC721URIStorage is ERC721 {\n using Strings for uint256;\n\n // Optional mapping for token URIs\n mapping(uint256 => string) private _tokenURIs;\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n _requireMinted(tokenId);\n\n string memory _tokenURI = _tokenURIs[tokenId];\n string memory base = _baseURI();\n\n // If there is no base URI, return the token URI.\n if (bytes(base).length == 0) {\n return _tokenURI;\n }\n // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).\n if (bytes(_tokenURI).length > 0) {\n return string(abi.encodePacked(base, _tokenURI));\n }\n\n return super.tokenURI(tokenId);\n }\n\n /**\n * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {\n require(_exists(tokenId), \"ERC721URIStorage: URI set of nonexistent token\");\n _tokenURIs[tokenId] = _tokenURI;\n }\n\n /**\n * @dev See {ERC721-_burn}. This override additionally checks to see if a\n * token-specific URI was set for the token, and if so, it deletes the token URI from\n * the storage mapping.\n */\n function _burn(uint256 tokenId) internal virtual override {\n super._burn(tokenId);\n\n if (bytes(_tokenURIs[tokenId]).length != 0) {\n delete _tokenURIs[tokenId];\n }\n }\n}\n"
},
"contracts/mocks/FlashNFT.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.4;\n\nimport \"@openzeppelin/contracts/utils/Counters.sol\";\nimport \"@openzeppelin/contracts/token/ERC721/ERC721.sol\";\nimport \"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract FlashNFT is ERC721URIStorage, Ownable {\n using Counters for Counters.Counter;\n Counters.Counter private tokenIds;\n\n constructor() ERC721(\"Flashstake NFT\", \"FLASHNFT\") {}\n\n function contractURI() public pure returns (string memory) {\n return \"https://nft.flashstake.io/metadata\";\n }\n\n function _baseURI() internal pure virtual override returns (string memory) {\n return \"https://nft.flashstake.io/\";\n }\n\n function exists(uint256 _tokenId) public view returns (bool) {\n return _exists(_tokenId);\n }\n\n // Only the FlashV3 protocol (owner) can burn\n function burn(uint256 _tokenId) public onlyOwner returns (bool) {\n _burn(_tokenId);\n return true;\n }\n\n // Only the FlashV3 protocol (owner) can mint\n function mint(address _recipientAddress) public onlyOwner returns (uint256) {\n tokenIds.increment();\n _mint(_recipientAddress, tokenIds.current());\n\n return tokenIds.current();\n }\n\n function totalSupply() public view returns (uint256) {\n return tokenIds.current();\n }\n}\n"
},
"@openzeppelin/contracts/utils/Counters.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n struct Counter {\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n // this feature: see https://github.com/ethereum/solidity/issues/4637\n uint256 _value; // default: 0\n }\n\n function current(Counter storage counter) internal view returns (uint256) {\n return counter._value;\n }\n\n function increment(Counter storage counter) internal {\n unchecked {\n counter._value += 1;\n }\n }\n\n function decrement(Counter storage counter) internal {\n uint256 value = counter._value;\n require(value > 0, \"Counter: decrement overflow\");\n unchecked {\n counter._value = value - 1;\n }\n }\n\n function reset(Counter storage counter) internal {\n counter._value = 0;\n }\n}\n"
},
"contracts/mocks/VotingEscrowMock.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"./libraries/Integers.sol\";\n\n/**\n * @title Voting Escrow\n * @author LevX (team@levx.io)\n * @notice Votes have a weight depending on time, so that users are\n * committed to the future of (whatever they are voting for)\n * @dev Vote weight decays linearly over time. Lock time cannot be\n * more than `MAXTIME`.\n * @dev Ported from vyper (https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/VotingEscrow.vy)\n */\n\n// Voting escrow to have time-weighted votes\n// Votes have a weight depending on time, so that users are committed\n// to the future of (whatever they are voting for).\n// The weight in this implementation is linear, and lock cannot be more than maxtime:\n// w ^\n// 1 + /\n// | /\n// | /\n// | /\n// |/\n// 0 +--------+------> time\n// maxtime\n\ncontract VotingEscrowMock is Ownable, ReentrancyGuard {\n using SafeERC20 for IERC20;\n using Integers for int128;\n using Integers for uint256;\n\n event Deposit(\n address indexed provider,\n uint256 value,\n uint256 discount,\n uint256 indexed unlockTime,\n int128 indexed _type,\n uint256 ts\n );\n event Withdraw(address indexed provider, uint256 value, uint256 discount, uint256 ts);\n event Supply(uint256 prevSupply, uint256 supply);\n\n struct Point {\n int128 bias;\n int128 slope; // - dweight / dt\n uint256 ts;\n uint256 blk; // block\n }\n\n struct LockedBalance {\n int128 amount;\n int128 discount;\n uint256 start;\n uint256 end;\n }\n\n int128 public constant DEPOSIT_FOR_TYPE = 0;\n int128 public constant CRETE_LOCK_TYPE = 1;\n int128 public constant INCREASE_LOCK_AMOUNT = 2;\n int128 public constant INCREASE_UNLOCK_TIME = 3;\n uint256 internal constant MULTIPLIER = 1e18;\n\n uint256 public immutable interval;\n uint256 public immutable maxDuration;\n address public immutable token;\n string public name;\n string public symbol;\n uint8 public immutable decimals;\n\n address public migrator;\n\n uint256 public supply;\n mapping(address => bool) public migrated;\n mapping(address => address[]) public delegateAt;\n mapping(address => LockedBalance) public locked;\n uint256 public epoch;\n\n mapping(uint256 => Point) public pointHistory; // epoch -> unsigned point\n mapping(address => mapping(uint256 => Point)) public userPointHistory; // user -> Point[user_epoch]\n mapping(address => uint256) public userPointEpoch;\n mapping(uint256 => int128) public slopeChanges; // time -> signed slope change\n\n constructor(\n address _token,\n string memory _name,\n string memory _symbol,\n uint256 _interval,\n uint256 _maxDuration\n ) {\n token = _token;\n name = _name;\n symbol = _symbol;\n decimals = IERC20Metadata(_token).decimals();\n\n interval = _interval;\n maxDuration = (_maxDuration / _interval) * _interval; // rounded down to a multiple of interval\n\n pointHistory[0].blk = block.number;\n pointHistory[0].ts = block.timestamp;\n }\n\n function delegateLength(address addr) external view returns (uint256) {\n return delegateAt[addr].length;\n }\n\n /**\n * @notice Get the most recently recorded rate of voting power decrease for `addr`\n * @param addr Address of the user wallet\n * @return Value of the slope\n */\n function getLastUserSlope(address addr) external view returns (int128) {\n uint256 uepoch = userPointEpoch[addr];\n return userPointHistory[addr][uepoch].slope;\n }\n\n /**\n * @notice Get the timestamp for checkpoint `_idx` for `_addr`\n * @param _addr User wallet address\n * @param _idx User epoch number\n * @return Epoch time of the checkpoint\n */\n function getCheckpointTime(address _addr, uint256 _idx) external view returns (uint256) {\n return userPointHistory[_addr][_idx].ts;\n }\n\n /**\n * @notice Get timestamp when `_addr`'s lock finishes\n * @param _addr User wallet\n * @return Epoch time of the lock end\n */\n function unlockTime(address _addr) external view returns (uint256) {\n return locked[_addr].end;\n }\n\n /**\n * @notice Record global and per-user data to checkpoint\n * @param addr User's wallet address. No user checkpoint if 0x0\n * @param old_locked Pevious locked amount / end lock time for the user\n * @param new_locked New locked amount / end lock time for the user\n */\n function _checkpoint(\n address addr,\n LockedBalance memory old_locked,\n LockedBalance memory new_locked\n ) internal {\n Point memory u_old;\n Point memory u_new;\n int128 old_dslope;\n int128 new_dslope;\n uint256 _epoch = epoch;\n\n if (addr != address(0)) {\n // Calculate slopes and biases\n // Kept at zero when they have to\n if (old_locked.end > block.timestamp && old_locked.amount > 0) {\n u_old.slope = old_locked.amount / maxDuration.toInt128();\n u_old.bias = u_old.slope * (old_locked.end - block.timestamp).toInt128();\n }\n if (new_locked.end > block.timestamp && new_locked.amount > 0) {\n u_new.slope = new_locked.amount / maxDuration.toInt128();\n u_new.bias = u_new.slope * (new_locked.end - block.timestamp).toInt128();\n }\n\n // Read values of scheduled changes in the slope\n // old_locked.end can be in the past and in the future\n // new_locked.end can ONLY by in the FUTURE unless everything expired: than zeros\n old_dslope = slopeChanges[old_locked.end];\n if (new_locked.end != 0) {\n if (new_locked.end == old_locked.end) new_dslope = old_dslope;\n else new_dslope = slopeChanges[new_locked.end];\n }\n }\n\n Point memory last_point = Point({bias: 0, slope: 0, ts: block.timestamp, blk: block.number});\n if (_epoch > 0) last_point = pointHistory[_epoch];\n uint256 last_checkpoint = last_point.ts;\n // initial_last_point is used for extrapolation to calculate block number\n // (approximately, for *At methods) and save them\n // as we cannot figure that out exactly from inside the contract\n Point memory initial_last_point = Point(last_point.bias, last_point.slope, last_point.ts, last_point.blk);\n uint256 block_slope; // dblock/dt\n if (block.timestamp > last_point.ts)\n block_slope = (MULTIPLIER * (block.number - last_point.blk)) / (block.timestamp - last_point.ts);\n // If last point is already recorded in this block, slope=0\n // But that's ok b/c we know the block in such case\n\n {\n // Go over weeks to fill history and calculate what the current point is\n uint256 t_i = (last_checkpoint / interval) * interval;\n for (uint256 i; i < 255; i++) {\n // Hopefully it won't happen that this won't get used in 5 years!\n // If it does, users will be able to withdraw but vote weight will be broken\n t_i += interval;\n int128 d_slope;\n if (t_i > block.timestamp) t_i = block.timestamp;\n else d_slope = slopeChanges[t_i];\n last_point.bias -= last_point.slope * (t_i - last_checkpoint).toInt128();\n last_point.slope += d_slope;\n if (last_point.bias < 0)\n // This can happen\n last_point.bias = 0;\n if (last_point.slope < 0)\n // This cannot happen - just in case\n last_point.slope = 0;\n last_checkpoint = t_i;\n last_point.ts = t_i;\n last_point.blk = initial_last_point.blk + (block_slope * (t_i - initial_last_point.ts)) / MULTIPLIER;\n _epoch += 1;\n if (t_i == block.timestamp) {\n last_point.blk = block.number;\n break;\n } else pointHistory[_epoch] = last_point;\n }\n }\n\n epoch = _epoch;\n // Now point_history is filled until t=now\n\n if (addr != address(0)) {\n // If last point was in this block, the slope change has been applied already\n // But in such case we have 0 slope(s)\n last_point.slope += (u_new.slope - u_old.slope);\n last_point.bias += (u_new.bias - u_old.bias);\n if (last_point.slope < 0) last_point.slope = 0;\n if (last_point.bias < 0) last_point.bias = 0;\n }\n\n // Record the changed point into history\n pointHistory[_epoch] = last_point;\n\n if (addr != address(0)) {\n // Schedule the slope changes (slope is going down)\n // We subtract new_user_slope from [new_locked.end]\n // and add old_user_slope to [old_locked.end]\n if (old_locked.end > block.timestamp) {\n // old_dslope was <something> - u_old.slope, so we cancel that\n old_dslope += u_old.slope;\n if (new_locked.end == old_locked.end) old_dslope -= u_new.slope; // It was a new deposit, not extension\n slopeChanges[old_locked.end] = old_dslope;\n }\n\n if (new_locked.end > block.timestamp) {\n if (new_locked.end > old_locked.end) {\n new_dslope -= u_new.slope; // old slope disappeared at this point\n slopeChanges[new_locked.end] = new_dslope;\n }\n // else: we recorded it already in old_dslope\n }\n\n // Now handle user history\n uint256 user_epoch = userPointEpoch[addr] + 1;\n\n userPointEpoch[addr] = user_epoch;\n u_new.ts = block.timestamp;\n u_new.blk = block.number;\n userPointHistory[addr][user_epoch] = u_new;\n }\n }\n\n /**\n * @notice Deposit and lock tokens for a user\n * @param _addr User's wallet address\n * @param _value Amount to deposit\n * @param _discount Amount to get discounted out of _value\n * @param unlock_time New time when to unlock the tokens, or 0 if unchanged\n * @param locked_balance Previous locked amount / timestamp\n */\n function _depositFor(\n address _addr,\n uint256 _value,\n uint256 _discount,\n uint256 unlock_time,\n LockedBalance memory locked_balance,\n int128 _type\n ) internal {\n LockedBalance memory _locked = locked_balance;\n uint256 supply_before = supply;\n\n supply = supply_before + _value;\n LockedBalance memory old_locked;\n (old_locked.amount, old_locked.discount, old_locked.start, old_locked.end) = (\n _locked.amount,\n _locked.discount,\n _locked.start,\n _locked.end\n );\n // Adding to existing lock, or if a lock is expired - creating a new one\n _locked.amount += (_value).toInt128();\n if (_discount != 0) _locked.discount += _discount.toInt128();\n if (unlock_time != 0) {\n if (_locked.start == 0) _locked.start = block.timestamp;\n _locked.end = unlock_time;\n }\n locked[_addr] = _locked;\n\n // Possibilities:\n // Both old_locked.end could be current or expired (>/< block.timestamp)\n // value == 0 (extend lock) or value > 0 (add to lock or extend lock)\n // _locked.end > block.timestamp (always)\n _checkpoint(_addr, old_locked, _locked);\n\n if (_value > _discount) {\n IERC20(token).safeTransferFrom(_addr, address(this), _value - _discount);\n }\n\n emit Deposit(_addr, _value, _discount, _locked.end, _type, block.timestamp);\n emit Supply(supply_before, supply_before + _value);\n }\n\n /**\n * @notice Record global data to checkpoint\n */\n function checkpoint() external {\n _checkpoint(address(0), LockedBalance(0, 0, 0, 0), LockedBalance(0, 0, 0, 0));\n }\n\n /**\n * @notice Deposit `_value` tokens for `_addr` and add to the lock\n * @dev Anyone (even a smart contract) can deposit for someone else, but\n * cannot extend their locktime and deposit for a brand new user\n * @param _addr User's wallet address\n * @param _value Amount to add to user's lock\n */\n function depositFor(address _addr, uint256 _value) external nonReentrant {\n LockedBalance memory _locked = locked[_addr];\n\n require(_value > 0, \"VE: INVALID_VALUE\");\n require(_locked.amount > 0, \"VE: LOCK_NOT_FOUND\");\n require(_locked.end > block.timestamp, \"VE: LOCK_EXPIRED\");\n\n _depositFor(_addr, _value, 0, 0, _locked, DEPOSIT_FOR_TYPE);\n }\n\n /**\n * @notice Deposit `_value` tokens with `_discount` for `_addr` and lock for `_duration`\n * @param _addr User's wallet address\n * @param _value Amount to add to user's lock\n * @param _discount Amount to get discounted out of _value\n * @param _duration Epoch time until tokens unlock from now\n */\n function createLockFor(\n address _addr,\n uint256 _value,\n uint256 _discount,\n uint256 _duration\n ) external nonReentrant {\n uint256 unlock_time = ((block.timestamp + _duration) / interval) * interval; // Locktime is rounded down to a multiple of interval\n LockedBalance memory _locked = locked[_addr];\n\n require(_value > 0, \"VE: INVALID_VALUE\");\n require(_value >= _discount, \"VE: DISCOUNT_TOO_HIGH\");\n require(_locked.amount == 0, \"VE: EXISTING_LOCK_FOUND\");\n require(unlock_time > block.timestamp, \"VE: UNLOCK_TIME_TOO_EARLY\");\n require(unlock_time <= block.timestamp + maxDuration, \"VE: UNLOCK_TIME_TOO_LATE\");\n\n _depositFor(_addr, _value, _discount, unlock_time, _locked, CRETE_LOCK_TYPE);\n }\n\n /**\n * @notice Deposit `_value` tokens for `msg.sender` and lock for `_duration`\n * @param _value Amount to deposit\n * @param _duration Epoch time until tokens unlock from now\n */\n function createLock(uint256 _value, uint256 _duration) external nonReentrant {\n uint256 unlock_time = ((block.timestamp + _duration) / interval) * interval; // Locktime is rounded down to a multiple of interval\n LockedBalance memory _locked = locked[msg.sender];\n\n require(_value > 0, \"VE: INVALID_VALUE\");\n require(_locked.amount == 0, \"VE: EXISTING_LOCK_FOUND\");\n require(unlock_time > block.timestamp, \"VE: UNLOCK_TIME_TOO_EARLY\");\n require(unlock_time <= block.timestamp + maxDuration, \"VE: UNLOCK_TIME_TOO_LATE\");\n\n _depositFor(msg.sender, _value, 0, unlock_time, _locked, CRETE_LOCK_TYPE);\n }\n\n /**\n * @notice Deposit `_value` additional tokens for `msg.sender`\n * without modifying the unlock time\n * @param _addr User's wallet address\n * @param _value Amount of tokens to deposit and add to the lock\n * @param _discount Amount to get discounted out of _value\n */\n function increaseAmountFor(\n address _addr,\n uint256 _value,\n uint256 _discount\n ) external nonReentrant {\n LockedBalance memory _locked = locked[_addr];\n\n require(_value > 0, \"VE: INVALID_VALUE\");\n require(_value >= _discount, \"VE: DISCOUNT_TOO_HIGH\");\n require(_locked.amount > 0, \"VE: LOCK_NOT_FOUND\");\n require(_locked.end > block.timestamp, \"VE: LOCK_EXPIRED\");\n\n _depositFor(_addr, _value, _discount, 0, _locked, INCREASE_LOCK_AMOUNT);\n }\n\n /**\n * @notice Deposit `_value` additional tokens for `msg.sender`\n * without modifying the unlock time\n * @param _value Amount of tokens to deposit and add to the lock\n */\n function increaseAmount(uint256 _value) external nonReentrant {\n LockedBalance memory _locked = locked[msg.sender];\n\n require(_value > 0, \"VE: INVALID_VALUE\");\n require(_locked.amount > 0, \"VE: LOCK_NOT_FOUND\");\n require(_locked.end > block.timestamp, \"VE: LOCK_EXPIRED\");\n\n _depositFor(msg.sender, _value, 0, 0, _locked, INCREASE_LOCK_AMOUNT);\n }\n\n /**\n * @notice Extend the unlock time for `msg.sender` to `_duration`\n * @param _duration Increased epoch time for unlocking\n */\n function increaseUnlockTime(uint256 _duration) external nonReentrant {\n LockedBalance memory _locked = locked[msg.sender];\n uint256 unlock_time = ((_locked.end + _duration) / interval) * interval; // Locktime is rounded down to a multiple of interval\n\n require(_locked.end > block.timestamp, \"VE: LOCK_EXPIRED\");\n require(_locked.amount > 0, \"VE: LOCK_NOT_FOUND\");\n require(_locked.discount == 0, \"VE: LOCK_DISCOUNTED\");\n require(unlock_time >= _locked.end + interval, \"VE: UNLOCK_TIME_TOO_EARLY\");\n require(unlock_time <= block.timestamp + maxDuration, \"VE: UNLOCK_TIME_TOO_LATE\");\n\n _depositFor(msg.sender, 0, 0, unlock_time, _locked, INCREASE_UNLOCK_TIME);\n }\n\n /**\n * @notice Withdraw all tokens for `msg.sender`\n * @dev Only possible if the lock has expired\n */\n function withdraw() external nonReentrant {\n LockedBalance memory _locked = locked[msg.sender];\n require(block.timestamp >= _locked.end, \"VE: LOCK_NOT_EXPIRED\");\n\n uint256 supply_before = _clear(_locked);\n\n uint256 value = _locked.amount.toUint256();\n uint256 discount = _locked.discount.toUint256();\n\n if (value > discount) {\n IERC20(token).safeTransfer(msg.sender, value - discount);\n }\n\n emit Withdraw(msg.sender, value, discount, block.timestamp);\n emit Supply(supply_before, supply_before - value);\n }\n\n function _clear(LockedBalance memory _locked) internal returns (uint256 supply_before) {\n uint256 value = _locked.amount.toUint256();\n\n locked[msg.sender] = LockedBalance(0, 0, 0, 0);\n supply_before = supply;\n supply = supply_before - value;\n\n // old_locked can have either expired <= timestamp or zero end\n // _locked has only 0 end\n // Both can have >= 0 amount\n _checkpoint(msg.sender, _locked, LockedBalance(0, 0, 0, 0));\n }\n\n // The following ERC20/minime-compatible methods are not real balanceOf and supply!\n // They measure the weights for the purpose of voting, so they don't represent\n // real coins.\n\n /**\n * @notice Binary search to estimate timestamp for block number\n * @param _block Block to find\n * @param max_epoch Don't go beyond this epoch\n * @return Approximate timestamp for block\n */\n function _findBlockEpoch(uint256 _block, uint256 max_epoch) internal view returns (uint256) {\n uint256 _min;\n uint256 _max = max_epoch;\n for (uint256 i; i < 128; i++) {\n if (_min >= _max) break;\n uint256 _mid = (_min + _max + 1) / 2;\n if (pointHistory[_mid].blk <= _block) _min = _mid;\n else _max = _mid - 1;\n }\n return _min;\n }\n\n function balanceOf(address addr) public view returns (uint256) {\n return balanceOf(addr, block.timestamp);\n }\n\n /**\n * @notice Get the current voting power for `msg.sender`\n * @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility\n * @param addr User wallet address\n * @param _t Epoch time to return voting power at\n * @return User voting power\n */\n function balanceOf(address addr, uint256 _t) public view returns (uint256) {\n uint256 _epoch = userPointEpoch[addr];\n if (_epoch == 0) return 0;\n else {\n Point memory last_point = userPointHistory[addr][_epoch];\n last_point.bias -= last_point.slope * (_t - last_point.ts).toInt128();\n if (last_point.bias < 0) last_point.bias = 0;\n return last_point.bias.toUint256();\n }\n }\n\n /**\n * @notice Measure voting power of `addr` at block height `_block`\n * @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime\n * @param addr User's wallet address\n * @param _block Block to calculate the voting power at\n * @return Voting power\n */\n function balanceOfAt(address addr, uint256 _block) external view returns (uint256) {\n // Copying and pasting totalSupply code because Vyper cannot pass by\n // reference yet\n require(_block <= block.number);\n\n // Binary search\n uint256 _min;\n uint256 _max = userPointEpoch[addr];\n for (uint256 i; i < 128; i++) {\n if (_min >= _max) break;\n uint256 _mid = (_min + _max + 1) / 2;\n if (userPointHistory[addr][_mid].blk <= _block) _min = _mid;\n else _max = _mid - 1;\n }\n\n Point memory upoint = userPointHistory[addr][_min];\n\n uint256 max_epoch = epoch;\n uint256 _epoch = _findBlockEpoch(_block, max_epoch);\n Point memory point_0 = pointHistory[_epoch];\n uint256 d_block;\n uint256 d_t;\n if (_epoch < max_epoch) {\n Point memory point_1 = pointHistory[_epoch + 1];\n d_block = point_1.blk - point_0.blk;\n d_t = point_1.ts - point_0.ts;\n } else {\n d_block = block.number - point_0.blk;\n d_t = block.timestamp - point_0.ts;\n }\n uint256 block_time = point_0.ts;\n if (d_block != 0) block_time += ((d_t * (_block - point_0.blk)) / d_block);\n\n upoint.bias -= upoint.slope * (block_time - upoint.ts).toInt128();\n if (upoint.bias >= 0) return upoint.bias.toUint256();\n else return 0;\n }\n\n /**\n * @notice Calculate total voting power at some point in the past\n * @param point The point (bias/slope) to start search from\n * @param t Time to calculate the total voting power at\n * @return Total voting power at that time\n */\n function _supplyAt(Point memory point, uint256 t) internal view returns (uint256) {\n Point memory last_point = point;\n uint256 t_i = (last_point.ts / interval) * interval;\n for (uint256 i; i < 255; i++) {\n t_i += interval;\n int128 d_slope;\n if (t_i > t) t_i = t;\n else d_slope = slopeChanges[t_i];\n last_point.bias -= last_point.slope * (t_i - last_point.ts).toInt128();\n if (t_i == t) break;\n last_point.slope += d_slope;\n last_point.ts = t_i;\n }\n\n if (last_point.bias < 0) last_point.bias = 0;\n return last_point.bias.toUint256();\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply(block.timestamp);\n }\n\n /**\n * @notice Calculate total voting power\n * @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility\n * @return Total voting power\n */\n function totalSupply(uint256 t) public view returns (uint256) {\n uint256 _epoch = epoch;\n Point memory last_point = pointHistory[_epoch];\n return _supplyAt(last_point, t);\n }\n\n /**\n * @notice Calculate total voting power at some point in the past\n * @param _block Block to calculate the total voting power at\n * @return Total voting power at `_block`\n */\n function totalSupplyAt(uint256 _block) external view returns (uint256) {\n require(_block <= block.number);\n uint256 _epoch = epoch;\n uint256 target_epoch = _findBlockEpoch(_block, _epoch);\n\n Point memory point = pointHistory[target_epoch];\n uint256 dt;\n if (target_epoch < _epoch) {\n Point memory point_next = pointHistory[target_epoch + 1];\n if (point.blk != point_next.blk)\n dt = ((_block - point.blk) * (point_next.ts - point.ts)) / (point_next.blk - point.blk);\n } else if (point.blk != block.number)\n dt = ((_block - point.blk) * (block.timestamp - point.ts)) / (block.number - point.blk);\n // Now dt contains info on how far are we beyond point\n\n return _supplyAt(point, point.ts + dt);\n }\n}\n"
},
"contracts/mocks/libraries/Integers.sol": {
"content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.17;\n\nlibrary Integers {\n error OutOfRange();\n\n function toInt128(uint256 u) internal pure returns (int128) {\n revertIfOutOfRange(u <= uint256(uint128(type(int128).max)));\n return int128(int256(u));\n }\n\n function toUint192(uint256 u) internal pure returns (uint192) {\n revertIfOutOfRange(u <= uint256(type(uint192).max));\n return uint192(u);\n }\n\n function toUint256(int128 i) internal pure returns (uint256) {\n revertIfOutOfRange(i >= 0);\n return uint256(uint128(i));\n }\n\n function revertIfOutOfRange(bool success) internal pure {\n if (!success) revert OutOfRange();\n }\n}\n"
},
"@openzeppelin/contracts/security/ReentrancyGuard.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\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 ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
},
"@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC20.sol\";\nimport \"../utils/SafeERC20.sol\";\nimport \"../../../interfaces/IERC4626.sol\";\nimport \"../../../utils/math/Math.sol\";\n\n/**\n * @dev Implementation of the ERC4626 \"Tokenized Vault Standard\" as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626].\n *\n * This extension allows the minting and burning of \"shares\" (represented using the ERC20 inheritance) in exchange for\n * underlying \"assets\" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends\n * the ERC20 standard. Any additional extensions included along it would affect the \"shares\" token represented by this\n * contract and not the \"assets\" token which is an independent contract.\n *\n * CAUTION: Deposits and withdrawals may incur unexpected slippage. Users should verify that the amount received of\n * shares or assets is as expected. EOAs should operate through a wrapper that performs these checks such as\n * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].\n *\n * _Available since v4.7._\n */\nabstract contract ERC4626 is ERC20, IERC4626 {\n using Math for uint256;\n\n IERC20 private immutable _asset;\n uint8 private immutable _decimals;\n\n /**\n * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).\n */\n constructor(IERC20 asset_) {\n (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_);\n _decimals = success ? assetDecimals : super.decimals();\n _asset = asset_;\n }\n\n /**\n * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way.\n */\n function _tryGetAssetDecimals(IERC20 asset_) private returns (bool, uint8) {\n (bool success, bytes memory encodedDecimals) = address(asset_).call(\n abi.encodeWithSelector(IERC20Metadata.decimals.selector)\n );\n if (success && encodedDecimals.length >= 32) {\n uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));\n if (returnedDecimals <= type(uint8).max) {\n return (true, uint8(returnedDecimals));\n }\n }\n return (false, 0);\n }\n\n /**\n * @dev Decimals are read from the underlying asset in the constructor and cached. If this fails (e.g., the asset\n * has not been created yet), the cached value is set to a default obtained by `super.decimals()` (which depends on\n * inheritance but is most likely 18). Override this function in order to set a guaranteed hardcoded value.\n * See {IERC20Metadata-decimals}.\n */\n function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) {\n return _decimals;\n }\n\n /** @dev See {IERC4626-asset}. */\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /** @dev See {IERC4626-totalAssets}. */\n function totalAssets() public view virtual override returns (uint256) {\n return _asset.balanceOf(address(this));\n }\n\n /** @dev See {IERC4626-convertToShares}. */\n function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {\n return _convertToShares(assets, Math.Rounding.Down);\n }\n\n /** @dev See {IERC4626-convertToAssets}. */\n function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {\n return _convertToAssets(shares, Math.Rounding.Down);\n }\n\n /** @dev See {IERC4626-maxDeposit}. */\n function maxDeposit(address) public view virtual override returns (uint256) {\n return _isVaultCollateralized() ? type(uint256).max : 0;\n }\n\n /** @dev See {IERC4626-maxMint}. */\n function maxMint(address) public view virtual override returns (uint256) {\n return type(uint256).max;\n }\n\n /** @dev See {IERC4626-maxWithdraw}. */\n function maxWithdraw(address owner) public view virtual override returns (uint256) {\n return _convertToAssets(balanceOf(owner), Math.Rounding.Down);\n }\n\n /** @dev See {IERC4626-maxRedeem}. */\n function maxRedeem(address owner) public view virtual override returns (uint256) {\n return balanceOf(owner);\n }\n\n /** @dev See {IERC4626-previewDeposit}. */\n function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n return _convertToShares(assets, Math.Rounding.Down);\n }\n\n /** @dev See {IERC4626-previewMint}. */\n function previewMint(uint256 shares) public view virtual override returns (uint256) {\n return _convertToAssets(shares, Math.Rounding.Up);\n }\n\n /** @dev See {IERC4626-previewWithdraw}. */\n function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n return _convertToShares(assets, Math.Rounding.Up);\n }\n\n /** @dev See {IERC4626-previewRedeem}. */\n function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n return _convertToAssets(shares, Math.Rounding.Down);\n }\n\n /** @dev See {IERC4626-deposit}. */\n function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n require(assets <= maxDeposit(receiver), \"ERC4626: deposit more than max\");\n\n uint256 shares = previewDeposit(assets);\n _deposit(_msgSender(), receiver, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4626-mint}. */\n function mint(uint256 shares, address receiver) public virtual override returns (uint256) {\n require(shares <= maxMint(receiver), \"ERC4626: mint more than max\");\n\n uint256 assets = previewMint(shares);\n _deposit(_msgSender(), receiver, assets, shares);\n\n return assets;\n }\n\n /** @dev See {IERC4626-withdraw}. */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more than max\");\n\n uint256 shares = previewWithdraw(assets);\n _withdraw(_msgSender(), receiver, owner, assets, shares);\n\n return shares;\n }\n\n /** @dev See {IERC4626-redeem}. */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) public virtual override returns (uint256) {\n require(shares <= maxRedeem(owner), \"ERC4626: redeem more than max\");\n\n uint256 assets = previewRedeem(shares);\n _withdraw(_msgSender(), receiver, owner, assets, shares);\n\n return assets;\n }\n\n /**\n * @dev Internal conversion function (from assets to shares) with support for rounding direction.\n *\n * Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset\n * would represent an infinite amount of shares.\n */\n function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256 shares) {\n uint256 supply = totalSupply();\n return\n (assets == 0 || supply == 0)\n ? _initialConvertToShares(assets, rounding)\n : assets.mulDiv(supply, totalAssets(), rounding);\n }\n\n /**\n * @dev Internal conversion function (from assets to shares) to apply when the vault is empty.\n *\n * NOTE: Make sure to keep this function consistent with {_initialConvertToAssets} when overriding it.\n */\n function _initialConvertToShares(\n uint256 assets,\n Math.Rounding /*rounding*/\n ) internal view virtual returns (uint256 shares) {\n return assets;\n }\n\n /**\n * @dev Internal conversion function (from shares to assets) with support for rounding direction.\n */\n function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256 assets) {\n uint256 supply = totalSupply();\n return\n (supply == 0) ? _initialConvertToAssets(shares, rounding) : shares.mulDiv(totalAssets(), supply, rounding);\n }\n\n /**\n * @dev Internal conversion function (from shares to assets) to apply when the vault is empty.\n *\n * NOTE: Make sure to keep this function consistent with {_initialConvertToShares} when overriding it.\n */\n function _initialConvertToAssets(\n uint256 shares,\n Math.Rounding /*rounding*/\n ) internal view virtual returns (uint256 assets) {\n return shares;\n }\n\n /**\n * @dev Deposit/mint common workflow.\n */\n function _deposit(\n address caller,\n address receiver,\n uint256 assets,\n uint256 shares\n ) internal virtual {\n // If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the\n // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,\n // calls the vault, which is assumed not malicious.\n //\n // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the\n // assets are transferred and before the shares are minted, which is a valid state.\n // slither-disable-next-line reentrancy-no-eth\n SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n }\n\n /**\n * @dev Withdraw/redeem common workflow.\n */\n function _withdraw(\n address caller,\n address receiver,\n address owner,\n uint256 assets,\n uint256 shares\n ) internal virtual {\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the\n // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,\n // calls the vault, which is assumed not malicious.\n //\n // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the\n // shares are burned and after the assets are transferred, which is a valid state.\n _burn(owner, shares);\n SafeERC20.safeTransfer(_asset, receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n }\n\n function _isVaultCollateralized() private view returns (bool) {\n return totalAssets() > 0 || totalSupply() == 0;\n }\n}\n"
},
"@openzeppelin/contracts/interfaces/IERC4626.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20.sol\";\nimport \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n *\n * _Available since v4.7._\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed sender,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n}\n"
},
"@openzeppelin/contracts/utils/cryptography/EIP712.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n /* solhint-disable var-name-mixedcase */\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n uint256 private immutable _CACHED_CHAIN_ID;\n address private immutable _CACHED_THIS;\n\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/cryptography/EIP712.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n using Counters for Counters.Counter;\n\n mapping(address => Counters.Counter) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private constant _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n /**\n * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\n * However, to ensure consistency with the upgradeable transpiler, we will continue\n * to reserve a slot.\n * @custom:oz-renamed-from _PERMIT_TYPEHASH\n */\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n constructor(string memory name) EIP712(name, \"1\") {}\n\n /**\n * @dev See {IERC20Permit-permit}.\n */\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 override {\n require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n require(signer == owner, \"ERC20Permit: invalid signature\");\n\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view virtual override returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev \"Consume a nonce\": return the current value and increment.\n *\n * _Available since v4.1._\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n}\n"
},
"contracts/mocks/FlashFToken.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol\";\n\ncontract FlashFToken is ERC20, ERC20Burnable, ERC20Permit, Ownable {\n constructor(string memory _tokenName, string memory _tokenSymbol)\n ERC20(_tokenName, _tokenSymbol)\n ERC20Permit(_tokenName)\n {}\n\n function mint(address to, uint256 amount) public onlyOwner {\n _mint(to, amount);\n }\n}\n"
},
"contracts/mocks/FlashFTokenFactory.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"../interfaces/IFlashFTokenFactory.sol\";\nimport \"./FlashFToken.sol\";\n\ncontract FlashFTokenFactory is Ownable, IFlashFTokenFactory {\n event FTokenCreated(address _tokenAddress);\n\n constructor() {}\n\n function createFToken(string calldata _fTokenName, string calldata _fTokenSymbol)\n external\n onlyOwner\n returns (address)\n {\n FlashFToken flashFToken = new FlashFToken(_fTokenName, _fTokenSymbol);\n flashFToken.transferOwnership(msg.sender);\n\n emit FTokenCreated(address(flashFToken));\n return address(flashFToken);\n }\n}\n"
},
"contracts/interfaces/IFlashFTokenFactory.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IFlashFTokenFactory {\n function createFToken(string calldata _fTokenName, string calldata _fTokenSymbol) external returns (address);\n}\n"
},
"contracts/mocks/FlashProtocol.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"../interfaces/IFlashStrategy.sol\";\nimport \"../interfaces/IFlashFToken.sol\";\nimport \"../interfaces/IFlashNFT.sol\";\nimport \"../interfaces/IFlashFTokenFactory.sol\";\n\ncontract FlashProtocol is Ownable, ReentrancyGuard {\n using SafeERC20 for IERC20;\n\n address public immutable flashNFTAddress;\n address immutable flashFTokenFactoryAddress;\n\n // Define the structure for each strategy\n struct StrategyInformation {\n address fTokenAddress;\n address principalTokenAddress;\n }\n mapping(address => StrategyInformation) strategies;\n\n // This will store the NFT ID to StakeID mapping\n mapping(uint256 => uint256) nftIdMappingsToStakeIds;\n\n // This will store how many stakes we have\n uint256 stakeCount = 0;\n\n // The global fToken mint fee\n uint96 globalMintFee = 0;\n address globalMintFeeRecipient = 0x5089722613C2cCEe071C39C59e9889641f435F15;\n\n // This defines the structure of the Stake information we store\n struct StakeStruct {\n address stakerAddress; // Address of staker\n address strategyAddress; // Address of strategy being used\n uint256 stakeStartTs; // Unix timestamp of when stake started\n uint256 stakeDuration; // Time in seconds from start time until stake ends\n uint256 stakedAmount; // The amount of tokens staked\n bool active; // Stake has been removed/unstaked\n uint256 nftId; // NFT id if set\n uint256 fTokensToUser; // How many fERC20 tokens were minted\n uint256 fTokensFee; // How many fERC20 tokens were taken as fee\n uint256 totalFTokenBurned;\n uint256 totalStakedWithdrawn;\n }\n mapping(uint256 => StakeStruct) stakes;\n\n // Define events\n event StrategyRegistered(\n address indexed _strategyAddress,\n address indexed _principalTokenAddress,\n address indexed _fTokenAddress\n );\n event Staked(uint256 _stakeId);\n event Unstaked(uint256 _stakeId, uint256 _tokensReturned, uint256 _fTokensBurned, bool _stakeFinished);\n event NFTIssued(uint256 _stakeId, uint256 nftId);\n\n constructor(address _flashNFTAddress, address _flashFTokenFactoryAddress) {\n flashNFTAddress = _flashNFTAddress;\n flashFTokenFactoryAddress = _flashFTokenFactoryAddress;\n }\n\n function registerStrategy(\n address _strategyAddress,\n address _principalTokenAddress,\n string calldata _fTokenName,\n string calldata _fTokenSymbol\n ) external {\n require(\n strategies[_strategyAddress].principalTokenAddress == address(0) &&\n _strategyAddress != address(0) &&\n _principalTokenAddress != address(0)\n );\n\n address flashFToken = IFlashFTokenFactory(flashFTokenFactoryAddress).createFToken(_fTokenName, _fTokenSymbol);\n\n // Store the appropriate information\n strategies[_strategyAddress].fTokenAddress = flashFToken;\n strategies[_strategyAddress].principalTokenAddress = _principalTokenAddress;\n\n IFlashStrategy(_strategyAddress).setFTokenAddress(flashFToken);\n\n emit StrategyRegistered(_strategyAddress, _principalTokenAddress, flashFToken);\n }\n\n function stake(\n address _strategyAddress,\n uint256 _tokenAmount,\n uint256 _stakeDuration,\n address _fTokensTo,\n bool _issueNFT\n ) public nonReentrant returns (StakeStruct memory _stake) {\n require(strategies[_strategyAddress].principalTokenAddress != address(0));\n require(\n _stakeDuration >= 60 && _stakeDuration <= IFlashStrategy(_strategyAddress).getMaxStakeDuration(),\n \"ISD\"\n );\n\n // Transfer the tokens from caller to the strategy contract\n IERC20(strategies[_strategyAddress].principalTokenAddress).safeTransferFrom(\n msg.sender,\n address(_strategyAddress),\n _tokenAmount\n );\n\n // Determine how many fERC20 tokens to mint (ask strategy)\n uint256 tokensToMint = IFlashStrategy(_strategyAddress).quoteMintFToken(_tokenAmount, _stakeDuration);\n\n // Deposit into the strategy\n uint256 principalAfterDeductions = IFlashStrategy(_strategyAddress).depositPrincipal(_tokenAmount);\n\n // Calculate fee and if this is more than 0, transfer fee\n uint256 fee = (tokensToMint * globalMintFee) / 10000;\n if (fee > 0) {\n IFlashFToken(strategies[_strategyAddress].fTokenAddress).mint(globalMintFeeRecipient, fee);\n }\n\n // Mint fERC20 tokens to the user\n IFlashFToken(strategies[_strategyAddress].fTokenAddress).mint(_fTokensTo, (tokensToMint - fee));\n\n // Save the stake details\n stakeCount = stakeCount + 1;\n stakes[stakeCount] = StakeStruct(\n msg.sender,\n _strategyAddress,\n block.timestamp,\n _stakeDuration,\n principalAfterDeductions,\n true,\n 0,\n (tokensToMint - fee),\n fee,\n 0,\n 0\n );\n\n // Mint NFT if requested\n if (_issueNFT) {\n issueNFT(stakeCount);\n }\n\n emit Staked(stakeCount);\n\n return stakes[stakeCount];\n }\n\n function unstake(\n uint256 _id,\n bool _isNFT,\n uint256 _fTokenToBurn\n ) external nonReentrant returns (uint256 _principalReturned, uint256 _fTokensBurned) {\n StakeStruct memory p;\n uint256 stakeId;\n address returnAddress;\n if (_isNFT) {\n stakeId = nftIdMappingsToStakeIds[_id];\n p = stakes[stakeId];\n returnAddress = msg.sender;\n require(p.nftId == _id, \"SNM\");\n require(IFlashNFT(flashNFTAddress).ownerOf(_id) == msg.sender, \"NNO\");\n } else {\n stakeId = _id;\n p = stakes[stakeId];\n returnAddress = p.stakerAddress;\n\n require(p.nftId == 0, \"NTR\");\n require(p.stakerAddress == msg.sender, \"NSO\");\n }\n require(p.active == true, \"SNE\");\n\n bool stakeFinished;\n uint256 principalToReturn;\n uint256 percentageIntoStake = (((block.timestamp - p.stakeStartTs) * (10**18)) / p.stakeDuration);\n\n if (percentageIntoStake >= (10**18)) {\n // Stake has ended, simply return principal\n principalToReturn = p.stakedAmount - p.totalStakedWithdrawn;\n _fTokenToBurn = 0;\n\n stakeFinished = true;\n } else {\n require(block.timestamp >= (p.stakeStartTs + 3600), \"MIN DUR 1HR\");\n\n // Stake has not ended yet, user is trying to withdraw early\n uint256 fTokenBurnForFullUnstake = ((((10**18) - percentageIntoStake) * (p.fTokensToUser + p.fTokensFee)) /\n (10**18));\n\n if (p.totalFTokenBurned > fTokenBurnForFullUnstake) {\n // The total number of fTokens burned is greater than the amount required, no burn required\n fTokenBurnForFullUnstake = 0;\n } else {\n fTokenBurnForFullUnstake = fTokenBurnForFullUnstake - p.totalFTokenBurned;\n }\n\n // Ensure the user cannot burn more fTokens than required\n if (_fTokenToBurn > fTokenBurnForFullUnstake) {\n _fTokenToBurn = fTokenBurnForFullUnstake;\n }\n\n // Is the user trying to withdraw everything early?\n if (_fTokenToBurn == fTokenBurnForFullUnstake) {\n // Yes, return all principal\n principalToReturn = p.stakedAmount - p.totalStakedWithdrawn;\n stakeFinished = true;\n } else {\n // No - only a partial withdraw\n principalToReturn =\n (((_fTokenToBurn * (10**18)) / (p.fTokensToUser + p.fTokensFee)) * p.stakedAmount) /\n (10**18);\n }\n\n // Burn these fTokens\n IFlashFToken(strategies[p.strategyAddress].fTokenAddress).burnFrom(msg.sender, _fTokenToBurn);\n\n // Update stake information\n stakes[stakeId].totalFTokenBurned = p.totalFTokenBurned + _fTokenToBurn;\n stakes[stakeId].totalStakedWithdrawn = p.totalStakedWithdrawn + principalToReturn;\n }\n require(principalToReturn > 0);\n require(p.stakedAmount >= stakes[stakeId].totalStakedWithdrawn);\n\n // if the stake is finished, delete all data related to it (nice to have)\n if (stakeFinished) {\n delete stakes[stakeId];\n }\n // if the stake finished and it was NFT based, remove the mapping (nice to have)\n if (stakeFinished && _isNFT) {\n delete nftIdMappingsToStakeIds[_id];\n }\n emit Unstaked(stakeId, principalToReturn, _fTokenToBurn, stakeFinished);\n\n // Remove tokens from Strategy and transfer to user\n IFlashStrategy(p.strategyAddress).withdrawPrincipal(principalToReturn);\n IERC20(strategies[p.strategyAddress].principalTokenAddress).safeTransfer(returnAddress, principalToReturn);\n\n return (principalToReturn, _fTokenToBurn);\n }\n\n function issueNFT(uint256 _stakeId) public returns (uint256 _nftId) {\n StakeStruct memory p = stakes[_stakeId];\n require(p.active == true && p.nftId == 0 && p.stakerAddress == msg.sender);\n\n // Mint the NFT\n uint256 nftId = IFlashNFT(flashNFTAddress).mint(msg.sender);\n\n // Store the NFT ID\n stakes[_stakeId].nftId = nftId;\n\n // Update the NFT Mapping so we can look it up later\n nftIdMappingsToStakeIds[nftId] = _stakeId;\n\n emit NFTIssued(_stakeId, nftId);\n\n return nftId;\n }\n\n function setMintFeeInfo(address _feeRecipient, uint96 _feePercentageBasis) external onlyOwner {\n require(_feePercentageBasis <= 2000);\n globalMintFeeRecipient = _feeRecipient;\n globalMintFee = _feePercentageBasis;\n }\n\n function getStakeInfo(uint256 _id, bool _isNFT) external view returns (StakeStruct memory _stake) {\n uint256 stakeId;\n if (_isNFT) {\n stakeId = nftIdMappingsToStakeIds[_id];\n require(stakes[stakeId].nftId == _id);\n } else {\n stakeId = _id;\n }\n\n return stakes[stakeId];\n }\n\n function flashStake(\n address _strategyAddress,\n uint256 _tokenAmount,\n uint256 _stakeDuration,\n uint256 _minimumReceived,\n address _yieldTo,\n bool _mintNFT\n ) external {\n // Stake (re-direct fTokens to this contract)\n uint256 fTokensToUser = stake(_strategyAddress, _tokenAmount, _stakeDuration, address(this), _mintNFT)\n .fTokensToUser;\n\n IERC20 fToken = IERC20(strategies[_strategyAddress].fTokenAddress);\n\n // Approve, burn and send yield to specified address\n fToken.approve(_strategyAddress, fTokensToUser);\n IFlashStrategy(_strategyAddress).burnFToken(fTokensToUser, _minimumReceived, _yieldTo);\n }\n}\n"
},
"contracts/interfaces/IFlashStrategy.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IFlashStrategy {\n event BurnedFToken(address indexed _address, uint256 _tokenAmount, uint256 _yieldReturned);\n\n // This is how principal will be deposited into the contract\n // The Flash protocol allows the strategy to specify how much\n // should be registered. This allows the strategy to manipulate (eg take fee)\n // on the principal if the strategy requires\n function depositPrincipal(uint256 _tokenAmount) external returns (uint256);\n\n // This is how principal will be returned from the contract\n function withdrawPrincipal(uint256 _tokenAmount) external;\n\n // Responsible for instant upfront yield. Takes fERC20 tokens specific to this\n // strategy. The strategy is responsible for returning some amount of principal tokens\n function burnFToken(\n uint256 _tokenAmount,\n uint256 _minimumReturned,\n address _yieldTo\n ) external returns (uint256);\n\n // This should return the current total of all principal within the contract\n function getPrincipalBalance() external view returns (uint256);\n\n // This should return the current total of all yield generated to date (including bootstrapped tokens)\n function getYieldBalance() external view returns (uint256);\n\n // This should return the principal token address (eg DAI)\n function getPrincipalAddress() external view returns (address);\n\n // View function which quotes how many principal tokens would be returned if x\n // fERC20 tokens are burned\n function quoteMintFToken(uint256 _tokenAmount, uint256 duration) external view returns (uint256);\n\n // View function which quotes how many principal tokens would be returned if x\n // fERC20 tokens are burned\n // IMPORTANT NOTE: This should utilise bootstrap tokens if they exist\n // bootstrapped tokens are any principal tokens that exist within the smart contract\n function quoteBurnFToken(uint256 _tokenAmount) external view returns (uint256);\n\n // The function to set the fERC20 address within the strategy\n function setFTokenAddress(address _fTokenAddress) external;\n\n // This should return what the maximum stake duration is\n function getMaxStakeDuration() external view returns (uint256);\n}\n"
},
"contracts/interfaces/IFlashFToken.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IFlashFToken {\n function mint(address account, uint256 amount) external;\n\n function burnFrom(address from, uint256 amount) external;\n\n function decimals() external returns (uint8);\n}\n"
},
"contracts/interfaces/IFlashNFT.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IFlashNFT {\n function mint(address _recipientAddress) external returns (uint256);\n\n function burn(uint256 _tokenId) external returns (bool);\n\n function ownerOf(uint256 tokenId) external view returns (address);\n}\n"
},
"contracts/FlashStrategySushiSwap.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"./interfaces/IFlashStrategySushiSwap.sol\";\nimport \"./interfaces/IFlashStrategySushiSwapFactory.sol\";\nimport \"./interfaces/IFlashFToken.sol\";\nimport \"./interfaces/IFarmingLPToken.sol\";\nimport \"./interfaces/IERC20Receiver.sol\";\n\ncontract FlashStrategySushiSwap is Initializable, ReentrancyGuard, IFlashStrategySushiSwap {\n using SafeERC20 for IERC20;\n\n address public override factory;\n\n /**\n * @notice address of FlashProtocol\n */\n address public override flashProtocol;\n\n /**\n * @notice address of SUSHI token\n */\n address public override sushi;\n /**\n * @notice address of FarmingLPToken\n */\n address public override flpToken;\n\n uint256 internal _balancePrincipal;\n\n /**\n * @notice address of fERC20 for this strategy\n */\n address public override fToken;\n\n function initialize(address _flashProtocol, address _flpToken) external override initializer {\n if (_flashProtocol == address(0)) return;\n\n factory = msg.sender;\n flashProtocol = _flashProtocol;\n sushi = IFarmingLPToken(_flpToken).sushi();\n flpToken = _flpToken;\n }\n\n modifier onlyAuthorised() {\n if (msg.sender != flashProtocol && msg.sender != address(this)) revert Forbidden();\n _;\n }\n\n /**\n * @return amount of principal tokens that are currently deposited\n */\n function getPrincipalBalance() external view override returns (uint256) {\n return _balancePrincipal;\n }\n\n /**\n * @return amount of yield tokens that can be rewarded in SUSHI\n */\n function getYieldBalance() public view override returns (uint256) {\n return IFarmingLPToken(flpToken).withdrawableYieldOf(address(this));\n }\n\n /**\n * @return address of LP Token\n */\n function getPrincipalAddress() external view override returns (address) {\n return flpToken;\n }\n\n /**\n * @dev called by flashProtocol\n * @return amountFToken how many fTokens should be minted for a given _amount and _duration (in seconds)\n */\n function quoteMintFToken(uint256 _amount, uint256 _duration) external pure override returns (uint256 amountFToken) {\n // 1 fToken per 1 year\n uint256 amountToMint = (_amount * _duration) / 365 days;\n\n if (amountToMint == 0) revert AmountTooLow();\n\n return amountToMint;\n }\n\n /**\n * @return how many aLP rewards should be returned if _amount fERC20 tokens are burned\n */\n function quoteBurnFToken(uint256 _amount) public view override returns (uint256) {\n uint256 totalSupply = IERC20(fToken).totalSupply();\n if (totalSupply == 0) revert InsufficientTotalSupply();\n\n if (_amount > totalSupply) {\n _amount = totalSupply;\n }\n\n return (getYieldBalance() * _amount) / totalSupply;\n }\n\n function getMaxStakeDuration() public pure override returns (uint256) {\n return 104 weeks; // almost 2 years\n }\n\n /**\n * @dev called by flashProtocol\n */\n function setFTokenAddress(address _fTokenAddress) external override {\n if (msg.sender != flashProtocol) revert Forbidden();\n fToken = _fTokenAddress;\n }\n\n /**\n * @notice This function will be called whenever a user stakes via the Flash Protocol.\n * @dev The Strategy owner can choose to implement a fee but the resulting \"locked\" principal the user should expect\n * after the stake has ended must be returned.\n */\n function depositPrincipal(uint256 _amount) external override onlyAuthorised returns (uint256) {\n uint256 fee = _amount / 400; // charge 0.25%\n _transferFee(flpToken, fee);\n\n uint256 amount = _amount - fee;\n _balancePrincipal += amount;\n\n return amount;\n }\n\n /**\n * @notice This function should withdraw principal from the underlying strategy.\n */\n function withdrawPrincipal(uint256 _amount) external override onlyAuthorised {\n address _flpToken = flpToken;\n IFarmingLPToken(_flpToken).checkpoint();\n\n IERC20(_flpToken).safeTransfer(msg.sender, _amount);\n _balancePrincipal -= _amount;\n }\n\n /**\n * @notice This is the function the user will be calling when performing a FlashBurn.\n * @dev It is responsible for burning the fToken supplied by the user and returning yield to the user.\n */\n function burnFToken(\n uint256 _amount,\n uint256 _minimumReturned,\n address _yieldTo\n ) external override nonReentrant returns (uint256) {\n uint256 yield = quoteBurnFToken(_amount);\n if (yield == 0 || yield < _minimumReturned) revert InsufficientYield();\n\n IFlashFToken(fToken).burnFrom(msg.sender, _amount);\n\n address _flpToken = flpToken;\n IFarmingLPToken(_flpToken).withdraw(yield, address(this));\n\n address lpToken = IFarmingLPToken(_flpToken).lpToken();\n uint256 balanceLPToken = IERC20(lpToken).balanceOf(address(this));\n _transfer(lpToken, _yieldTo, balanceLPToken);\n\n address _sushi = sushi;\n uint256 balanceSushi = IERC20(_sushi).balanceOf(address(this));\n _transfer(_sushi, _yieldTo, balanceSushi);\n\n emit BurnedFToken(msg.sender, _amount, yield);\n\n return yield;\n }\n\n function _transfer(\n address token,\n address to,\n uint256 amount\n ) internal {\n uint256 fee = amount / 100; // charge 1%\n IERC20(token).safeTransfer(to, amount - fee);\n _transferFee(token, fee);\n }\n\n function _transferFee(address token, uint256 amount) internal {\n if (amount > 0) {\n address feeRecipient = IFlashStrategySushiSwapFactory(factory).feeRecipient();\n IERC20(token).safeTransfer(feeRecipient, amount);\n if (feeRecipient.code.length > 0) {\n try IERC20Receiver(feeRecipient).onReceiveERC20(token, address(this), amount) {} catch {}\n }\n }\n }\n}\n"
},
"contracts/interfaces/IFlashStrategySushiSwap.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\nimport \"./IFlashStrategy.sol\";\n\ninterface IFlashStrategySushiSwap is IFlashStrategy {\n error Forbidden();\n error InvalidVault();\n error AmountTooLow();\n error InsufficientYield();\n error InsufficientTotalSupply();\n\n function factory() external view returns (address);\n\n function flashProtocol() external view returns (address);\n\n function fToken() external view returns (address);\n\n function sushi() external view returns (address);\n\n function flpToken() external view returns (address);\n\n function initialize(address _flashProtocol, address _flpToken) external;\n}\n"
},
"contracts/interfaces/IFlashStrategySushiSwapFactory.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFlashStrategySushiSwapFactory {\n error InvalidFee();\n error InvalidFeeRecipient();\n error FlashStrategySushiSwapCreated();\n\n event UpdateStakeFeeBPS(uint256 fee);\n event UpdateFlashStakeFeeBPS(uint256 fee);\n event UpdateFeeRecipient(address feeRecipient);\n event CreateFlashStrategySushiSwap(uint256 pid, address strategy);\n\n function flashProtocol() external view returns (address);\n\n function flpTokenFactory() external view returns (address);\n\n function feeRecipient() external view returns (address);\n\n function getFlashStrategySushiSwap(uint256 pid) external view returns (address);\n\n function predictFlashStrategySushiSwapAddress(uint256 pid) external view returns (address strategy);\n\n function updateFeeRecipient(address _feeRecipient) external;\n\n function createFlashStrategySushiSwap(uint256 pid) external returns (address strategy);\n}\n"
},
"contracts/interfaces/IFarmingLPToken.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IFarmingLPToken is IERC20 {\n error InvalidPath();\n error InsufficientYield();\n error InsufficientAmount();\n error NoMigratorSet();\n\n event Deposit(uint256 shares, uint256 amountLP, address indexed beneficiary);\n event Withdraw(uint256 shares, uint256 amountLP, address indexed beneficiary);\n event EmergencyWithdraw(uint256 shares, uint256 amountLP, address indexed beneficiary);\n event ClaimSushi(uint256 shares, uint256 yield, address indexed beneficiary);\n event Migrate(uint256 shares, uint256 amountLP, address indexed beneficiary);\n event EmergencyMigrate(uint256 shares, uint256 amountLP, address indexed beneficiary);\n\n function initialize(\n address _router,\n address _masterChef,\n uint256 _pid\n ) external;\n\n function factory() external view returns (address);\n\n function router() external view returns (address);\n\n function masterChef() external view returns (address);\n\n function sushi() external view returns (address);\n\n function pid() external view returns (uint256);\n\n function lpToken() external view returns (address);\n\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function withdrawableTotalLPs() external view returns (uint256);\n\n function withdrawableLPsOf(address account) external view returns (uint256);\n\n function withdrawableTotalYield() external view returns (uint256);\n\n function withdrawableYieldOf(address account) external view returns (uint256);\n\n function totalShares() external view returns (uint256);\n\n function sharesOf(address account) external view returns (uint256);\n\n function approveMax() external;\n\n function depositSigned(\n uint256 amountLP,\n address[] calldata path0,\n address[] calldata path1,\n uint256 amountMin,\n address beneficiary,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n function deposit(\n uint256 amountLP,\n address[] calldata path0,\n address[] calldata path1,\n uint256 amountMin,\n address beneficiary,\n uint256 deadline\n ) external;\n\n function depositWithSushi(\n uint256 amount,\n address[] calldata path0,\n address[] calldata path1,\n uint256 amountLPMin,\n address beneficiary,\n uint256 deadline\n ) external;\n\n function withdraw(uint256 shares, address beneficiary) external;\n\n function emergencyWithdraw(address beneficiary) external;\n\n function migrate(address beneficiary, bytes calldata params) external;\n\n function emergencyMigrate(address beneficiary, bytes calldata params) external;\n\n function checkpoint() external;\n}\n"
},
"contracts/interfaces/IERC20Receiver.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IERC20Receiver {\n function onReceiveERC20(\n address token,\n address from,\n uint256 amount\n ) external;\n}\n"
},
"@openzeppelin/contracts/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/Address.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Internal function that returns the initialized version. Returns `_initialized`\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Internal function that returns the initialized version. Returns `_initializing`\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n"
},
"contracts/FlashStrategySushiSwapFactory.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/proxy/Clones.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"./interfaces/IFarmingLPTokenFactory.sol\";\nimport \"./interfaces/IFlashStrategySushiSwapFactory.sol\";\nimport \"./FlashStrategySushiSwap.sol\";\n\ninterface IFlashProtocol {\n function registerStrategy(\n address _strategyAddress,\n address _principalTokenAddress,\n string calldata _fTokenName,\n string calldata _fTokenSymbol\n ) external;\n}\n\ncontract FlashStrategySushiSwapFactory is Ownable, IFlashStrategySushiSwapFactory {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @notice address of FlashProtocol\n */\n address public immutable override flashProtocol;\n /**\n * @notice address of FarmingLPTokenFactory\n */\n address public immutable override flpTokenFactory;\n\n address internal immutable _implementation;\n\n /**\n * @notice fee recipient\n */\n address public override feeRecipient;\n\n mapping(uint256 => address) public override getFlashStrategySushiSwap;\n\n constructor(\n address _flashProtocol,\n address _flpTokenFactory,\n address _feeRecipient\n ) {\n flashProtocol = _flashProtocol;\n flpTokenFactory = _flpTokenFactory;\n updateFeeRecipient(_feeRecipient);\n\n FlashStrategySushiSwap strategy = new FlashStrategySushiSwap();\n strategy.initialize(address(0), address(0));\n _implementation = address(strategy);\n }\n\n function predictFlashStrategySushiSwapAddress(uint256 pid) external view override returns (address token) {\n token = Clones.predictDeterministicAddress(_implementation, bytes32(pid));\n }\n\n function updateFeeRecipient(address _feeRecipient) public override onlyOwner {\n if (_feeRecipient == address(0)) revert InvalidFeeRecipient();\n\n feeRecipient = _feeRecipient;\n\n emit UpdateFeeRecipient(_feeRecipient);\n }\n\n function createFlashStrategySushiSwap(uint256 pid) external override returns (address strategy) {\n if (getFlashStrategySushiSwap[pid] != address(0)) revert FlashStrategySushiSwapCreated();\n\n address flpToken = IFarmingLPTokenFactory(flpTokenFactory).getFarmingLPToken(pid);\n if (flpToken == address(0)) flpToken = IFarmingLPTokenFactory(flpTokenFactory).createFarmingLPToken(pid);\n\n strategy = Clones.cloneDeterministic(_implementation, bytes32(pid));\n FlashStrategySushiSwap(strategy).initialize(flashProtocol, flpToken);\n\n getFlashStrategySushiSwap[pid] = strategy;\n\n string memory name = string.concat(\"fToken for \", IERC20Metadata(flpToken).name());\n string memory symbol = string.concat(\n \"f\",\n IERC20Metadata(flpToken).symbol(),\n \"-\",\n _toHexString(uint160(flpToken) >> 144, 4)\n );\n IFlashProtocol(flashProtocol).registerStrategy(strategy, flpToken, name, symbol);\n\n emit CreateFlashStrategySushiSwap(pid, strategy);\n }\n\n function _toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(length);\n for (uint256 i = 0; i < length; ) {\n buffer[length - i - 1] = _SYMBOLS[value & 0xf];\n value >>= 4;\n unchecked {\n ++i;\n }\n }\n return string(buffer);\n }\n}\n"
},
"contracts/interfaces/IFarmingLPTokenFactory.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFarmingLPTokenFactory {\n error InvalidAddress();\n error MigratorSet();\n error TokenCreated();\n\n event UpdateVault(address indexed vault);\n event UpdateMigrator(address indexed migrator);\n event CreateFarmingLPToken(uint256 indexed pid, address indexed token);\n\n function router() external view returns (address);\n\n function masterChef() external view returns (address);\n\n function yieldVault() external view returns (address);\n\n function migrator() external view returns (address);\n\n function getFarmingLPToken(uint256 pid) external view returns (address);\n\n function predictFarmingLPTokenAddress(uint256 pid) external view returns (address token);\n\n function updateYieldVault(address vault) external;\n\n function updateMigrator(address vault) external;\n\n function createFarmingLPToken(uint256 pid) external returns (address token);\n}\n"
},
"@openzeppelin/contracts/proxy/Clones.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n /// @solidity memory-safe-assembly\n assembly {\n // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n // of the `implementation` address with the bytecode before the address.\n mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n instance := create(0, 0x09, 0x37)\n }\n require(instance != address(0), \"ERC1167: create failed\");\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n /// @solidity memory-safe-assembly\n assembly {\n // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n // of the `implementation` address with the bytecode before the address.\n mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n instance := create2(0, 0x09, 0x37, salt)\n }\n require(instance != address(0), \"ERC1167: create2 failed\");\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n /// @solidity memory-safe-assembly\n assembly {\n let ptr := mload(0x40)\n mstore(add(ptr, 0x38), deployer)\n mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)\n mstore(add(ptr, 0x14), implementation)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)\n mstore(add(ptr, 0x58), salt)\n mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))\n predicted := keccak256(add(ptr, 0x43), 0x55)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(address implementation, bytes32 salt)\n internal\n view\n returns (address predicted)\n {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n}\n"
},
"contracts/SousChef.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/proxy/Clones.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport \"./interfaces/ISousChef.sol\";\nimport \"./interfaces/IFSushi.sol\";\nimport \"./interfaces/IFSushiRestaurant.sol\";\nimport \"./interfaces/IFlashStrategySushiSwapFactory.sol\";\nimport \"./interfaces/IFlashStrategySushiSwap.sol\";\nimport \"./FSushiBill.sol\";\n\ncontract SousChef is Ownable, ISousChef {\n using SafeERC20 for IERC20;\n using SafeCast for uint256;\n using SafeCast for int256;\n using DateUtils for uint256;\n\n uint256 internal constant BONUS_MULTIPLIER = 10;\n uint256 internal constant REWARDS_PER_WEEK = 3000e18;\n uint256 internal constant REWARDS_FOR_INITIAL_WEEKS = BONUS_MULTIPLIER * REWARDS_PER_WEEK;\n\n address public immutable override fSushi;\n address public immutable override flashStrategyFactory;\n uint256 public immutable override startWeek;\n\n address internal immutable _implementation;\n\n /**\n * @notice address of IFSushiRestaurant\n */\n address public override restaurant;\n\n /**\n * @notice address of IFSushiKitchen\n */\n address public override kitchen;\n\n mapping(uint256 => address) public override getBill;\n /**\n * @notice how much rewards to be minted at the week\n */\n mapping(uint256 => uint256) public override weeklyRewards; // week => amount\n /**\n * @notice weeklyRewards is guaranteed to be correct before this week (exclusive)\n */\n uint256 public override lastCheckpoint; // week\n\n constructor(\n address _fSushi,\n address _restaurant,\n address _kitchen,\n address _flashStrategyFactory\n ) {\n fSushi = _fSushi;\n restaurant = _restaurant;\n kitchen = _kitchen;\n flashStrategyFactory = _flashStrategyFactory;\n uint256 thisWeek = block.timestamp.toWeekNumber();\n startWeek = thisWeek;\n lastCheckpoint = thisWeek + 1;\n weeklyRewards[thisWeek] = REWARDS_FOR_INITIAL_WEEKS;\n\n FSushiBill bill = new FSushiBill();\n bill.initialize(0, address(0));\n _implementation = address(bill);\n }\n\n function predictBillAddress(uint256 pid) external view override returns (address bill) {\n bill = Clones.predictDeterministicAddress(_implementation, bytes32(pid));\n }\n\n function updateRestaurant(address _restaurant) external override onlyOwner {\n if (_restaurant == address(0)) revert InvalidRestaurant();\n\n restaurant = _restaurant;\n\n emit UpdateRestaurant(_restaurant);\n }\n\n function updateKitchen(address _kitchen) external override onlyOwner {\n if (_kitchen == address(0)) revert InvalidKitchen();\n\n kitchen = _kitchen;\n\n emit UpdateKitchen(_kitchen);\n }\n\n function createBill(uint256 pid) external override returns (address bill) {\n if (getBill[pid] != address(0)) revert BillCreated();\n\n address strategy = IFlashStrategySushiSwapFactory(flashStrategyFactory).getFlashStrategySushiSwap(pid);\n if (strategy == address(0))\n strategy = IFlashStrategySushiSwapFactory(flashStrategyFactory).createFlashStrategySushiSwap(pid);\n\n bill = Clones.cloneDeterministic(_implementation, bytes32(pid));\n FSushiBill(bill).initialize(pid, IFlashStrategySushiSwap(strategy).fToken());\n\n getBill[pid] = bill;\n\n emit CreateBill(pid, bill);\n }\n\n /**\n * @dev if this function doesn't get called for 512 weeks (around 9.8 years) this contract breaks\n */\n function checkpoint() external override {\n uint256 from = lastCheckpoint;\n uint256 until = block.timestamp.toWeekNumber() + 1;\n if (until <= from) return;\n\n for (uint256 i; i < 512; ) {\n uint256 week = from + i;\n if (until <= week) break;\n weeklyRewards[week] = _rewards(week);\n\n unchecked {\n ++i;\n }\n }\n lastCheckpoint = until;\n }\n\n function _rewards(uint256 week) internal returns (uint256) {\n if (week < startWeek + 2) return REWARDS_FOR_INITIAL_WEEKS;\n if (week == startWeek + 2) return REWARDS_PER_WEEK;\n\n uint256 totalSupply = IFSushi(fSushi).checkpointedTotalSupplyDuring(week - 1);\n uint256 lockedAssets = IFSushiRestaurant(restaurant).checkpointedTotalAssetsDuring(week - 1);\n\n uint256 rewards = (totalSupply == 0 || totalSupply < lockedAssets)\n ? 0\n : (REWARDS_PER_WEEK * (totalSupply - lockedAssets)) / totalSupply;\n\n // emission rate decreases 1% every week from week 3\n if (week - startWeek > 2) {\n rewards = (rewards * 99) / 100;\n }\n return rewards;\n }\n\n function mintFSushi(\n uint256 pid,\n address to,\n uint256 amount\n ) external override {\n if (getBill[pid] != msg.sender) revert Forbidden();\n\n IFSushi(fSushi).mint(to, amount);\n }\n}\n"
},
"contracts/interfaces/ISousChef.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface ISousChef {\n error BillCreated();\n error InvalidRestaurant();\n error InvalidKitchen();\n error Forbidden();\n\n event UpdateRestaurant(address indexed restaurant);\n event UpdateKitchen(address indexed kitchen);\n event CreateBill(uint256 indexed pid, address indexed bill);\n event Checkpoint();\n\n function fSushi() external view returns (address);\n\n function flashStrategyFactory() external view returns (address);\n\n function startWeek() external view returns (uint256);\n\n function restaurant() external view returns (address);\n\n function kitchen() external view returns (address);\n\n function getBill(uint256 pid) external view returns (address);\n\n function weeklyRewards(uint256 week) external view returns (uint256);\n\n function lastCheckpoint() external view returns (uint256);\n\n function predictBillAddress(uint256 pid) external view returns (address bill);\n\n function updateRestaurant(address _restaurant) external;\n\n function updateKitchen(address _kitchen) external;\n\n function createBill(uint256 pid) external returns (address strategy);\n\n function checkpoint() external;\n\n function mintFSushi(\n uint256 pid,\n address to,\n uint256 amount\n ) external;\n}\n"
},
"contracts/interfaces/IFSushiRestaurant.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFSushiRestaurant {\n function startWeek() external view returns (uint256);\n\n function totalAssets() external view returns (uint256);\n\n function totalAssetsDuring(uint256 week) external view returns (uint256);\n\n function lastCheckpoint() external view returns (uint256);\n\n function checkpointedTotalAssets() external returns (uint256);\n\n function checkpointedTotalAssetsDuring(uint256 week) external returns (uint256);\n\n function checkpoint() external;\n}\n"
},
"contracts/FSushiBill.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"./base/BaseERC20.sol\";\nimport \"./interfaces/IFSushiBill.sol\";\nimport \"./interfaces/ISousChef.sol\";\nimport \"./interfaces/IFSushiKitchen.sol\";\nimport \"./libraries/DateUtils.sol\";\n\ncontract FSushiBill is BaseERC20, IFSushiBill {\n using SafeERC20 for IERC20;\n using DateUtils for uint256;\n\n address public override sousChef;\n uint256 public override pid;\n address public override fToken;\n\n /**\n * @notice points = ∫W(t)dt, where W(t) is the total supply at the week\n */\n mapping(uint256 => uint256) public override points; // week => points\n /**\n * @notice points are guaranteed to be correct before this time's week start\n */\n uint256 public override lastCheckpoint; // timestamp\n\n /**\n * @notice userPoints = ∫w(t)dt, where a(t) is the balance of account at the week\n */\n mapping(address => mapping(uint256 => uint256)) public override userPoints; // account => week => points\n /**\n * @notice userPoints of account is guaranteed to be correct before this week\n */\n mapping(address => uint256) public override userLastCheckpoint; // account => timestamp\n /**\n * @notice how much rewards were claimed in total for account\n */\n mapping(address => uint256) public override claimedRewards; // account => amount\n /**\n * @notice in the next claim, rewards will be accumulated from this week\n */\n mapping(address => uint256) public override nextClaimableWeek; // account => week\n\n function initialize(uint256 _pid, address _fToken) external override initializer {\n if (_fToken == address(0)) return;\n\n BaseERC20_initialize(\n string.concat(\"Flash Sushi Bill for \", IERC20Metadata(_fToken).name()),\n string.concat(\"x\", IERC20Metadata(_fToken).symbol()),\n \"1\"\n );\n\n sousChef = msg.sender;\n pid = _pid;\n fToken = _fToken;\n }\n\n function deposit(uint256 amount, address beneficiary) external override {\n userCheckpoint(msg.sender);\n\n if (amount > 0) {\n IERC20(fToken).safeTransferFrom(msg.sender, address(this), amount);\n\n uint256 balance = _balanceOf[msg.sender] + amount;\n _balanceOf[msg.sender] = balance;\n uint256 totalSupply = _totalSupply + amount;\n _totalSupply = totalSupply;\n\n _mint(beneficiary, amount);\n }\n\n emit Deposit(msg.sender, amount, beneficiary);\n }\n\n function withdraw(uint256 amount, address beneficiary) external override {\n userCheckpoint(msg.sender);\n\n if (amount > 0) {\n uint256 balance = _balanceOf[msg.sender] - amount;\n _balanceOf[msg.sender] = balance;\n uint256 totalSupply = _totalSupply - amount;\n _totalSupply = totalSupply;\n\n _burn(msg.sender, amount);\n\n IERC20(fToken).safeTransfer(beneficiary, amount);\n }\n\n emit Withdraw(msg.sender, amount, beneficiary);\n }\n\n /**\n * @dev if this function doesn't get called for 512 weeks (around 9.8 years) this contract breaks\n */\n function checkpoint() public override {\n ISousChef(sousChef).checkpoint();\n\n uint256 prevCheckpoint = lastCheckpoint;\n _updatePoints(points, _totalSupply, prevCheckpoint);\n if (prevCheckpoint < block.timestamp) {\n lastCheckpoint = block.timestamp;\n }\n\n emit Checkpoint();\n }\n\n function userCheckpoint(address account) public override {\n checkpoint();\n\n uint256 prevCheckpoint = userLastCheckpoint[account];\n _updatePoints(userPoints[account], _balanceOf[account], prevCheckpoint);\n if (prevCheckpoint < block.timestamp) {\n userLastCheckpoint[account] = block.timestamp;\n }\n\n emit UserCheckpoint(account);\n }\n\n function _updatePoints(\n mapping(uint256 => uint256) storage _points,\n uint256 balance,\n uint256 lastTime\n ) internal {\n if (balance == 0) return;\n\n if (lastTime == 0) {\n uint256 startWeek = ISousChef(sousChef).startWeek();\n lastTime = startWeek.toTimestamp();\n }\n\n uint256 from = lastTime.toWeekNumber();\n for (uint256 i; i < 512; ) {\n uint256 week = from + i;\n uint256 weekStart = week.toTimestamp();\n uint256 weekEnd = weekStart + WEEK;\n if (block.timestamp <= weekStart) break;\n if (block.timestamp < weekEnd) {\n _points[week] += balance * (block.timestamp - Math.max(lastTime, weekStart));\n break;\n }\n if (i == 0) {\n _points[week] += balance * (weekEnd - lastTime);\n } else {\n _points[week] += balance * WEEK;\n }\n\n unchecked {\n ++i;\n }\n }\n }\n\n function claimRewards(address beneficiary) external {\n userCheckpoint(msg.sender);\n\n uint256 from = nextClaimableWeek[msg.sender];\n if (from == block.timestamp.toWeekNumber()) return;\n if (from == 0) {\n from = ISousChef(sousChef).startWeek();\n }\n\n (address _sousChef, uint256 _pid) = (sousChef, pid);\n address kitchen = ISousChef(_sousChef).kitchen();\n IFSushiKitchen(kitchen).checkpoint(_pid);\n\n // add week-by-week rewards until the last week\n uint256 totalRewards;\n uint256 to = block.timestamp.toWeekNumber(); // exclusive last index\n for (uint256 i; i < 512; ) {\n uint256 week = from + i;\n if (to <= week) break;\n uint256 weeklyRewards = ISousChef(_sousChef).weeklyRewards(week);\n uint256 weight = IFSushiKitchen(kitchen).relativeWeightAt(_pid, (week + 1).toTimestamp());\n uint256 rewards = points[week] == 0\n ? 0\n : (weeklyRewards * weight * userPoints[msg.sender][week]) / points[week] / 1e18;\n totalRewards += rewards;\n\n unchecked {\n ++i;\n }\n }\n nextClaimableWeek[msg.sender] = to;\n\n if (totalRewards > 0) {\n claimedRewards[msg.sender] += totalRewards;\n\n ISousChef(sousChef).mintFSushi(_pid, beneficiary, totalRewards);\n\n emit ClaimRewards(msg.sender, beneficiary, totalRewards);\n }\n }\n\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal override returns (uint256 balanceOfFrom, uint256 balanceOfTo) {\n userCheckpoint(from);\n userCheckpoint(to);\n\n return super._transfer(from, to, amount);\n }\n}\n"
},
"@openzeppelin/contracts/utils/math/SafeCast.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n *\n * _Available since v4.7._\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n require(value <= type(uint248).max, \"SafeCast: value doesn't fit in 248 bits\");\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n *\n * _Available since v4.7._\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n require(value <= type(uint240).max, \"SafeCast: value doesn't fit in 240 bits\");\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n *\n * _Available since v4.7._\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n require(value <= type(uint232).max, \"SafeCast: value doesn't fit in 232 bits\");\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n *\n * _Available since v4.2._\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n *\n * _Available since v4.7._\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n require(value <= type(uint216).max, \"SafeCast: value doesn't fit in 216 bits\");\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n *\n * _Available since v4.7._\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n require(value <= type(uint208).max, \"SafeCast: value doesn't fit in 208 bits\");\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n *\n * _Available since v4.7._\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n require(value <= type(uint200).max, \"SafeCast: value doesn't fit in 200 bits\");\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n *\n * _Available since v4.7._\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n require(value <= type(uint192).max, \"SafeCast: value doesn't fit in 192 bits\");\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n *\n * _Available since v4.7._\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n require(value <= type(uint184).max, \"SafeCast: value doesn't fit in 184 bits\");\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n *\n * _Available since v4.7._\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n require(value <= type(uint176).max, \"SafeCast: value doesn't fit in 176 bits\");\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n *\n * _Available since v4.7._\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n require(value <= type(uint168).max, \"SafeCast: value doesn't fit in 168 bits\");\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n *\n * _Available since v4.7._\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n require(value <= type(uint160).max, \"SafeCast: value doesn't fit in 160 bits\");\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n *\n * _Available since v4.7._\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n require(value <= type(uint152).max, \"SafeCast: value doesn't fit in 152 bits\");\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n *\n * _Available since v4.7._\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n require(value <= type(uint144).max, \"SafeCast: value doesn't fit in 144 bits\");\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n *\n * _Available since v4.7._\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n require(value <= type(uint136).max, \"SafeCast: value doesn't fit in 136 bits\");\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v2.5._\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n *\n * _Available since v4.7._\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n require(value <= type(uint120).max, \"SafeCast: value doesn't fit in 120 bits\");\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n *\n * _Available since v4.7._\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n require(value <= type(uint112).max, \"SafeCast: value doesn't fit in 112 bits\");\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n *\n * _Available since v4.7._\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n require(value <= type(uint104).max, \"SafeCast: value doesn't fit in 104 bits\");\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n *\n * _Available since v4.2._\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n *\n * _Available since v4.7._\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n require(value <= type(uint88).max, \"SafeCast: value doesn't fit in 88 bits\");\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n *\n * _Available since v4.7._\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n require(value <= type(uint80).max, \"SafeCast: value doesn't fit in 80 bits\");\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n *\n * _Available since v4.7._\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n require(value <= type(uint72).max, \"SafeCast: value doesn't fit in 72 bits\");\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v2.5._\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n *\n * _Available since v4.7._\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n require(value <= type(uint56).max, \"SafeCast: value doesn't fit in 56 bits\");\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n *\n * _Available since v4.7._\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n require(value <= type(uint48).max, \"SafeCast: value doesn't fit in 48 bits\");\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n *\n * _Available since v4.7._\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n require(value <= type(uint40).max, \"SafeCast: value doesn't fit in 40 bits\");\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v2.5._\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n *\n * _Available since v4.7._\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n require(value <= type(uint24).max, \"SafeCast: value doesn't fit in 24 bits\");\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v2.5._\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n *\n * _Available since v2.5._\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n *\n * _Available since v3.0._\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n *\n * _Available since v4.7._\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 248 bits\");\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n *\n * _Available since v4.7._\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 240 bits\");\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n *\n * _Available since v4.7._\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 232 bits\");\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n *\n * _Available since v4.7._\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 224 bits\");\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n *\n * _Available since v4.7._\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 216 bits\");\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n *\n * _Available since v4.7._\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 208 bits\");\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n *\n * _Available since v4.7._\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 200 bits\");\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n *\n * _Available since v4.7._\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 192 bits\");\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n *\n * _Available since v4.7._\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 184 bits\");\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n *\n * _Available since v4.7._\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 176 bits\");\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n *\n * _Available since v4.7._\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 168 bits\");\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n *\n * _Available since v4.7._\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 160 bits\");\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n *\n * _Available since v4.7._\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 152 bits\");\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n *\n * _Available since v4.7._\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 144 bits\");\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n *\n * _Available since v4.7._\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 136 bits\");\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 128 bits\");\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n *\n * _Available since v4.7._\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 120 bits\");\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n *\n * _Available since v4.7._\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 112 bits\");\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n *\n * _Available since v4.7._\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 104 bits\");\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n *\n * _Available since v4.7._\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 96 bits\");\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n *\n * _Available since v4.7._\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 88 bits\");\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n *\n * _Available since v4.7._\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 80 bits\");\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n *\n * _Available since v4.7._\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 72 bits\");\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 64 bits\");\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n *\n * _Available since v4.7._\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 56 bits\");\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n *\n * _Available since v4.7._\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 48 bits\");\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n *\n * _Available since v4.7._\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 40 bits\");\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 32 bits\");\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n *\n * _Available since v4.7._\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 24 bits\");\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 16 bits\");\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 8 bits\");\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n *\n * _Available since v3.0._\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n"
},
"contracts/base/BaseERC20.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nabstract contract BaseERC20 is Initializable, IERC20Metadata {\n error Expired();\n error InvalidSignature();\n error InvalidAccount();\n error InvalidSender();\n error InvalidReceiver();\n error InvalidOwner();\n error InvalidSpender();\n error NotEnoughBalance();\n\n uint8 public constant override decimals = 18;\n bytes32 private _CACHED_DOMAIN_SEPARATOR;\n uint256 private _CACHED_CHAIN_ID;\n address private _CACHED_THIS;\n\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private _TYPE_HASH;\n\n string public override name;\n string public override symbol;\n\n uint256 internal _totalSupply;\n mapping(address => uint256) internal _balanceOf;\n mapping(address => mapping(address => uint256)) internal _allowance;\n mapping(address => uint256) public nonces;\n\n bytes32 private constant _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n function BaseERC20_initialize(\n string memory _name,\n string memory _symbol,\n string memory _version\n ) internal onlyInitializing {\n name = _name;\n symbol = _symbol;\n\n bytes32 hashedName = keccak256(bytes(_name));\n bytes32 hashedVersion = keccak256(bytes(_version));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n function DOMAIN_SEPARATOR() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n function totalSupply() external view virtual returns (uint256) {\n return _totalSupply;\n }\n\n function balanceOf(address account) external view virtual returns (uint256) {\n return _balanceOf[account];\n }\n\n function allowance(address owner, address spender) external view virtual returns (uint256) {\n return _allowance[owner][spender];\n }\n\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n\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 if (block.timestamp > deadline) revert Expired();\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n if (signer != owner) revert InvalidSignature();\n\n _approve(owner, spender, value);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool) {\n if (_allowance[from][msg.sender] != type(uint256).max) {\n _allowance[from][msg.sender] -= amount;\n }\n _transfer(from, to, amount);\n return true;\n }\n\n function transfer(address to, uint256 amount) external override returns (bool) {\n _transfer(msg.sender, to, amount);\n return true;\n }\n\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual returns (uint256 balanceOfFrom, uint256 balanceOfTo) {\n if (from == address(0)) revert InvalidSender();\n if (to == address(0)) revert InvalidReceiver();\n\n uint256 balance = _balanceOf[from];\n if (balance < amount) revert NotEnoughBalance();\n unchecked {\n balanceOfFrom = balance - amount;\n balanceOfTo = _balanceOf[to] + amount;\n _balanceOf[from] = balanceOfFrom;\n _balanceOf[to] = balanceOfTo;\n }\n\n emit Transfer(from, to, amount);\n }\n\n function approve(address spender, uint256 amount) external override returns (bool) {\n _approve(msg.sender, spender, amount);\n return true;\n }\n\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n if (owner == address(0)) revert InvalidOwner();\n if (spender == address(0)) revert InvalidSpender();\n\n _allowance[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n function _mint(address account, uint256 amount) internal virtual {\n if (account == address(0)) revert InvalidAccount();\n\n _totalSupply += amount;\n unchecked {\n _balanceOf[account] += amount;\n }\n\n emit Transfer(address(0), account, amount);\n }\n\n function _burn(address account, uint256 amount) internal virtual {\n if (account == address(0)) revert InvalidAccount();\n\n uint256 balance = _balanceOf[account];\n if (balance < amount) revert NotEnoughBalance();\n unchecked {\n _balanceOf[account] = balance - amount;\n _totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n }\n}\n"
},
"contracts/interfaces/IFSushiBill.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IFSushiBill is IERC20Metadata {\n error NoClaimableRewards();\n\n event Deposit(address indexed account, uint256 amount, address indexed beneficiary);\n event Withdraw(address indexed account, uint256 amount, address indexed beneficiary);\n event Checkpoint();\n event UserCheckpoint(address indexed account);\n event ClaimRewards(address indexed account, address indexed beneficiary, uint256 amount);\n\n function sousChef() external view returns (address);\n\n function pid() external view returns (uint256);\n\n function fToken() external view returns (address);\n\n function points(uint256 week) external view returns (uint256);\n\n function lastCheckpoint() external view returns (uint256 timestamp);\n\n function userPoints(address account, uint256 week) external view returns (uint256);\n\n function userLastCheckpoint(address account) external view returns (uint256 timestamp);\n\n function claimedRewards(address account) external view returns (uint256);\n\n function nextClaimableWeek(address account) external view returns (uint256);\n\n function initialize(uint256 _pid, address _fToken) external;\n\n function deposit(uint256 amount, address beneficiary) external;\n\n function withdraw(uint256 amount, address beneficiary) external;\n\n function claimRewards(address beneficiary) external;\n\n function checkpoint() external;\n\n function userCheckpoint(address account) external;\n}\n"
},
"contracts/interfaces/IFSushiKitchen.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFSushiKitchen {\n error InvalidPid();\n\n event AddPool(uint256 indexed pid);\n event UpdateWeight(uint256 indexed pid, uint256 weightPoints, uint256 totalWeightPoints);\n\n function flashStrategyFactory() external view returns (address);\n\n function totalWeightPointsLength() external view returns (uint256);\n\n function weightPointsLength(uint256 pid) external view returns (uint256);\n\n function totalWeightPoints() external view returns (uint256);\n\n function weightPoints(uint256 pid) external view returns (uint256);\n\n function totalWeightPointsAt(uint256 timestamp) external view returns (uint256);\n\n function weightPointsAt(uint256 pid, uint256 timestamp) external view returns (uint256);\n\n function relativeWeight(uint256 pid) external view returns (uint256);\n\n function relativeWeightAt(uint256 pid, uint256 timestamp) external view returns (uint256);\n\n function addPool(uint256 pid) external;\n\n function updateWeight(uint256 pid, uint256 points) external;\n\n function checkpoint(uint256 pid) external;\n}\n"
},
"contracts/FarmingLPToken.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Pair.sol\";\nimport \"./interfaces/IFarmingLPToken.sol\";\nimport \"./interfaces/IFarmingLPTokenFactory.sol\";\nimport \"./interfaces/IFarmingLPTokenMigrator.sol\";\nimport \"./interfaces/IMasterChef.sol\";\nimport \"./libraries/UniswapV2Utils.sol\";\nimport \"./base/BaseERC20.sol\";\n\ncontract FarmingLPToken is BaseERC20, ReentrancyGuard, IFarmingLPToken {\n using SafeERC20 for IERC20;\n using SafeCast for uint256;\n using SafeCast for int256;\n\n uint128 internal constant POINTS_MULTIPLIER = type(uint128).max;\n\n address public override factory;\n address public override router;\n address public override masterChef;\n uint256 public override pid;\n address public override sushi;\n address public override lpToken;\n address public override token0;\n address public override token1;\n\n uint256 public override withdrawableTotalLPs;\n uint256 internal _pointsPerShare;\n mapping(address => int256) internal _pointsCorrection;\n mapping(address => uint256) internal _withdrawnVaultBalanceOf;\n\n function initialize(\n address _router,\n address _masterChef,\n uint256 _pid\n ) external override initializer {\n if (_router == address(0)) return;\n\n factory = msg.sender;\n (address _lpToken, , , ) = IMasterChef(_masterChef).poolInfo(_pid);\n address _token0 = IUniswapV2Pair(_lpToken).token0();\n address _token1 = IUniswapV2Pair(_lpToken).token1();\n router = _router;\n masterChef = _masterChef;\n pid = _pid;\n sushi = IMasterChef(_masterChef).sushi();\n lpToken = _lpToken;\n token0 = _token0;\n token1 = _token1;\n\n BaseERC20_initialize(\n string.concat(\n \"Farming LP Token (\",\n IERC20Metadata(_token0).name(),\n \"-\",\n IERC20Metadata(_token1).name(),\n \")\"\n ),\n string.concat(\"fLP:\", IERC20Metadata(_token0).symbol(), \"-\", IERC20Metadata(_token1).symbol()),\n \"1\"\n );\n approveMax();\n }\n\n function withdrawableLPsOf(address account) external view override returns (uint256) {\n uint256 total = totalShares();\n if (total == 0) return 0;\n return (sharesOf(account) * withdrawableTotalLPs) / total;\n }\n\n /**\n * @return Sum of (shares in SUSHI) + (withdrawable total SUSHI)\n */\n function totalSupply() public view override(BaseERC20, IERC20) returns (uint256) {\n return totalShares() + withdrawableTotalYield();\n }\n\n /**\n * @return Sum of (shares in SUSHI by depositd account) + (SUSHI withdrawable by account)\n */\n function balanceOf(address account) public view override(BaseERC20, IERC20) returns (uint256) {\n return sharesOf(account) + withdrawableYieldOf(account);\n }\n\n /**\n * @return total shares in SUSHI currently being depositd\n */\n function totalShares() public view override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @return shares in SUSHI currently being depositd by account\n */\n function sharesOf(address account) public view override returns (uint256) {\n return _balanceOf[account];\n }\n\n /**\n * @dev Returns the total amount of SUSHI if every holder wants to withdraw at once\n * @return A uint256 representing the total SUSHI\n */\n function withdrawableTotalYield() public view override returns (uint256) {\n address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n uint256 pendingSushi = IMasterChef(masterChef).pendingSushi(pid, address(this));\n return pendingSushi + IERC4626(yieldVault).maxWithdraw(address(this));\n }\n\n /**\n * @dev Returns the amount of SUSHI a given address is able to withdraw.\n * @param account Address of a reward recipient\n * @return A uint256 representing the SUSHI `account` can withdraw\n */\n function withdrawableYieldOf(address account) public view override returns (uint256) {\n address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n return IERC4626(yieldVault).convertToAssets((_withdrawableVaultBalanceOf(account, true)));\n }\n\n /**\n * @dev Vault balance is used to record reward debt for account.\n * @param account Address of a reward recipient\n * @param preview if true, it adds the amount of MasterChef.pendingSushi()\n * @return A uint256 representing the SUSHI `account` can withdraw\n */\n function _withdrawableVaultBalanceOf(address account, bool preview) internal view returns (uint256) {\n return _cumulativeVaultBalanceOf(account, preview) - _withdrawnVaultBalanceOf[account];\n }\n\n /**\n * @notice View the amount of vault balance that an address has earned in total.\n * @dev cumulativeVaultBalanceOf(account) = withdrawableVaultBalanceOf(account) + withdrawnVaultBalanceOf(account)\n * = (pointsPerShare * sharesOf(account) + pointsCorrection[account]) / POINTS_MULTIPLIER\n * @param account The address of a token holder.\n * @param preview if true, it adds the amount of MasterChef.pendingSushi()\n * @return The amount of SUSHI that `account` has earned in total.\n */\n function _cumulativeVaultBalanceOf(address account, bool preview) internal view returns (uint256) {\n uint256 pointsPerShare = _pointsPerShare;\n if (preview) {\n uint256 total = totalShares();\n if (total > 0) {\n address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n uint256 pendingSushi = IMasterChef(masterChef).pendingSushi(pid, address(this));\n pointsPerShare += (IERC4626(yieldVault).previewDeposit(pendingSushi) * POINTS_MULTIPLIER) / total;\n }\n }\n return\n ((pointsPerShare * sharesOf(account)).toInt256() + _pointsCorrection[account]).toUint256() /\n POINTS_MULTIPLIER;\n }\n\n function approveMax() public override {\n IERC20(lpToken).approve(masterChef, type(uint256).max);\n IERC20(sushi).approve(IFarmingLPTokenFactory(factory).yieldVault(), type(uint256).max);\n IERC20(sushi).approve(router, type(uint256).max);\n IERC20(token0).approve(router, type(uint256).max);\n IERC20(token1).approve(router, type(uint256).max);\n }\n\n /**\n * @dev amount of sushi that LPs converted to is added to sharesOf(account) and aLP is minted\n * user signature is needed for IUniswapV2Pair.permit()\n */\n function depositSigned(\n uint256 amountLP,\n address[] calldata path0,\n address[] calldata path1,\n uint256 amountMin,\n address beneficiary,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external override nonReentrant {\n IUniswapV2Pair(lpToken).permit(msg.sender, address(this), amountLP, deadline, v, r, s);\n _deposit(amountLP, path0, path1, amountMin, beneficiary);\n }\n\n /**\n * @dev amount of sushi that LPs converted to is added to sharesOf(account) and aLP is minted\n */\n function deposit(\n uint256 amountLP,\n address[] calldata path0,\n address[] calldata path1,\n uint256 amountMin,\n address beneficiary,\n uint256 deadline\n ) external override nonReentrant {\n if (block.timestamp > deadline) revert Expired();\n _deposit(amountLP, path0, path1, amountMin, beneficiary);\n }\n\n function _deposit(\n uint256 amountLP,\n address[] calldata path0,\n address[] calldata path1,\n uint256 amountMin,\n address beneficiary\n ) internal {\n if (path0[0] != token0 || path0[path0.length - 1] != sushi) revert InvalidPath();\n if (path1[0] != token1 || path1[path1.length - 1] != sushi) revert InvalidPath();\n\n IERC20(lpToken).safeTransferFrom(msg.sender, address(this), amountLP);\n\n uint256 total = IUniswapV2Pair(lpToken).totalSupply();\n (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(lpToken).getReserves();\n uint256 amount = UniswapV2Utils.quote(router, (reserve0 * amountLP) / total, path0) +\n UniswapV2Utils.quote(router, (reserve1 * amountLP) / total, path1);\n\n if (amount < amountMin) revert InsufficientAmount();\n\n IMasterChef(masterChef).deposit(pid, amountLP);\n _depositSushi();\n\n _mint(beneficiary, amount);\n withdrawableTotalLPs += amountLP;\n\n emit Deposit(amount, amountLP, beneficiary);\n }\n\n /**\n * @dev amount is added to sharesOf(account) and same amount of aLP is minted\n * provided SUSHI is swapped then added as liquidity which results in LP tokens depositd\n */\n function depositWithSushi(\n uint256 amount,\n address[] calldata path0,\n address[] calldata path1,\n uint256 amountLPMin,\n address beneficiary,\n uint256 deadline\n ) external override {\n if (path0[0] != sushi || path0[path0.length - 1] != token0) revert InvalidPath();\n if (path1[0] != sushi || path1[path1.length - 1] != token1) revert InvalidPath();\n\n IERC20(sushi).safeTransferFrom(msg.sender, address(this), amount);\n uint256 amountLP = UniswapV2Utils.addLiquidityWithSingleToken(router, amount, path0, path1, deadline);\n if (amountLP < amountLPMin) revert InsufficientAmount();\n\n IMasterChef(masterChef).deposit(pid, amountLP);\n _depositSushi();\n\n _mint(beneficiary, amount);\n withdrawableTotalLPs += amountLP;\n\n emit Deposit(amount, amountLP, beneficiary);\n }\n\n /**\n * @dev when unstaking, the user's share of LP tokens are returned and pro-rata SUSHI yield is return as well\n */\n function withdraw(uint256 shares, address beneficiary) external override nonReentrant {\n uint256 amountLP = (shares * withdrawableTotalLPs) / totalShares();\n IMasterChef(masterChef).withdraw(pid, amountLP);\n\n _claimSushi(shares, beneficiary);\n\n IERC20(lpToken).safeTransfer(beneficiary, amountLP);\n\n _burn(msg.sender, shares);\n withdrawableTotalLPs -= amountLP;\n\n emit Withdraw(shares, amountLP, beneficiary);\n }\n\n function _claimSushi(uint256 shares, address beneficiary) internal {\n _depositSushi();\n\n uint256 sharesMax = sharesOf(msg.sender);\n if (shares > sharesMax) revert InsufficientAmount();\n\n address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n uint256 withdrawable = _withdrawableVaultBalanceOf(msg.sender, false);\n if (withdrawable == 0) revert InsufficientYield();\n\n uint256 yieldShares = (withdrawable * shares) / sharesMax;\n _withdrawnVaultBalanceOf[msg.sender] += yieldShares;\n\n uint256 yield = IERC4626(yieldVault).redeem(yieldShares, beneficiary, address(this));\n\n emit ClaimSushi(shares, yield, beneficiary);\n }\n\n /**\n * @dev withdraw without caring about rewards. EMERGENCY ONLY\n */\n function emergencyWithdraw(address beneficiary) external override nonReentrant {\n uint256 shares = sharesOf(msg.sender);\n uint256 amountLP = (shares * withdrawableTotalLPs) / totalShares();\n IMasterChef(masterChef).withdraw(pid, amountLP);\n\n IERC20(lpToken).safeTransfer(beneficiary, amountLP);\n\n _burn(msg.sender, shares);\n withdrawableTotalLPs -= amountLP;\n\n emit EmergencyWithdraw(shares, amountLP, beneficiary);\n }\n\n /**\n * @dev migrate to a new version of fLP\n */\n function migrate(address beneficiary, bytes calldata params) external nonReentrant {\n address migrator = IFarmingLPTokenFactory(factory).migrator();\n if (migrator == address(0)) revert NoMigratorSet();\n\n uint256 shares = sharesOf(msg.sender);\n uint256 amountLP = (shares * withdrawableTotalLPs) / totalShares();\n IMasterChef(masterChef).withdraw(pid, amountLP);\n\n _claimSushi(shares, beneficiary);\n\n _burn(msg.sender, shares);\n withdrawableTotalLPs -= amountLP;\n\n address _lpToken = lpToken;\n IERC20(_lpToken).approve(migrator, amountLP);\n IFarmingLPTokenMigrator(migrator).onMigrate(msg.sender, pid, _lpToken, shares, amountLP, beneficiary, params);\n\n emit Migrate(shares, amountLP, beneficiary);\n }\n\n /**\n * @dev migrate to a new version of fLP without caring about rewards. EMERGENCY ONLY\n */\n function emergencyMigrate(address beneficiary, bytes calldata params) external nonReentrant {\n address migrator = IFarmingLPTokenFactory(factory).migrator();\n if (migrator == address(0)) revert NoMigratorSet();\n\n uint256 shares = sharesOf(msg.sender);\n uint256 amountLP = (shares * withdrawableTotalLPs) / totalShares();\n IMasterChef(masterChef).withdraw(pid, amountLP);\n\n _burn(msg.sender, shares);\n withdrawableTotalLPs -= amountLP;\n\n address _lpToken = lpToken;\n IERC20(_lpToken).approve(migrator, amountLP);\n IFarmingLPTokenMigrator(migrator).onMigrate(msg.sender, pid, _lpToken, shares, amountLP, beneficiary, params);\n\n emit EmergencyMigrate(shares, amountLP, beneficiary);\n }\n\n /**\n * @dev withdraws pending SUSHI from MasterChef and add it to the balance\n */\n function checkpoint() external override nonReentrant {\n uint256 balance = IERC20(lpToken).balanceOf(address(this));\n if (balance > withdrawableTotalLPs) {\n withdrawableTotalLPs = balance;\n }\n\n IMasterChef(masterChef).deposit(pid, 0);\n _depositSushi();\n }\n\n function _depositSushi() internal {\n uint256 balance = IERC20(sushi).balanceOf(address(this));\n if (balance > 0) {\n address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n uint256 yieldBalance = IERC4626(yieldVault).deposit(balance, address(this));\n\n uint256 total = totalShares();\n if (total > 0) {\n _pointsPerShare += (yieldBalance * POINTS_MULTIPLIER) / total;\n }\n }\n }\n\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal override returns (uint256 balanceOfFrom, uint256 balanceOfTo) {\n uint256 balance = balanceOf(from);\n uint256 shares = balance == 0 ? 0 : (amount * sharesOf(from)) / balance;\n\n (balanceOfFrom, balanceOfTo) = super._transfer(from, to, shares);\n\n int256 _magCorrection = (_pointsPerShare * shares).toInt256();\n _pointsCorrection[from] += _magCorrection;\n _pointsCorrection[to] += _magCorrection;\n }\n\n function _mint(address account, uint256 shares) internal override {\n super._mint(account, shares);\n\n _correctPoints(account, -int256(shares));\n }\n\n function _burn(address account, uint256 shares) internal override {\n super._burn(account, shares);\n\n _correctPoints(account, int256(shares));\n }\n\n function _correctPoints(address account, int256 amount) internal {\n _pointsCorrection[account] += amount * int256(_pointsPerShare);\n }\n}\n"
},
"contracts/interfaces/IFarmingLPTokenMigrator.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFarmingLPTokenMigrator {\n /**\n * @dev address of legacy FarmingLPTokenFactory\n */\n function factoryLegacy() external view returns (address);\n\n /**\n * @dev msg.sender MUST be factoryLegacy.getFarmingLPToken(lpToken)\n */\n function onMigrate(\n address account,\n uint256 pid,\n address lpToken,\n uint256 shares,\n uint256 amountLP,\n address beneficiary,\n bytes calldata params\n ) external;\n}\n"
},
"contracts/interfaces/IMasterChef.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IMasterChef {\n function sushi() external view returns (address);\n\n function poolInfo(uint256 _pid)\n external\n view\n returns (\n address lpToken,\n uint256 allocPoint,\n uint256 lastRewardBlock,\n uint256 accSushiPerShare\n );\n\n function userInfo(uint256 _pid, address user) external view returns (uint256 amount, uint256 rewardDebt);\n\n function pendingSushi(uint256 _pid, address _user) external view returns (uint256);\n\n function deposit(uint256 _pid, uint256 _amount) external;\n\n function withdraw(uint256 _pid, uint256 _amount) external;\n}\n"
},
"contracts/libraries/UniswapV2Utils.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol\";\n\nlibrary UniswapV2Utils {\n using SafeERC20 for IERC20;\n\n error InsufficientAmountLP();\n\n function quote(\n address router,\n uint256 amountIn,\n address[] memory path\n ) internal view returns (uint256 amountOut) {\n if (path.length < 2) return amountIn;\n\n uint256[] memory amountsOut = IUniswapV2Router02(router).getAmountsOut(amountIn, path);\n return amountsOut[amountsOut.length - 1];\n }\n\n function addLiquidityWithSingleToken(\n address router,\n uint256 amount,\n address[] memory path0,\n address[] memory path1,\n uint256 deadline\n ) internal returns (uint256 amountLP) {\n uint256 amountOut0 = swap(router, amount / 2, path0, deadline);\n uint256 amountOut1 = swap(router, amount / 2, path1, deadline);\n\n (address token0, address token1) = (path0[path0.length - 1], path1[path1.length - 1]);\n (, , uint256 _amountLP) = IUniswapV2Router02(router).addLiquidity(\n token0,\n token1,\n amountOut0,\n amountOut1,\n 0,\n 0,\n address(this),\n deadline\n );\n\n uint256 balance0 = IERC20(token0).balanceOf(address(this));\n if (balance0 > 0) {\n IERC20(token0).safeTransfer(msg.sender, balance0);\n }\n uint256 balance1 = IERC20(token1).balanceOf(address(this));\n if (balance1 > 0) {\n IERC20(token1).safeTransfer(msg.sender, balance1);\n }\n\n return _amountLP;\n }\n\n function swap(\n address router,\n uint256 amountIn,\n address[] memory path,\n uint256 deadline\n ) internal returns (uint256 amountOut) {\n if (path.length < 2) return amountIn;\n\n uint256[] memory amountsOut = IUniswapV2Router02(router).swapExactTokensForTokens(\n amountIn,\n 0,\n path,\n address(this),\n deadline\n );\n return amountsOut[amountsOut.length - 1];\n }\n}\n"
},
"@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Pair.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2Pair {\n event Approval(address indexed owner, address indexed spender, uint value);\n event Transfer(address indexed from, address indexed to, uint value);\n\n function name() external pure returns (string memory);\n function symbol() external pure returns (string memory);\n function decimals() external pure returns (uint8);\n function totalSupply() external view returns (uint);\n function balanceOf(address owner) external view returns (uint);\n function allowance(address owner, address spender) external view returns (uint);\n\n function approve(address spender, uint value) external returns (bool);\n function transfer(address to, uint value) external returns (bool);\n function transferFrom(address from, address to, uint value) external returns (bool);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n function PERMIT_TYPEHASH() external pure returns (bytes32);\n function nonces(address owner) external view returns (uint);\n\n function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;\n\n event Mint(address indexed sender, uint amount0, uint amount1);\n event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);\n event Swap(\n address indexed sender,\n uint amount0In,\n uint amount1In,\n uint amount0Out,\n uint amount1Out,\n address indexed to\n );\n event Sync(uint112 reserve0, uint112 reserve1);\n\n function MINIMUM_LIQUIDITY() external pure returns (uint);\n function factory() external view returns (address);\n function token0() external view returns (address);\n function token1() external view returns (address);\n function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);\n function price0CumulativeLast() external view returns (uint);\n function price1CumulativeLast() external view returns (uint);\n function kLast() external view returns (uint);\n\n function mint(address to) external returns (uint liquidity);\n function burn(address to) external returns (uint amount0, uint amount1);\n function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;\n function skim(address to) external;\n function sync() external;\n\n function initialize(address, address) external;\n}"
},
"@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.2;\n\nimport './IUniswapV2Router01.sol';\n\ninterface IUniswapV2Router02 is IUniswapV2Router01 {\n function removeLiquidityETHSupportingFeeOnTransferTokens(\n address token,\n uint liquidity,\n uint amountTokenMin,\n uint amountETHMin,\n address to,\n uint deadline\n ) external returns (uint amountETH);\n function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\n address token,\n uint liquidity,\n uint amountTokenMin,\n uint amountETHMin,\n address to,\n uint deadline,\n bool approveMax, uint8 v, bytes32 r, bytes32 s\n ) external returns (uint amountETH);\n\n function swapExactTokensForTokensSupportingFeeOnTransferTokens(\n uint amountIn,\n uint amountOutMin,\n address[] calldata path,\n address to,\n uint deadline\n ) external;\n function swapExactETHForTokensSupportingFeeOnTransferTokens(\n uint amountOutMin,\n address[] calldata path,\n address to,\n uint deadline\n ) external payable;\n function swapExactTokensForETHSupportingFeeOnTransferTokens(\n uint amountIn,\n uint amountOutMin,\n address[] calldata path,\n address to,\n uint deadline\n ) external;\n}"
},
"@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.2;\n\ninterface IUniswapV2Router01 {\n function factory() external pure returns (address);\n function WETH() external pure returns (address);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint amountADesired,\n uint amountBDesired,\n uint amountAMin,\n uint amountBMin,\n address to,\n uint deadline\n ) external returns (uint amountA, uint amountB, uint liquidity);\n function addLiquidityETH(\n address token,\n uint amountTokenDesired,\n uint amountTokenMin,\n uint amountETHMin,\n address to,\n uint deadline\n ) external payable returns (uint amountToken, uint amountETH, uint liquidity);\n function removeLiquidity(\n address tokenA,\n address tokenB,\n uint liquidity,\n uint amountAMin,\n uint amountBMin,\n address to,\n uint deadline\n ) external returns (uint amountA, uint amountB);\n function removeLiquidityETH(\n address token,\n uint liquidity,\n uint amountTokenMin,\n uint amountETHMin,\n address to,\n uint deadline\n ) external returns (uint amountToken, uint amountETH);\n function removeLiquidityWithPermit(\n address tokenA,\n address tokenB,\n uint liquidity,\n uint amountAMin,\n uint amountBMin,\n address to,\n uint deadline,\n bool approveMax, uint8 v, bytes32 r, bytes32 s\n ) external returns (uint amountA, uint amountB);\n function removeLiquidityETHWithPermit(\n address token,\n uint liquidity,\n uint amountTokenMin,\n uint amountETHMin,\n address to,\n uint deadline,\n bool approveMax, uint8 v, bytes32 r, bytes32 s\n ) external returns (uint amountToken, uint amountETH);\n function swapExactTokensForTokens(\n uint amountIn,\n uint amountOutMin,\n address[] calldata path,\n address to,\n uint deadline\n ) external returns (uint[] memory amounts);\n function swapTokensForExactTokens(\n uint amountOut,\n uint amountInMax,\n address[] calldata path,\n address to,\n uint deadline\n ) external returns (uint[] memory amounts);\n function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)\n external\n payable\n returns (uint[] memory amounts);\n function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)\n external\n returns (uint[] memory amounts);\n function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)\n external\n returns (uint[] memory amounts);\n function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)\n external\n payable\n returns (uint[] memory amounts);\n\n function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);\n function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);\n function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);\n function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);\n function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);\n}"
},
"contracts/FarmingLPTokenFactory.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/proxy/Clones.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./interfaces/IFarmingLPTokenFactory.sol\";\nimport \"./FarmingLPToken.sol\";\n\ncontract FarmingLPTokenFactory is Ownable, IFarmingLPTokenFactory {\n address public immutable override router;\n address public immutable override masterChef;\n address internal immutable _implementation;\n\n address public override yieldVault;\n address public override migrator;\n mapping(uint256 => address) public override getFarmingLPToken;\n\n constructor(\n address _router,\n address _masterChef,\n address _yieldVault\n ) {\n router = _router;\n masterChef = _masterChef;\n yieldVault = _yieldVault;\n FarmingLPToken token = new FarmingLPToken();\n token.initialize(address(0), address(0), 0);\n _implementation = address(token);\n }\n\n function predictFarmingLPTokenAddress(uint256 pid) external view override returns (address token) {\n token = Clones.predictDeterministicAddress(_implementation, bytes32(pid));\n }\n\n function updateYieldVault(address vault) external override onlyOwner {\n if (vault == address(0)) revert InvalidAddress();\n yieldVault = vault;\n\n emit UpdateVault(vault);\n }\n\n function updateMigrator(address _migrator) external override onlyOwner {\n if (_migrator != address(0)) revert MigratorSet();\n migrator = _migrator;\n\n emit UpdateMigrator(_migrator);\n }\n\n function createFarmingLPToken(uint256 pid) external override returns (address token) {\n if (getFarmingLPToken[pid] != address(0)) revert TokenCreated();\n\n token = Clones.cloneDeterministic(_implementation, bytes32(pid));\n FarmingLPToken(token).initialize(router, masterChef, pid);\n\n getFarmingLPToken[pid] = token;\n\n emit CreateFarmingLPToken(pid, token);\n }\n}\n"
},
"contracts/FSushiCookV0.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"./interfaces/IFlashStrategySushiSwapFactory.sol\";\nimport \"./interfaces/IFlashStrategySushiSwap.sol\";\nimport \"./interfaces/IFarmingLPTokenFactory.sol\";\nimport \"./interfaces/IFarmingLPToken.sol\";\nimport \"./interfaces/ISousChef.sol\";\nimport \"./interfaces/IFSushiBill.sol\";\n\ninterface IFlashProtocol_ {\n function stake(\n address _strategyAddress,\n uint256 _tokenAmount,\n uint256 _stakeDuration,\n address _fTokensTo,\n bool _issueNFT\n )\n external\n returns (\n address stakerAddress,\n address strategyAddress,\n uint256 stakeStartTs,\n uint256 stakeDuration,\n uint256 stakedAmount,\n bool active,\n uint256 nftId,\n uint256 fTokensToUser,\n uint256 fTokensFee,\n uint256 totalFTokenBurned,\n uint256 totalStakedWithdrawn\n );\n}\n\ncontract FSushiCookV0 {\n address public immutable flashStrategyFactory;\n address public immutable flpTokenFactory;\n address public immutable sousChef;\n\n constructor(address _flashStrategyFactory, address _sousChef) {\n flashStrategyFactory = _flashStrategyFactory;\n flpTokenFactory = IFlashStrategySushiSwapFactory(_flashStrategyFactory).flpTokenFactory();\n sousChef = _sousChef;\n }\n\n function cook(\n uint256 pid,\n uint256 amountLP,\n address[] calldata path0,\n address[] calldata path1,\n uint256 amountMin,\n address beneficiary,\n uint256 stakeDuration,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n address flpToken = IFarmingLPTokenFactory(flpTokenFactory).getFarmingLPToken(pid);\n IFarmingLPToken(flpToken).depositSigned(amountLP, path0, path1, amountMin, address(this), deadline, v, r, s);\n\n uint256 amountFLP = IFarmingLPToken(flpToken).balanceOf(address(this));\n address strategy = IFlashStrategySushiSwapFactory(flpTokenFactory).getFlashStrategySushiSwap(pid);\n\n address protocol = IFlashStrategySushiSwap(strategy).flashProtocol();\n (, , , , , , , uint256 fTokensToUser, , , ) = IFlashProtocol_(protocol).stake(\n strategy,\n amountFLP,\n stakeDuration,\n beneficiary,\n false\n );\n\n address bill = ISousChef(sousChef).getBill(pid);\n IFSushiBill(bill).deposit(fTokensToUser, msg.sender);\n }\n}\n"
},
"contracts/FSushiBar.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"./interfaces/IFSushiBar.sol\";\nimport \"./interfaces/IFSushi.sol\";\nimport \"./libraries/FSushiBarPriorityQueue.sol\";\nimport \"./libraries/DateUtils.sol\";\n\n/**\n * @notice FSushiBar is an extension of ERC4626 with the addition of vesting period for locks\n */\ncontract FSushiBar is IFSushiBar {\n using FSushiBarPriorityQueue for FSushiBarPriorityQueue.Heap;\n using SafeERC20 for IERC20;\n using Math for uint256;\n using DateUtils for uint256;\n\n uint8 public constant decimals = 18;\n string public constant name = \"Flash SushiBar\";\n string public constant symbol = \"xfSUSHI\";\n uint256 internal constant MINIMUM_WEEKS = 1;\n uint256 internal constant MAXIMUM_WEEKS = 104; // almost 2 years\n\n address public immutable override asset;\n uint256 public immutable override startWeek;\n\n mapping(address => uint256) public override balanceOf;\n uint256 public override totalSupply;\n\n mapping(address => FSushiBarPriorityQueue.Heap) internal _locks;\n\n uint256 public override totalAssets;\n /**\n * @dev this is guaranteed to be correct up until the last week\n * @return minimum number of staked total assets during the whole week\n */\n mapping(uint256 => uint256) public override totalAssetsDuring;\n /**\n * @notice totalAssetsDuring is guaranteed to be correct before this week\n */\n uint256 public override lastCheckpoint; // week\n\n uint256 internal _totalPower;\n uint256 internal _totalYield;\n\n modifier validWeeks(uint256 _weeks) {\n if (_weeks < MINIMUM_WEEKS || _weeks > MAXIMUM_WEEKS) revert InvalidDuration();\n _;\n }\n\n constructor(address fSushi) {\n asset = fSushi;\n\n uint256 thisWeek = block.timestamp.toWeekNumber();\n startWeek = thisWeek;\n lastCheckpoint = thisWeek;\n }\n\n function previewDeposit(uint256 assets, uint256 _weeks)\n public\n view\n override\n validWeeks(_weeks)\n returns (uint256 shares)\n {\n return _toShares(_toPower(assets, _weeks), _totalPower);\n }\n\n function previewWithdraw(address owner)\n public\n view\n override\n returns (\n uint256 shares,\n uint256 assets,\n uint256 yield\n )\n {\n (assets, , shares) = _locks[owner].enqueued(block.timestamp);\n yield = _getYield(shares);\n }\n\n function _toShares(uint256 power, uint256 totalPower) internal view returns (uint256 shares) {\n uint256 supply = totalSupply;\n shares = (power == 0 || supply == 0) ? power : power.mulDiv(supply, totalPower, Math.Rounding.Down);\n }\n\n function _toPower(uint256 assets, uint256 _weeks) internal pure returns (uint256) {\n return assets.mulDiv(_weeks, MAXIMUM_WEEKS, Math.Rounding.Up);\n }\n\n function _getYield(uint256 shares) internal view returns (uint256 yield) {\n uint256 _totalSupply = totalSupply;\n if (_totalSupply == 0) return 0;\n\n return _totalYield.mulDiv(shares, _totalSupply, Math.Rounding.Down);\n }\n\n function depositSigned(\n uint256 assets,\n uint256 _weeks,\n address beneficiary,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public override returns (uint256) {\n IFSushi(asset).permit(msg.sender, address(this), assets, deadline, v, r, s);\n\n return deposit(assets, _weeks, beneficiary);\n }\n\n function deposit(\n uint256 assets,\n uint256 _weeks,\n address beneficiary\n ) public override validWeeks(_weeks) returns (uint256) {\n checkpoint();\n\n uint256 max = (totalAssets > 0 || totalSupply == 0) ? type(uint256).max : 0;\n if (assets > max) revert Bankrupt();\n\n uint256 totalPower = _totalPower;\n uint256 power = _toPower(assets, _weeks);\n uint256 shares = _toShares(power, totalPower);\n\n IERC20(asset).safeTransferFrom(msg.sender, address(this), assets);\n _mint(beneficiary, shares);\n\n _locks[msg.sender].enqueue(block.timestamp + _weeks * (1 weeks), assets, power, shares);\n\n totalAssets += assets;\n totalAssetsDuring[block.timestamp.toWeekNumber()] += assets;\n _totalPower = totalPower + power;\n\n emit Deposit(msg.sender, beneficiary, shares, assets);\n\n return shares;\n }\n\n function withdraw(address beneficiary)\n public\n override\n returns (\n uint256 shares,\n uint256 assets,\n uint256 yield\n )\n {\n checkpoint();\n\n uint256 power;\n (assets, power, shares) = _locks[msg.sender].drain(block.timestamp);\n if (shares == 0) revert WithdrawalDenied();\n\n yield = _getYield(shares);\n totalAssets -= (assets + yield);\n totalAssetsDuring[block.timestamp.toWeekNumber()] -= (assets + yield);\n _totalPower -= power;\n _totalYield -= yield;\n\n _burn(msg.sender, shares);\n IERC20(asset).safeTransfer(beneficiary, assets + yield);\n\n emit Withdraw(msg.sender, beneficiary, shares, assets, yield);\n }\n\n function checkpointedTotalAssets() external override returns (uint256) {\n checkpoint();\n return totalAssets;\n }\n\n function checkpointedTotalAssetsDuring(uint256 week) external override returns (uint256) {\n checkpoint();\n return totalAssetsDuring[week];\n }\n\n /**\n * @dev if this function doesn't get called for 512 weeks (around 9.8 years) this contract breaks\n */\n function checkpoint() public override {\n uint256 oldTotalAssets = totalAssets;\n uint256 newTotalAssets = IERC20(asset).balanceOf(address(this));\n if (newTotalAssets > oldTotalAssets) {\n totalAssets = newTotalAssets;\n totalAssetsDuring[block.timestamp.toWeekNumber()] = newTotalAssets;\n _totalPower += newTotalAssets - oldTotalAssets;\n _totalYield += newTotalAssets - oldTotalAssets;\n }\n\n uint256 from = lastCheckpoint;\n uint256 until = block.timestamp.toWeekNumber();\n if (until <= from) return;\n\n for (uint256 i; i < 512; ) {\n uint256 week = from + i;\n if (until <= week) break;\n\n totalAssetsDuring[week + 1] = totalAssetsDuring[week];\n\n unchecked {\n ++i;\n }\n }\n\n lastCheckpoint = until;\n }\n\n function _mint(address account, uint256 amount) internal {\n if (account == address(0)) revert InvalidAccount();\n\n totalSupply += amount;\n unchecked {\n balanceOf[account] += amount;\n }\n\n emit Transfer(address(0), account, amount);\n }\n\n function _burn(address account, uint256 amount) internal {\n if (account == address(0)) revert InvalidAccount();\n\n uint256 balance = balanceOf[account];\n if (balance < amount) revert NotEnoughBalance();\n unchecked {\n balanceOf[account] = balance - amount;\n totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n }\n}\n"
},
"contracts/interfaces/IFSushiBar.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\nimport \"./IFSushiRestaurant.sol\";\n\ninterface IFSushiBar is IFSushiRestaurant {\n error Bankrupt();\n error InvalidDuration();\n error InvalidAccount();\n error NotEnoughBalance();\n error WithdrawalDenied();\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Deposit(address indexed sender, address indexed beneficiary, uint256 shares, uint256 assets);\n event Withdraw(address indexed owner, address indexed beneficiary, uint256 shares, uint256 assets, uint256 yield);\n\n function asset() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address account) external view returns (uint256);\n\n function previewDeposit(uint256 assets, uint256 _weeks) external view returns (uint256 shares);\n\n function previewWithdraw(address owner)\n external\n view\n returns (\n uint256 shares,\n uint256 assets,\n uint256 yield\n );\n\n function depositSigned(\n uint256 assets,\n uint256 _weeks,\n address receiver,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external returns (uint256);\n\n function deposit(\n uint256 assets,\n uint256 _weeks,\n address receiver\n ) external returns (uint256);\n\n function withdraw(address beneficiary)\n external\n returns (\n uint256 shares,\n uint256 assets,\n uint256 yield\n );\n}\n"
},
"contracts/libraries/FSushiBarPriorityQueue.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\n// modified https://github.com/MihanixA/SummingPriorityQueue/blob/master/contracts/SummingPriorityQueue.sol\nlibrary FSushiBarPriorityQueue {\n error QueueEmpty();\n\n struct Snapshot {\n uint256 assets;\n uint256 power;\n uint256 shares;\n }\n\n struct Heap {\n uint256[] timestamps;\n mapping(uint256 => Snapshot) snapshots;\n }\n\n modifier notEmpty(Heap storage self) {\n if (self.timestamps.length == 1) revert QueueEmpty();\n _;\n }\n\n function top(Heap storage self) internal view notEmpty(self) returns (uint256) {\n return self.timestamps[1];\n }\n\n /**\n * @dev average time complexity: O(log n), worst-case time complexity: O(n)\n */\n function enqueued(Heap storage self, uint256 timestamp)\n internal\n view\n returns (\n uint256 assets,\n uint256 power,\n uint256 shares\n )\n {\n return _dfs(self, timestamp, 1);\n }\n\n function _dfs(\n Heap storage self,\n uint256 timestamp,\n uint256 i\n )\n private\n view\n returns (\n uint256 assets,\n uint256 power,\n uint256 shares\n )\n {\n if (i >= self.timestamps.length) return (0, 0, 0);\n if (self.timestamps[i] > timestamp) return (0, 0, 0);\n\n Snapshot memory snapshot = self.snapshots[self.timestamps[i]];\n assets = snapshot.assets;\n power = snapshot.power;\n shares = snapshot.shares;\n\n (uint256 assetsLeft, uint256 powerLeft, uint256 sharesLeft) = _dfs(self, timestamp, i * 2);\n (uint256 assetsRight, uint256 powerRight, uint256 sharesRight) = _dfs(self, timestamp, i * 2 + 1);\n return (assets + assetsLeft + assetsRight, power + powerLeft + powerRight, shares + sharesLeft + sharesRight);\n }\n\n function enqueue(\n Heap storage self,\n uint256 timestamp,\n uint256 assets,\n uint256 power,\n uint256 shares\n ) internal {\n if (self.timestamps.length == 0) self.timestamps.push(0); // initialize\n\n self.timestamps.push(timestamp);\n uint256 i = self.timestamps.length - 1;\n\n while (i > 1 && self.timestamps[i / 2] > self.timestamps[i]) {\n (self.timestamps[i / 2], self.timestamps[i]) = (timestamp, self.timestamps[i / 2]);\n i /= 2;\n }\n\n self.snapshots[timestamp] = Snapshot(assets, power, shares);\n }\n\n function dequeue(Heap storage self)\n internal\n notEmpty(self)\n returns (\n uint256 timestamp,\n uint256 assets,\n uint256 power,\n uint256 shares\n )\n {\n if (self.timestamps.length == 1) revert QueueEmpty();\n\n timestamp = top(self);\n self.timestamps[1] = self.timestamps[self.timestamps.length - 1];\n self.timestamps.pop();\n\n uint256 i = 1;\n\n while (i * 2 < self.timestamps.length) {\n uint256 j = i * 2;\n\n if (j + 1 < self.timestamps.length)\n if (self.timestamps[j] > self.timestamps[j + 1]) j++;\n\n if (self.timestamps[i] < self.timestamps[j]) break;\n\n (self.timestamps[i], self.timestamps[j]) = (self.timestamps[j], self.timestamps[i]);\n i = j;\n }\n\n Snapshot memory snapshot = self.snapshots[timestamp];\n delete self.snapshots[timestamp];\n\n return (timestamp, snapshot.assets, snapshot.power, snapshot.shares);\n }\n\n function drain(Heap storage self, uint256 timestamp)\n internal\n returns (\n uint256 assetsDequeued,\n uint256 powerDequeued,\n uint256 sharesDequeued\n )\n {\n while (self.timestamps.length > 1 && top(self) < timestamp) {\n (, uint256 assets, uint256 power, uint256 shares) = dequeue(self);\n assetsDequeued += assets;\n powerDequeued += power;\n sharesDequeued += shares;\n }\n }\n}\n"
},
"contracts/FSushiAirdropsVotingEscrow.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"./interfaces/IVotingEscrow.sol\";\nimport \"./interfaces/IFSushi.sol\";\nimport \"./libraries/DateUtils.sol\";\n\ncontract FSushiAirdropsVotingEscrow {\n using DateUtils for uint256;\n\n uint256 private constant INITIAL_SUPPLY_PER_WEEK = 5000e18;\n\n address public immutable votingEscrow;\n address public immutable fSushi;\n uint256 public immutable startWeek;\n uint256 public immutable votingEscrowInterval;\n\n uint256 public lastCheckpoint;\n mapping(address => uint256) public lastCheckpointOf;\n mapping(uint256 => uint256) public votingEscrowTotalSupply;\n\n error Expired();\n error Claimed();\n\n event Claim(\n address indexed account,\n uint256 amount,\n address indexed beneficiary,\n uint256 fromWeek,\n uint256 untilWeek\n );\n\n constructor(address _votingEscrow, address _fSushi) {\n votingEscrow = _votingEscrow;\n fSushi = _fSushi;\n startWeek = block.timestamp.toWeekNumber();\n votingEscrowInterval = IVotingEscrow(_votingEscrow).interval();\n }\n\n function claim(address beneficiary) external returns (uint256 amount) {\n IVotingEscrow(votingEscrow).checkpoint();\n\n uint256 from = lastCheckpointOf[msg.sender];\n if (from == 0) {\n from = startWeek;\n }\n uint256 until = block.timestamp.toWeekNumber() + 1;\n\n for (uint256 i; i < 512; ) {\n uint256 week = from + i;\n if (week >= until) break;\n\n uint256 weekStart = week.toTimestamp();\n uint256 balance = _votingEscrowBalanceOf(msg.sender, weekStart);\n uint256 totalSupply = _votingEscrowTotalSupply(weekStart);\n\n amount += ((INITIAL_SUPPLY_PER_WEEK >> (week - startWeek)) * balance) / totalSupply;\n\n unchecked {\n ++i;\n }\n }\n\n lastCheckpointOf[msg.sender] = until;\n\n if (amount > 0) {\n IFSushi(fSushi).mint(beneficiary, amount);\n\n emit Claim(msg.sender, amount, beneficiary, from, until);\n }\n }\n\n function _votingEscrowBalanceOf(address account, uint256 timestamp) internal view returns (uint256) {\n uint256 epoch = IVotingEscrow(votingEscrow).userPointEpoch(account);\n if (epoch == 0) return 0;\n else {\n (int128 bias, int128 slope, uint256 ts, ) = IVotingEscrow(votingEscrow).userPointHistory(account, epoch);\n unchecked {\n bias -= slope * int128(int256(timestamp - ts));\n }\n if (bias < 0) bias = 0;\n return uint256(uint128(bias));\n }\n }\n\n function _votingEscrowTotalSupply(uint256 timestamp) internal returns (uint256) {\n uint256 week = timestamp.toWeekNumber();\n if (week < lastCheckpoint) return votingEscrowTotalSupply[week];\n\n lastCheckpoint = timestamp.toWeekNumber() + 1;\n\n uint256 epoch = IVotingEscrow(votingEscrow).epoch();\n (int128 bias, int128 slope, uint256 ts, ) = IVotingEscrow(votingEscrow).pointHistory(epoch);\n uint256 t_i = (ts / votingEscrowInterval) * votingEscrowInterval;\n for (uint256 i; i < 255; i++) {\n t_i += votingEscrowInterval;\n int128 d_slope;\n if (t_i > timestamp) t_i = timestamp;\n else d_slope = IVotingEscrow(votingEscrow).slopeChanges(t_i);\n unchecked {\n bias -= slope * int128(int256(t_i - ts));\n }\n if (t_i == timestamp) break;\n slope += d_slope;\n ts = t_i;\n }\n\n if (bias < 0) bias = 0;\n uint256 totalSupply = uint256(uint128(bias));\n votingEscrowTotalSupply[week] = totalSupply;\n return totalSupply;\n }\n}\n"
},
"contracts/interfaces/IVotingEscrow.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IVotingEscrow {\n error Forbidden();\n error Expired();\n error Existent();\n error NonExistent();\n error TooLate();\n error TooEarly();\n error InvalidAmount();\n error InvalidPath();\n error OutOfRange();\n error DiscountTooHigh();\n error Discounted();\n error NotExpired();\n error NotPastBlock();\n\n event SetDelegate(address indexed account, bool isDelegate);\n event Deposit(\n address indexed provider,\n uint256 value,\n uint256 discount,\n uint256 indexed unlockTime,\n int128 indexed _type,\n uint256 ts\n );\n event Withdraw(address indexed provider, uint256 value, uint256 discount, uint256 ts);\n event Supply(uint256 prevSupply, uint256 supply);\n\n function interval() external view returns (uint256);\n\n function maxDuration() external view returns (uint256);\n\n function token() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n\n function isDelegate(address account) external view returns (bool);\n\n function supply() external view returns (uint256);\n\n function delegateAt(address account, uint256 index) external view returns (address);\n\n function locked(address account)\n external\n view\n returns (\n int128 amount,\n int128 discount,\n uint256 start,\n uint256 end\n );\n\n function epoch() external view returns (uint256);\n\n function pointHistory(uint256 epoch)\n external\n view\n returns (\n int128 bias,\n int128 slope,\n uint256 ts,\n uint256 blk\n );\n\n function userPointHistory(address account, uint256 epoch)\n external\n view\n returns (\n int128 bias,\n int128 slope,\n uint256 ts,\n uint256 blk\n );\n\n function userPointEpoch(address account) external view returns (uint256);\n\n function slopeChanges(uint256 epoch) external view returns (int128);\n\n function delegateLength(address addr) external view returns (uint256);\n\n function getLastUserSlope(address addr) external view returns (int128);\n\n function getCheckpointTime(address _addr, uint256 _idx) external view returns (uint256);\n\n function unlockTime(address _addr) external view returns (uint256);\n\n function setDelegate(address account, bool _isDelegate) external;\n\n function checkpoint() external;\n\n function depositFor(address _addr, uint256 _value) external;\n\n function createLockFor(\n address _addr,\n uint256 _value,\n uint256 _discount,\n uint256 _duration\n ) external;\n\n function createLock(uint256 _value, uint256 _duration) external;\n\n function increaseAmountFor(\n address _addr,\n uint256 _value,\n uint256 _discount\n ) external;\n\n function increaseAmount(uint256 _value) external;\n\n function increaseUnlockTime(uint256 _duration) external;\n\n function withdraw() external;\n\n function balanceOf(address addr) external view returns (uint256);\n\n function balanceOf(address addr, uint256 _t) external view returns (uint256);\n\n function balanceOfAt(address addr, uint256 _block) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function totalSupply(uint256 t) external view returns (uint256);\n\n function totalSupplyAt(uint256 _block) external view returns (uint256);\n}\n"
},
"contracts/FSushiAirdrops.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"./interfaces/IFSushi.sol\";\n\ncontract FSushiAirdrops is Ownable {\n bytes32 private constant CLAIM_TYPEHASH =\n keccak256(\"Claim(uint256 chainId,address contract,uint256 id,address account,uint256 amount)\");\n\n address public immutable fSushi;\n address public signer;\n string[] public airdrops;\n mapping(uint256 => mapping(address => bool)) public hasClaimed;\n\n error NotEOA();\n error InvalidName();\n error InvalidId();\n error InvalidSignature();\n error Expired();\n error Claimed();\n\n event UpdateSigner(address indexed signer);\n event AddAirdrop(uint256 indexed id, string name);\n event Claim(uint256 indexed id, string name, address indexed account, uint256 amount, address indexed beneficiary);\n\n constructor(address _fSushi) {\n fSushi = _fSushi;\n }\n\n function updateSigner(address _signer) external onlyOwner {\n if (_signer.code.length > 0) revert NotEOA();\n\n signer = _signer;\n\n emit UpdateSigner(_signer);\n }\n\n function addAirdrop(string memory name) external onlyOwner {\n if (bytes(name).length == 0) revert InvalidName();\n\n uint256 id = airdrops.length;\n airdrops.push(name);\n\n emit AddAirdrop(id, name);\n }\n\n function claim(\n uint256 id,\n uint256 amount,\n address beneficiary,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n if (block.timestamp > deadline) revert Expired();\n\n string memory name = airdrops[id];\n if (bytes(name).length == 0) revert InvalidId();\n\n if (hasClaimed[id][msg.sender]) revert Claimed();\n hasClaimed[id][msg.sender] = true;\n\n bytes32 hash = keccak256(\n abi.encodePacked(block.chainid, address(this), id, msg.sender, amount, beneficiary, deadline)\n );\n address _signer = ECDSA.recover(ECDSA.toEthSignedMessageHash(hash), v, r, s);\n if (_signer != signer) revert InvalidSignature();\n\n IFSushi(fSushi).mint(beneficiary, amount);\n\n emit Claim(id, name, msg.sender, amount, beneficiary);\n }\n}\n"
},
"contracts/FSushiKitchen.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./interfaces/IFSushiKitchen.sol\";\nimport \"./interfaces/IFlashStrategySushiSwapFactory.sol\";\nimport \"./libraries/Snapshots.sol\";\n\ncontract FSushiKitchen is Ownable, IFSushiKitchen {\n using Snapshots for Snapshots.Snapshot[];\n\n uint256 internal constant BASE = 1e18;\n\n address public immutable override flashStrategyFactory;\n\n Snapshots.Snapshot[] internal _totalWeightPoints;\n mapping(uint256 => Snapshots.Snapshot[]) internal _weightPoints; // pid -> snapshots\n\n constructor(address _flashStrategyFactory) {\n flashStrategyFactory = _flashStrategyFactory;\n }\n\n function totalWeightPointsLength() external view override returns (uint256) {\n return _totalWeightPoints.size();\n }\n\n function weightPointsLength(uint256 pid) external view override returns (uint256) {\n return _weightPoints[pid].size();\n }\n\n function totalWeightPoints() external view override returns (uint256) {\n return _totalWeightPoints.lastValue();\n }\n\n function weightPoints(uint256 pid) external view override returns (uint256) {\n return _weightPoints[pid].lastValue();\n }\n\n function totalWeightPointsAt(uint256 timestamp) external view override returns (uint256) {\n return _totalWeightPoints.valueAt(timestamp);\n }\n\n function weightPointsAt(uint256 pid, uint256 timestamp) external view override returns (uint256) {\n return _weightPoints[pid].valueAt(timestamp);\n }\n\n function relativeWeight(uint256 pid) external view override returns (uint256) {\n uint256 totalPoints = _totalWeightPoints.lastValue();\n if (totalPoints == 0) return 0;\n\n uint256 points = _weightPoints[pid].lastValue();\n return (points * BASE) / totalPoints;\n }\n\n function relativeWeightAt(uint256 pid, uint256 timestamp) external view override returns (uint256) {\n uint256 totalPoints = _totalWeightPoints.valueAt(timestamp);\n if (totalPoints == 0) return 0;\n\n uint256 points = _weightPoints[pid].valueAt(timestamp);\n return (points * BASE) / totalPoints;\n }\n\n function addPool(uint256 pid) external override {\n address strategy = IFlashStrategySushiSwapFactory(flashStrategyFactory).getFlashStrategySushiSwap(pid);\n if (strategy == address(0)) revert InvalidPid();\n\n emit AddPool(pid);\n\n _updateWeight(pid, 100e18);\n }\n\n function updateWeight(uint256 pid, uint256 points) external override onlyOwner {\n if (_weightPoints[pid].size() == 0) revert InvalidPid();\n\n _updateWeight(pid, points);\n }\n\n function _updateWeight(uint256 pid, uint256 points) internal {\n uint256 prev = _weightPoints[pid].lastValue();\n _weightPoints[pid].append(points);\n uint256 totalPoints = _totalWeightPoints.lastValue() + points - prev;\n _totalWeightPoints.append(totalPoints);\n\n emit UpdateWeight(pid, points, totalPoints);\n }\n\n function checkpoint(uint256) external override {\n // Empty: for future compatibility\n }\n}\n"
},
"contracts/libraries/Snapshots.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nlibrary Snapshots {\n error InvalidTimestamp();\n\n struct Snapshot {\n uint256 value;\n uint256 timestamp;\n }\n\n function size(Snapshot[] storage snapshots) internal view returns (uint256) {\n return snapshots.length;\n }\n\n function lastValue(Snapshot[] storage snapshots) internal view returns (uint256) {\n uint256 _length = snapshots.length;\n return _length > 0 ? snapshots[_length - 1].value : 0;\n }\n\n function valueAt(Snapshot[] storage snapshots, uint256 timestamp) internal view returns (uint256) {\n uint256 _now = block.timestamp;\n if (_now < timestamp) revert InvalidTimestamp();\n\n uint256 _length = snapshots.length;\n if (_length == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (snapshots[_length - 1].timestamp <= timestamp) {\n return snapshots[_length - 1].value;\n }\n\n // Next check implicit zero balance\n if (timestamp < snapshots[0].timestamp) {\n return 0;\n }\n\n unchecked {\n uint256 lower = 0;\n uint256 upper = _length - 1;\n while (upper > lower) {\n uint256 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Snapshot memory snapshot = snapshots[center];\n if (snapshot.timestamp == _now) {\n return snapshot.value;\n } else if (snapshot.timestamp < _now) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return snapshots[lower].value;\n }\n }\n\n function append(Snapshot[] storage snapshots, uint256 value) internal {\n snapshots.push(Snapshot(value, block.timestamp));\n }\n}\n"
},
"contracts/mocks/FeeVault.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"../interfaces/IERC20Receiver.sol\";\n\ncontract FeeVault is IERC20Receiver {\n using SafeERC20 for IERC20;\n\n mapping(address => uint256) claimableAmount;\n\n function onReceiveERC20(\n address token,\n address,\n uint256\n ) external {\n claimableAmount[token] = IERC20(token).balanceOf(address(this));\n }\n\n function claim(address token) external {\n uint256 amount = claimableAmount[token];\n claimableAmount[token] = 0;\n\n IERC20(token).safeTransfer(msg.sender, amount);\n }\n}\n"
},
"contracts/SushiBarVault.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport \"./interfaces/ISushiBar.sol\";\n\ncontract SushiBarVault is ERC4626 {\n using SafeERC20 for IERC20;\n\n address internal immutable _sushi;\n address internal immutable _sushiBar;\n\n constructor(address sushi, address sushiBar) ERC4626(IERC20(sushi)) ERC20(\"SushiBar Yield Vault\", \"yxSUSHI\") {\n _sushi = sushi;\n _sushiBar = sushiBar;\n\n approveMax();\n }\n\n function totalAssets() public view override returns (uint256) {\n uint256 total = IERC20(_sushiBar).totalSupply();\n return\n total == 0\n ? 0\n : (IERC20(_sushi).balanceOf(address(_sushiBar)) * IERC20(_sushiBar).balanceOf(address(this))) / total;\n }\n\n function _initialConvertToShares(\n uint256 assets,\n Math.Rounding /*rounding*/\n ) internal view override returns (uint256 shares) {\n uint256 balance = IERC20(_sushi).balanceOf(address(_sushiBar));\n return balance == 0 ? assets : (assets * IERC20(_sushiBar).totalSupply()) / balance;\n }\n\n function _initialConvertToAssets(\n uint256 shares,\n Math.Rounding /*rounding*/\n ) internal view override returns (uint256 assets) {\n uint256 total = IERC20(_sushiBar).totalSupply();\n return total == 0 ? shares : (shares * IERC20(_sushi).balanceOf(address(_sushiBar))) / total;\n }\n\n function approveMax() public {\n IERC20(_sushi).approve(_sushiBar, type(uint256).max);\n }\n\n function _deposit(\n address caller,\n address receiver,\n uint256 assets,\n uint256 shares\n ) internal override {\n IERC20(_sushi).safeTransferFrom(msg.sender, address(this), assets);\n ISushiBar(_sushiBar).enter(assets);\n\n _mint(receiver, shares);\n\n emit Deposit(caller, receiver, assets, shares);\n }\n\n function _withdraw(\n address caller,\n address receiver,\n address owner,\n uint256 assets,\n uint256 shares\n ) internal override {\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n\n _burn(owner, shares);\n\n ISushiBar(_sushiBar).leave(shares);\n IERC20(_sushi).safeTransfer(receiver, assets);\n\n emit Withdraw(caller, receiver, owner, assets, shares);\n }\n}\n"
},
"contracts/interfaces/ISushiBar.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface ISushiBar is IERC20 {\n function sushi() external view returns (IERC20);\n\n function enter(uint256 _amount) external;\n\n function leave(uint256 _share) external;\n}\n"
},
"contracts/mocks/MasterChef.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./SushiToken.sol\";\n\ninterface IMigratorChef {\n // Perform LP token migration from legacy UniswapV2 to SushiSwap.\n // Take the current LP token address and return the new LP token address.\n // Migrator should have full access to the caller's LP token.\n // Return the new LP token address.\n //\n // XXX Migrator must have allowance access to UniswapV2 LP tokens.\n // SushiSwap must mint EXACTLY the same amount of SushiSwap LP tokens or\n // else something bad will happen. Traditional UniswapV2 does not\n // do that so be careful!\n function migrate(IERC20 token) external returns (IERC20);\n}\n\n// MasterChef is the master of Sushi. He can make Sushi and he is a fair guy.\n//\n// Note that it's ownable and the owner wields tremendous power. The ownership\n// will be transferred to a governance smart contract once SUSHI is sufficiently\n// distributed and the community can show to govern itself.\n//\n// Have fun reading it. Hopefully it's bug-free. God bless.\ncontract MasterChef is Ownable {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many LP tokens the user has provided.\n uint256 rewardDebt; // Reward debt. See explanation below.\n //\n // We do some fancy math here. Basically, any point in time, the amount of SUSHIs\n // entitled to a user but is pending to be distributed is:\n //\n // pending reward = (user.amount * pool.accSushiPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accSushiPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the pending reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n }\n // Info of each pool.\n struct PoolInfo {\n IERC20 lpToken; // Address of LP token contract.\n uint256 allocPoint; // How many allocation points assigned to this pool. SUSHIs to distribute per block.\n uint256 lastRewardBlock; // Last block number that SUSHIs distribution occurs.\n uint256 accSushiPerShare; // Accumulated SUSHIs per share, times 1e12. See below.\n }\n // The SUSHI TOKEN!\n SushiToken public sushi;\n // Dev address.\n address public devaddr;\n // Block number when bonus SUSHI period ends.\n uint256 public bonusEndBlock;\n // SUSHI tokens created per block.\n uint256 public sushiPerBlock;\n // Bonus muliplier for early sushi makers.\n uint256 public constant BONUS_MULTIPLIER = 10;\n // The migrator contract. It has a lot of power. Can only be set through governance (owner).\n IMigratorChef public migrator;\n // Info of each pool.\n PoolInfo[] public poolInfo;\n // Info of each user that stakes LP tokens.\n mapping(uint256 => mapping(address => UserInfo)) public userInfo;\n // Total allocation poitns. Must be the sum of all allocation points in all pools.\n uint256 public totalAllocPoint = 0;\n // The block number when SUSHI mining starts.\n uint256 public startBlock;\n event Deposit(address indexed user, uint256 indexed pid, uint256 amount);\n event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);\n event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);\n\n constructor(\n SushiToken _sushi,\n address _devaddr,\n uint256 _sushiPerBlock,\n uint256 _startBlock,\n uint256 _bonusEndBlock\n ) {\n sushi = _sushi;\n devaddr = _devaddr;\n sushiPerBlock = _sushiPerBlock;\n bonusEndBlock = _bonusEndBlock;\n startBlock = _startBlock;\n }\n\n function poolLength() external view returns (uint256) {\n return poolInfo.length;\n }\n\n // Add a new lp to the pool. Can only be called by the owner.\n // XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do.\n function add(\n uint256 _allocPoint,\n IERC20 _lpToken,\n bool _withUpdate\n ) public onlyOwner {\n if (_withUpdate) {\n massUpdatePools();\n }\n uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n totalAllocPoint = totalAllocPoint.add(_allocPoint);\n poolInfo.push(\n PoolInfo({\n lpToken: _lpToken,\n allocPoint: _allocPoint,\n lastRewardBlock: lastRewardBlock,\n accSushiPerShare: 0\n })\n );\n }\n\n // Update the given pool's SUSHI allocation point. Can only be called by the owner.\n function set(\n uint256 _pid,\n uint256 _allocPoint,\n bool _withUpdate\n ) public onlyOwner {\n if (_withUpdate) {\n massUpdatePools();\n }\n totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint);\n poolInfo[_pid].allocPoint = _allocPoint;\n }\n\n // Set the migrator contract. Can only be called by the owner.\n function setMigrator(IMigratorChef _migrator) public onlyOwner {\n migrator = _migrator;\n }\n\n // Migrate lp token to another lp contract. Can be called by anyone. We trust that migrator contract is good.\n function migrate(uint256 _pid) public {\n require(address(migrator) != address(0), \"migrate: no migrator\");\n PoolInfo storage pool = poolInfo[_pid];\n IERC20 lpToken = pool.lpToken;\n uint256 bal = lpToken.balanceOf(address(this));\n lpToken.safeApprove(address(migrator), bal);\n IERC20 newLpToken = migrator.migrate(lpToken);\n require(bal == newLpToken.balanceOf(address(this)), \"migrate: bad\");\n pool.lpToken = newLpToken;\n }\n\n // Return reward multiplier over the given _from to _to block.\n function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) {\n if (_to <= bonusEndBlock) {\n return _to.sub(_from).mul(BONUS_MULTIPLIER);\n } else if (_from >= bonusEndBlock) {\n return _to.sub(_from);\n } else {\n return bonusEndBlock.sub(_from).mul(BONUS_MULTIPLIER).add(_to.sub(bonusEndBlock));\n }\n }\n\n // View function to see pending SUSHIs on frontend.\n function pendingSushi(uint256 _pid, address _user) external view returns (uint256) {\n PoolInfo storage pool = poolInfo[_pid];\n UserInfo storage user = userInfo[_pid][_user];\n uint256 accSushiPerShare = pool.accSushiPerShare;\n uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && lpSupply != 0) {\n uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);\n uint256 sushiReward = multiplier.mul(sushiPerBlock).mul(pool.allocPoint).div(totalAllocPoint);\n accSushiPerShare = accSushiPerShare.add(sushiReward.mul(1e12).div(lpSupply));\n }\n return user.amount.mul(accSushiPerShare).div(1e12).sub(user.rewardDebt);\n }\n\n // Update reward vairables for all pools. Be careful of gas spending!\n function massUpdatePools() public {\n uint256 length = poolInfo.length;\n for (uint256 pid = 0; pid < length; ++pid) {\n updatePool(pid);\n }\n }\n\n // Update reward variables of the given pool to be up-to-date.\n function updatePool(uint256 _pid) public {\n PoolInfo storage pool = poolInfo[_pid];\n if (block.number <= pool.lastRewardBlock) {\n return;\n }\n uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n if (lpSupply == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);\n uint256 sushiReward = multiplier.mul(sushiPerBlock).mul(pool.allocPoint).div(totalAllocPoint);\n sushi.mint(devaddr, sushiReward.div(10));\n sushi.mint(address(this), sushiReward);\n pool.accSushiPerShare = pool.accSushiPerShare.add(sushiReward.mul(1e12).div(lpSupply));\n pool.lastRewardBlock = block.number;\n }\n\n // Deposit LP tokens to MasterChef for SUSHI allocation.\n function deposit(uint256 _pid, uint256 _amount) public {\n PoolInfo storage pool = poolInfo[_pid];\n UserInfo storage user = userInfo[_pid][msg.sender];\n updatePool(_pid);\n if (user.amount > 0) {\n uint256 pending = user.amount.mul(pool.accSushiPerShare).div(1e12).sub(user.rewardDebt);\n safeSushiTransfer(msg.sender, pending);\n }\n pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n user.amount = user.amount.add(_amount);\n user.rewardDebt = user.amount.mul(pool.accSushiPerShare).div(1e12);\n emit Deposit(msg.sender, _pid, _amount);\n }\n\n // Withdraw LP tokens from MasterChef.\n function withdraw(uint256 _pid, uint256 _amount) public {\n PoolInfo storage pool = poolInfo[_pid];\n UserInfo storage user = userInfo[_pid][msg.sender];\n require(user.amount >= _amount, \"withdraw: not good\");\n updatePool(_pid);\n uint256 pending = user.amount.mul(pool.accSushiPerShare).div(1e12).sub(user.rewardDebt);\n safeSushiTransfer(msg.sender, pending);\n user.amount = user.amount.sub(_amount);\n user.rewardDebt = user.amount.mul(pool.accSushiPerShare).div(1e12);\n pool.lpToken.safeTransfer(address(msg.sender), _amount);\n emit Withdraw(msg.sender, _pid, _amount);\n }\n\n // Withdraw without caring about rewards. EMERGENCY ONLY.\n function emergencyWithdraw(uint256 _pid) public {\n PoolInfo storage pool = poolInfo[_pid];\n UserInfo storage user = userInfo[_pid][msg.sender];\n pool.lpToken.safeTransfer(address(msg.sender), user.amount);\n emit EmergencyWithdraw(msg.sender, _pid, user.amount);\n user.amount = 0;\n user.rewardDebt = 0;\n }\n\n // Safe sushi transfer function, just in case if rounding error causes pool to not have enough SUSHIs.\n function safeSushiTransfer(address _to, uint256 _amount) internal {\n uint256 sushiBal = sushi.balanceOf(address(this));\n if (_amount > sushiBal) {\n sushi.transfer(_to, sushiBal);\n } else {\n sushi.transfer(_to, _amount);\n }\n }\n\n // Update dev address by the previous dev.\n function dev(address _devaddr) public {\n require(msg.sender == devaddr, \"dev: wut?\");\n devaddr = _devaddr;\n }\n}\n"
},
"contracts/mocks/SushiToken.sol": {
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n// WARNING: There is a known vuln contained within this contract related to vote delegation,\n// it's NOT recommmended to use this in production.\n\n// SushiToken with Governance.\ncontract SushiToken is ERC20(\"SushiToken\", \"SUSHI\"), Ownable {\n using SafeMath for uint256;\n\n /// @notice Creates `_amount` token to `_to`. Must only be called by the owner (MasterChef).\n function mint(address _to, uint256 _amount) public onlyOwner {\n _mint(_to, _amount);\n _moveDelegates(address(0), _delegates[_to], _amount);\n }\n\n // Copied and modified from YAM code:\n // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernanceStorage.sol\n // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernance.sol\n // Which is copied and modified from COMPOUND:\n // https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol\n\n /// @notice A record of each accounts delegate\n mapping(address => address) internal _delegates;\n\n /// @notice A checkpoint for marking number of votes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint256 votes;\n }\n\n /// @notice A record of votes checkpoints for each account, by index\n mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;\n\n /// @notice The number of checkpoints for each account\n mapping(address => uint32) public numCheckpoints;\n\n /// @notice The EIP-712 typehash for the contract's domain\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n /// @notice A record of states for signing / validating signatures\n mapping(address => uint256) public nonces;\n\n /// @notice An event thats emitted when an account changes its delegate\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n /// @notice An event thats emitted when a delegate account's vote balance changes\n event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);\n\n /**\n * @notice Delegate votes from `msg.sender` to `delegatee`\n * @param delegator The address to get delegatee for\n */\n function delegates(address delegator) external view returns (address) {\n return _delegates[delegator];\n }\n\n /**\n * @notice Delegate votes from `msg.sender` to `delegatee`\n * @param delegatee The address to delegate votes to\n */\n function delegate(address delegatee) external {\n return _delegate(msg.sender, delegatee);\n }\n\n /**\n * @notice Delegates votes from signatory to `delegatee`\n * @param delegatee The address to delegate votes to\n * @param nonce The contract state required to match the signature\n * @param expiry The time at which to expire the signature\n * @param v The recovery byte of the signature\n * @param r Half of the ECDSA signature pair\n * @param s Half of the ECDSA signature pair\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n bytes32 domainSeparator = keccak256(\n abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name())), getChainId(), address(this))\n );\n\n bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));\n\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n\n address signatory = ecrecover(digest, v, r, s);\n require(signatory != address(0), \"SUSHI::delegateBySig: invalid signature\");\n require(nonce == nonces[signatory]++, \"SUSHI::delegateBySig: invalid nonce\");\n require(block.timestamp <= expiry, \"SUSHI::delegateBySig: signature expired\");\n return _delegate(signatory, delegatee);\n }\n\n /**\n * @notice Gets the current votes balance for `account`\n * @param account The address to get votes balance\n * @return The number of current votes for `account`\n */\n function getCurrentVotes(address account) external view returns (uint256) {\n uint32 nCheckpoints = numCheckpoints[account];\n return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;\n }\n\n /**\n * @notice Determine the prior number of votes for an account as of a block number\n * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\n * @param account The address of the account to check\n * @param blockNumber The block number to get the vote balance at\n * @return The number of votes the account had as of the given block\n */\n function getPriorVotes(address account, uint256 blockNumber) external view returns (uint256) {\n require(blockNumber < block.number, \"SUSHI::getPriorVotes: not yet determined\");\n\n uint32 nCheckpoints = numCheckpoints[account];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {\n return checkpoints[account][nCheckpoints - 1].votes;\n }\n\n // Next check implicit zero balance\n if (checkpoints[account][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = checkpoints[account][center];\n if (cp.fromBlock == blockNumber) {\n return cp.votes;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return checkpoints[account][lower].votes;\n }\n\n function _delegate(address delegator, address delegatee) internal {\n address currentDelegate = _delegates[delegator];\n uint256 delegatorBalance = balanceOf(delegator); // balance of underlying SUSHIs (not scaled);\n _delegates[delegator] = delegatee;\n\n emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance);\n }\n\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint256 amount\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) {\n // decrease old representative\n uint32 srcRepNum = numCheckpoints[srcRep];\n uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;\n uint256 srcRepNew = srcRepOld.sub(amount);\n _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);\n }\n\n if (dstRep != address(0)) {\n // increase new representative\n uint32 dstRepNum = numCheckpoints[dstRep];\n uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;\n uint256 dstRepNew = dstRepOld.add(amount);\n _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);\n }\n }\n }\n\n function _writeCheckpoint(\n address delegatee,\n uint32 nCheckpoints,\n uint256 oldVotes,\n uint256 newVotes\n ) internal {\n uint32 blockNumber = safe32(block.number, \"SUSHI::_writeCheckpoint: block number exceeds 32 bits\");\n\n if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {\n checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;\n } else {\n checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);\n numCheckpoints[delegatee] = nCheckpoints + 1;\n }\n\n emit DelegateVotesChanged(delegatee, oldVotes, newVotes);\n }\n\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function getChainId() internal view returns (uint256) {\n return block.chainid;\n }\n}\n"
},
"@openzeppelin/contracts/utils/math/SafeMath.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n"
},
"contracts/mocks/SushiBar.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./libraries/SafeMath.sol\";\n\ncontract SushiBar is ERC20(\"SushiBar\", \"xSUSHI\") {\n using SafeMath for uint256;\n IERC20 public sushi;\n\n constructor(IERC20 _sushi) {\n sushi = _sushi;\n }\n\n // Enter the bar. Pay some SUSHIs. Earn some shares.\n function enter(uint256 _amount) public {\n uint256 totalSushi = sushi.balanceOf(address(this));\n uint256 totalShares = totalSupply();\n if (totalShares == 0 || totalSushi == 0) {\n _mint(msg.sender, _amount);\n } else {\n uint256 what = _amount.mul(totalShares).div(totalSushi);\n _mint(msg.sender, what);\n }\n sushi.transferFrom(msg.sender, address(this), _amount);\n }\n\n // Leave the bar. Claim back your SUSHIs.\n function leave(uint256 _share) public {\n uint256 totalShares = totalSupply();\n uint256 what = _share.mul(sushi.balanceOf(address(this))).div(totalShares);\n _burn(msg.sender, _share);\n sushi.transfer(msg.sender, what);\n }\n}\n"
},
"contracts/mocks/libraries/SafeMath.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\n// a library for performing overflow-safe math, updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math)\nlibrary SafeMath {\n function add(uint256 a, uint256 b) internal pure returns (uint256 c) {\n require((c = a + b) >= b, \"SafeMath: Add Overflow\");\n }\n\n function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {\n require((c = a - b) <= a, \"SafeMath: Underflow\");\n }\n\n function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {\n require(b == 0 || (c = a * b) / b == a, \"SafeMath: Mul Overflow\");\n }\n\n function div(uint256 a, uint256 b) internal pure returns (uint256 c) {\n c = a / b;\n }\n\n function to128(uint256 a) internal pure returns (uint128 c) {\n require(a <= type(uint128).max, \"SafeMath: uint128 Overflow\");\n c = uint128(a);\n }\n}\n\nlibrary SafeMath128 {\n function add(uint128 a, uint128 b) internal pure returns (uint128 c) {\n require((c = a + b) >= b, \"SafeMath: Add Overflow\");\n }\n\n function sub(uint128 a, uint128 b) internal pure returns (uint128 c) {\n require((c = a - b) <= a, \"SafeMath: Underflow\");\n }\n}\n"
},
"contracts/mocks/ERC20Mock.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract ERC20Mock is ERC20 {\n uint8 internal immutable _decimals;\n\n constructor(\n string memory name,\n string memory symbol,\n uint8 __decimals\n ) ERC20(name, symbol) {\n _decimals = __decimals;\n }\n\n function decimals() public view override returns (uint8) {\n return _decimals;\n }\n\n function mint(address account, uint256 amount) public {\n _mint(account, amount);\n }\n\n function burn(address account, uint256 amount) public {\n _burn(account, amount);\n }\n\n function transferInternal(\n address from,\n address to,\n uint256 value\n ) public {\n _transfer(from, to, value);\n }\n\n function approveInternal(\n address owner,\n address spender,\n uint256 value\n ) public {\n _approve(owner, spender, value);\n }\n}\n"
},
"contracts/mocks/interfaces/IERC20.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IERC20Uniswap {\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n function decimals() external view returns (uint8);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address owner) external view returns (uint256);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function transfer(address to, uint256 value) external returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external returns (bool);\n}\n"
},
"contracts/mocks/uniswapv2/interfaces/IWETH.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IWETH {\n function deposit() external payable;\n\n function transfer(address to, uint256 value) external returns (bool);\n\n function withdraw(uint256) external;\n}\n"
},
"contracts/mocks/uniswapv2/interfaces/IUniswapV2Factory.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2Factory {\n event PairCreated(address indexed token0, address indexed token1, address pair, uint256);\n\n function feeTo() external view returns (address);\n\n function feeToSetter() external view returns (address);\n\n function migrator() external view returns (address);\n\n function getPair(address tokenA, address tokenB) external view returns (address pair);\n\n function allPairs(uint256) external view returns (address pair);\n\n function allPairsLength() external view returns (uint256);\n\n function createPair(address tokenA, address tokenB) external returns (address pair);\n\n function setFeeTo(address) external;\n\n function setFeeToSetter(address) external;\n\n function setMigrator(address) external;\n}\n"
},
"contracts/mocks/uniswapv2/interfaces/IUniswapV2Callee.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2Callee {\n function uniswapV2Call(\n address sender,\n uint256 amount0,\n uint256 amount1,\n bytes calldata data\n ) external;\n}\n"
},
"contracts/mocks/uniswapv2/interfaces/IUniswapV2Pair.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2Pair {\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function name() external pure returns (string memory);\n\n function symbol() external pure returns (string memory);\n\n function decimals() external pure returns (uint8);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address owner) external view returns (uint256);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function transfer(address to, uint256 value) external returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external returns (bool);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function PERMIT_TYPEHASH() external pure returns (bytes32);\n\n function nonces(address owner) external view returns (uint256);\n\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 ) external;\n\n event Mint(address indexed sender, uint256 amount0, uint256 amount1);\n event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);\n event Swap(\n address indexed sender,\n uint256 amount0In,\n uint256 amount1In,\n uint256 amount0Out,\n uint256 amount1Out,\n address indexed to\n );\n event Sync(uint112 reserve0, uint112 reserve1);\n\n function MINIMUM_LIQUIDITY() external pure returns (uint256);\n\n function factory() external view returns (address);\n\n function token0() external view returns (address);\n\n function token1() external view returns (address);\n\n function getReserves()\n external\n view\n returns (\n uint112 reserve0,\n uint112 reserve1,\n uint32 blockTimestampLast\n );\n\n function price0CumulativeLast() external view returns (uint256);\n\n function price1CumulativeLast() external view returns (uint256);\n\n function kLast() external view returns (uint256);\n\n function mint(address to) external returns (uint256 liquidity);\n\n function burn(address to) external returns (uint256 amount0, uint256 amount1);\n\n function swap(\n uint256 amount0Out,\n uint256 amount1Out,\n address to,\n bytes calldata data\n ) external;\n\n function skim(address to) external;\n\n function sync() external;\n\n function initialize(address, address) external;\n}\n"
},
"contracts/mocks/uniswapv2/interfaces/IUniswapV2Router02.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.2;\n\nimport \"./IUniswapV2Router01.sol\";\n\ninterface IUniswapV2Router02 is IUniswapV2Router01 {\n function removeLiquidityETHSupportingFeeOnTransferTokens(\n address token,\n uint256 liquidity,\n uint256 amountTokenMin,\n uint256 amountETHMin,\n address to,\n uint256 deadline\n ) external returns (uint256 amountETH);\n\n function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\n address token,\n uint256 liquidity,\n uint256 amountTokenMin,\n uint256 amountETHMin,\n address to,\n uint256 deadline,\n bool approveMax,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external returns (uint256 amountETH);\n\n function swapExactTokensForTokensSupportingFeeOnTransferTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external;\n\n function swapExactETHForTokensSupportingFeeOnTransferTokens(\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external payable;\n\n function swapExactTokensForETHSupportingFeeOnTransferTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external;\n}\n"
},
"contracts/mocks/uniswapv2/interfaces/IUniswapV2Router01.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.2;\n\ninterface IUniswapV2Router01 {\n function factory() external pure returns (address);\n\n function WETH() external pure returns (address);\n\n function addLiquidity(\n address tokenA,\n address tokenB,\n uint256 amountADesired,\n uint256 amountBDesired,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n )\n external\n returns (\n uint256 amountA,\n uint256 amountB,\n uint256 liquidity\n );\n\n function addLiquidityETH(\n address token,\n uint256 amountTokenDesired,\n uint256 amountTokenMin,\n uint256 amountETHMin,\n address to,\n uint256 deadline\n )\n external\n payable\n returns (\n uint256 amountToken,\n uint256 amountETH,\n uint256 liquidity\n );\n\n function removeLiquidity(\n address tokenA,\n address tokenB,\n uint256 liquidity,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline\n ) external returns (uint256 amountA, uint256 amountB);\n\n function removeLiquidityETH(\n address token,\n uint256 liquidity,\n uint256 amountTokenMin,\n uint256 amountETHMin,\n address to,\n uint256 deadline\n ) external returns (uint256 amountToken, uint256 amountETH);\n\n function removeLiquidityWithPermit(\n address tokenA,\n address tokenB,\n uint256 liquidity,\n uint256 amountAMin,\n uint256 amountBMin,\n address to,\n uint256 deadline,\n bool approveMax,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external returns (uint256 amountA, uint256 amountB);\n\n function removeLiquidityETHWithPermit(\n address token,\n uint256 liquidity,\n uint256 amountTokenMin,\n uint256 amountETHMin,\n address to,\n uint256 deadline,\n bool approveMax,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external returns (uint256 amountToken, uint256 amountETH);\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function swapTokensForExactTokens(\n uint256 amountOut,\n uint256 amountInMax,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function swapExactETHForTokens(\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external payable returns (uint256[] memory amounts);\n\n function swapTokensForExactETH(\n uint256 amountOut,\n uint256 amountInMax,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function swapExactTokensForETH(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function swapETHForExactTokens(\n uint256 amountOut,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external payable returns (uint256[] memory amounts);\n\n function quote(\n uint256 amountA,\n uint256 reserveA,\n uint256 reserveB\n ) external pure returns (uint256 amountB);\n\n function getAmountOut(\n uint256 amountIn,\n uint256 reserveIn,\n uint256 reserveOut\n ) external pure returns (uint256 amountOut);\n\n function getAmountIn(\n uint256 amountOut,\n uint256 reserveIn,\n uint256 reserveOut\n ) external pure returns (uint256 amountIn);\n\n function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);\n\n function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts);\n}\n"
},
"contracts/mocks/uniswapv2/libraries/TransferHelper.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.0;\n\n// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false\nlibrary TransferHelper {\n function safeApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n // bytes4(keccak256(bytes('approve(address,uint256)')));\n (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));\n require(success && (data.length == 0 || abi.decode(data, (bool))), \"TransferHelper: APPROVE_FAILED\");\n }\n\n function safeTransfer(\n address token,\n address to,\n uint256 value\n ) internal {\n // bytes4(keccak256(bytes('transfer(address,uint256)')));\n (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));\n require(success && (data.length == 0 || abi.decode(data, (bool))), \"TransferHelper: TRANSFER_FAILED\");\n }\n\n function safeTransferFrom(\n address token,\n address from,\n address to,\n uint256 value\n ) internal {\n // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));\n (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));\n require(success && (data.length == 0 || abi.decode(data, (bool))), \"TransferHelper: TRANSFER_FROM_FAILED\");\n }\n\n function safeTransferETH(address to, uint256 value) internal {\n (bool success, ) = to.call{value: value}(new bytes(0));\n require(success, \"TransferHelper: ETH_TRANSFER_FAILED\");\n }\n}\n"
},
"contracts/mocks/libraries/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\nimport \"../interfaces/IERC20.sol\";\n\nlibrary SafeERC20 {\n function safeSymbol(IERC20Uniswap token) internal view returns (string memory) {\n (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x95d89b41));\n return success && data.length > 0 ? abi.decode(data, (string)) : \"???\";\n }\n\n function safeName(IERC20Uniswap token) internal view returns (string memory) {\n (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x06fdde03));\n return success && data.length > 0 ? abi.decode(data, (string)) : \"???\";\n }\n\n function safeDecimals(IERC20Uniswap token) public view returns (uint8) {\n (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x313ce567));\n return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;\n }\n\n function safeTransfer(\n IERC20Uniswap token,\n address to,\n uint256 amount\n ) internal {\n (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(0xa9059cbb, to, amount));\n require(success && (data.length == 0 || abi.decode(data, (bool))), \"SafeERC20: Transfer failed\");\n }\n\n function safeTransferFrom(\n IERC20Uniswap token,\n address from,\n uint256 amount\n ) internal {\n (bool success, bytes memory data) = address(token).call(\n abi.encodeWithSelector(0x23b872dd, from, address(this), amount)\n );\n require(success && (data.length == 0 || abi.decode(data, (bool))), \"SafeERC20: TransferFrom failed\");\n }\n}\n"
},
"contracts/mocks/uniswapv2/interfaces/IUniswapV2ERC20.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2ERC20 {\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function name() external pure returns (string memory);\n\n function symbol() external pure returns (string memory);\n\n function decimals() external pure returns (uint8);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address owner) external view returns (uint256);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function transfer(address to, uint256 value) external returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external returns (bool);\n\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n function PERMIT_TYPEHASH() external pure returns (bytes32);\n\n function nonces(address owner) external view returns (uint256);\n\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 ) external;\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates",
"devdoc",
"userdoc"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {
"": {
"__CACHE_BREAKER__": "0x00000000d41867734bbee4c6863d9255b2b06ac1"
}
}
}
}