diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9282e829..2088ed21 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,12 +1,26 @@ name: test -on: workflow_dispatch +on: + workflow_dispatch: + pull_request: + push: + branches: [ dev, main ] env: FOUNDRY_PROFILE: ci jobs: check: + # Only run on: pushes to dev/main, PRs to/from branches with 'release' or to dev/main, or manual trigger + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request' && + (github.base_ref == 'dev' || + github.base_ref == 'main' || + contains(github.head_ref, 'release') || + contains(github.base_ref, 'release'))) + strategy: fail-fast: true @@ -20,7 +34,7 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: nightly + version: stable - name: Run Forge build run: | @@ -32,3 +46,86 @@ jobs: run: | forge test -vvv id: test + + upgrade-safety: + # Only run on: pushes to dev/main, PRs to/from branches with 'release' or to dev/main, or manual trigger + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + (github.event_name == 'pull_request' && + (github.base_ref == 'dev' || + github.base_ref == 'main' || + contains(github.head_ref, 'release') || + contains(github.base_ref, 'release'))) + + name: Upgrade Safety Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: stable + + - name: Run upgrade safety validation + run: | + forge clean && forge build + + # Check if previous flattened contracts exist + if [ -d "test/upgrades/previous" ] && ls test/upgrades/previous/*.sol 1> /dev/null 2>&1; then + echo "Previous contracts found, running upgrade validation..." + forge script script/upgrades/ValidateUpgrade.s.sol + else + echo "No previous contracts found, skipping upgrade validation (initial deployment)" + fi + + flatten: + name: Flatten and Track Contracts + runs-on: ubuntu-latest + needs: [check, upgrade-safety] # Only run after tests and validation pass + + # Only run on push to dev branch, not on PRs or main + if: github.event_name == 'push' && github.ref == 'refs/heads/dev' + + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: stable + + - name: Create flattened contracts directory + run: mkdir -p test/upgrades/current + + - name: Flatten all top-level contracts + run: | + # Find all Solidity files directly under src/, not nested + for contract in $(find src -maxdepth 1 -type f -name "*.sol"); do + name=$(basename "$contract") + forge flatten "$contract" > "test/upgrades/current/$name" + done + + # Backup for future upgrade validations + rm -rf test/upgrades/previous + cp -r test/upgrades/current test/upgrades/previous + + echo "Flattened contracts saved to test/upgrades/current/" + echo "Previous version backed up to test/upgrades/previous/" + + + - name: Commit flattened contracts + uses: stefanzweifel/git-auto-commit-action@v5 + with: + file_pattern: test/upgrades/**/*.sol + commit_message: "chore: auto-flatten contracts after validation passes [skip ci]" + push_options: '--follow-tags' \ No newline at end of file diff --git a/lib/bread-token-v2 b/lib/bread-token-v2 index 77710c4f..0c4f55e8 160000 --- a/lib/bread-token-v2 +++ b/lib/bread-token-v2 @@ -1 +1 @@ -Subproject commit 77710c4f9809d0e5cda0c76764a8fd9f1fe65354 +Subproject commit 0c4f55e8c6a3185f774d8e345c465c3a4d97899e diff --git a/script/upgrades/ValidateUpgrade.s.sol b/script/upgrades/ValidateUpgrade.s.sol index 45b58274..33ce658a 100644 --- a/script/upgrades/ValidateUpgrade.s.sol +++ b/script/upgrades/ValidateUpgrade.s.sol @@ -4,13 +4,28 @@ import {Script} from "forge-std/Script.sol"; import {Options} from "openzeppelin-foundry-upgrades/Options.sol"; import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol"; import {YieldDistributor} from "../../src/YieldDistributor.sol"; +import {ButteredBread} from "../../src/ButteredBread.sol"; +import {VotingMultipliers} from "../../src/VotingMultipliers.sol"; -contract DeployYieldDistributor is Script { +contract ValidateUpgrade is Script { function run() external { vm.startBroadcast(); - Options memory opts; - opts.referenceContract = "v1.0.4/YieldDistributor.sol:YieldDistributor"; - Upgrades.validateUpgrade("YieldDistributor.sol:YieldDistributor", opts); + + // Validate YieldDistributor upgrade + Options memory yieldOpts; + yieldOpts.referenceContract = "test/upgrades/previous/YieldDistributor.sol:YieldDistributor"; + Upgrades.validateUpgrade("YieldDistributor.sol:YieldDistributor", yieldOpts); + + // Validate ButteredBread upgrade + Options memory breadOpts; + breadOpts.referenceContract = "test/upgrades/previous/ButteredBread.sol:ButteredBread"; + Upgrades.validateUpgrade("ButteredBread.sol:ButteredBread", breadOpts); + + // Validate VotingMultipliers upgrade + Options memory votingOpts; + votingOpts.referenceContract = "test/upgrades/previous/VotingMultipliers.sol:VotingMultipliers"; + Upgrades.validateUpgrade("VotingMultipliers.sol:VotingMultipliers", votingOpts); + vm.stopBroadcast(); } -} +} \ No newline at end of file diff --git a/test/upgrades/current/ButteredBread.sol b/test/upgrades/current/ButteredBread.sol new file mode 100644 index 00000000..ba37ee96 --- /dev/null +++ b/test/upgrades/current/ButteredBread.sol @@ -0,0 +1,4916 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity =0.8.25 ^0.8.20 ^0.8.25; + +// lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) + +/** + * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. + * + * These functions can be used to verify that a message was signed by the holder + * of the private keys of a given address. + */ +library ECDSA { + enum RecoverError { + NoError, + InvalidSignature, + InvalidSignatureLength, + InvalidSignatureS + } + + /** + * @dev The signature derives the `address(0)`. + */ + error ECDSAInvalidSignature(); + + /** + * @dev The signature has an invalid length. + */ + error ECDSAInvalidSignatureLength(uint256 length); + + /** + * @dev The signature has an S value that is in the upper half order. + */ + error ECDSAInvalidSignatureS(bytes32 s); + + /** + * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not + * return address(0) without also returning an error description. Errors are documented using an enum (error type) + * and a bytes32 providing additional information about the error. + * + * If no error is returned, then the address can be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + * + * Documentation for signature generation: + * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] + * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] + */ + function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { + if (signature.length == 65) { + bytes32 r; + bytes32 s; + uint8 v; + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + /// @solidity memory-safe-assembly + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := byte(0, mload(add(signature, 0x60))) + } + return tryRecover(hash, v, r, s); + } else { + return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature`. This address can then be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + */ + function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. + * + * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] + */ + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { + unchecked { + bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + // We do not check for an overflow here since the shift operation results in 0 or 1. + uint8 v = uint8((uint256(vs) >> 255) + 27); + return tryRecover(hash, v, r, s); + } + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. + */ + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function tryRecover( + bytes32 hash, + uint8 v, + bytes32 r, + bytes32 s + ) internal pure returns (address, RecoverError, bytes32) { + // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature + // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines + // the valid range for s in (301): 0 < s < secp256k1n รท 2 + 1, and for v in (302): v โˆˆ {27, 28}. Most + // signatures from current libraries generate a unique signature with an s-value in the lower half order. + // + // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value + // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or + // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept + // these malleable signatures as well. + if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + return (address(0), RecoverError.InvalidSignatureS, s); + } + + // If the signature is valid (and not malleable), return the signer address + address signer = ecrecover(hash, v, r, s); + if (signer == address(0)) { + return (address(0), RecoverError.InvalidSignature, bytes32(0)); + } + + return (signer, RecoverError.NoError, bytes32(0)); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. + */ + function _throwError(RecoverError error, bytes32 errorArg) private pure { + if (error == RecoverError.NoError) { + return; // no error: do nothing + } else if (error == RecoverError.InvalidSignature) { + revert ECDSAInvalidSignature(); + } else if (error == RecoverError.InvalidSignatureLength) { + revert ECDSAInvalidSignatureLength(uint256(errorArg)); + } else if (error == RecoverError.InvalidSignatureS) { + revert ECDSAInvalidSignatureS(errorArg); + } + } +} + +// src/interfaces/IButteredBread.sol + +/** + * @title `ButteredBread` interface + */ +interface IButteredBread { + /// @notice Occurs when a user does not have sufficient Butter to mint `ButteredBread` + error InsufficientFunds(); + /// @notice Occurs when an invalid value is attempted to be used in setter functions + error InvalidValue(); + /// @notice Occurs when attempting a deposit with a non-sanctioned LP + error NotAllowListed(); + /// @notice Occurs when attempting to delegate `ButteredBrea`d tokens. Delegations are set via the $BREAD contract + error NonDelegatable(); + /// @notice Occurs when attempting to transfer soulbound `ButteredBread` tokens + error NonTransferable(); + /// @notice Occurs when a dependent variable is not set + error UnsetVariable(); + /// @notice Occurs when a transfer fails + error TransferFailed(); + /// @notice Occurs when an amount is 0 + error AmountZero(); + + /// @notice The event emitted when an LP Token (Butter) has been added + event ButterAdded(address _account, address _lp, uint256 _amount); + /// @notice The event emitted when an LP Token (Butter) has been removed + event ButterRemoved(address _account, address _lp, uint256 _amount); + /// @notice Emitted whenever a scaling factor is updated for a sanctioned LP + event ScalingFactorModified(address indexed _lp, uint256 _previousFactor, uint256 _newFactor); + + /** + * @param breadToken Address of `BreadToken` + * @param liquidityPools Sanctioned LPs + * @param scalingFactors Scaling factor on mint per sanctioned LP + * @dev Each scaling factor is a fixed point percent (e.g. 100 = 1X, 150 = 1.5X, 1000 = 10X) + * @param name ERC20 token name + * @param symbol ERC20 token symbol + */ + struct InitData { + address breadToken; + address[] liquidityPools; + uint256[] scalingFactors; + string name; + string symbol; + } + + /** + * @param balance Value of deposited LP tokens (Butter) + * @param scalingFactor At the time of deposit or updated with `syncVotingWeight` function + */ + struct LPData { + uint256 balance; + uint256 scalingFactor; + } + + /// @notice Initialize contract as a `TransparentUpgradeableProxy` + function initialize(InitData calldata _initData) external; + + /// @notice Returns whether a given liquidity pool is Breadchain sanctioned or not + function allowlistedLPs(address _lp) external view returns (bool _allowed); + + /// @notice Returns the factor that determines how much `ButteredBread` should be minted for a Liquidity Pool token (Butter) + function scalingFactors(address _lp) external view returns (uint256 _factor); + + /// @notice Returns the amount of LP tokens (Butter) deposited for an account + function accountToLPBalance(address _account, address _lp) external view returns (uint256 _balance); + + /// @notice Deposits LP tokens (Butter) and mints `ButteredBread` according to the respective LP scaling factor + function deposit(address _lp, uint256 _amount) external; + + /// @notice Withdraws some amount of Butter (LP token) and burns an amount of the user's `ButteredBread` according to the respective scaling factor + function withdraw(address _lp, uint256 _amount) external; + + /// @notice Defines a liquidity pool's status as sanctioned or unsanctioned by Breadchain + function modifyAllowList(address _lp, bool _allowed) external; + + /// @notice Modifies how much `ButteredBread` should be minted for a Liquidity Pool token (Butter) + function modifyScalingFactor(address _lp, uint256 _factor, address[] calldata holders) external; +} + +// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the value of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the value of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves a `value` amount of tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 value) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 value) external returns (bool); + + /** + * @dev Moves a `value` amount of tokens from `from` to `to` using the + * allowance mechanism. `value` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 value) external returns (bool); +} + +// lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) + +interface IERC5267 { + /** + * @dev MAY be emitted to signal that the domain could have changed. + */ + event EIP712DomainChanged(); + + /** + * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 + * signature. + */ + function eip712Domain() + external + view + returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ); +} + +// lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol) + +interface IERC6372 { + /** + * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting). + */ + function clock() external view returns (uint48); + + /** + * @dev Description of the clock + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() external view returns (string memory); +} + +// lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol) + +/** + * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. + */ +interface IVotes { + /** + * @dev The signature used has expired. + */ + error VotesExpiredSignature(uint256 expiry); + + /** + * @dev Emitted when an account changes their delegate. + */ + event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); + + /** + * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units. + */ + event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes); + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) external view returns (uint256); + + /** + * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + */ + function getPastVotes(address account, uint256 timepoint) external view returns (uint256); + + /** + * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + * + * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. + * Votes that have not been delegated are still part of total supply, even though they would not participate in a + * vote. + */ + function getPastTotalSupply(uint256 timepoint) external view returns (uint256); + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) external view returns (address); + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) external; + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external; +} + +// lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ```solidity + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Storage of the initializable contract. + * + * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions + * when using with upgradeable contracts. + * + * @custom:storage-location erc7201:openzeppelin.storage.Initializable + */ + struct InitializableStorage { + /** + * @dev Indicates that the contract has been initialized. + */ + uint64 _initialized; + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool _initializing; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; + + /** + * @dev The contract is already initialized. + */ + error InvalidInitialization(); + + /** + * @dev The contract is not initializing. + */ + error NotInitializing(); + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint64 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any + * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in + * production. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + // Cache values to avoid duplicated sloads + bool isTopLevelCall = !$._initializing; + uint64 initialized = $._initialized; + + // Allowed calls: + // - initialSetup: the contract is not in the initializing state and no previous version was + // initialized + // - construction: the contract is initialized at version 1 (no reininitialization) and the + // current contract is just being deployed + bool initialSetup = initialized == 0 && isTopLevelCall; + bool construction = initialized == 1 && address(this).code.length == 0; + + if (!initialSetup && !construction) { + revert InvalidInitialization(); + } + $._initialized = 1; + if (isTopLevelCall) { + $._initializing = true; + } + _; + if (isTopLevelCall) { + $._initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint64 version) { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing || $._initialized >= version) { + revert InvalidInitialization(); + } + $._initialized = version; + $._initializing = true; + _; + $._initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + _checkInitializing(); + _; + } + + /** + * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. + */ + function _checkInitializing() internal view virtual { + if (!_isInitializing()) { + revert NotInitializing(); + } + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing) { + revert InvalidInitialization(); + } + if ($._initialized != type(uint64).max) { + $._initialized = type(uint64).max; + emit Initialized(type(uint64).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint64) { + return _getInitializableStorage()._initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _getInitializableStorage()._initializing; + } + + /** + * @dev Returns a pointer to the storage namespace. + */ + // solhint-disable-next-line var-name-mixedcase + function _getInitializableStorage() private pure returns (InitializableStorage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + /** + * @dev Muldiv operation overflow. + */ + error MathOverflowedMulDiv(); + + enum Rounding { + Floor, // Toward negative infinity + Ceil, // Toward positive infinity + Trunc, // Toward zero + Expand // Away from zero + } + + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with an overflow flag. + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds towards infinity instead + * of rounding towards zero. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + if (b == 0) { + // Guarantee the same behavior as in a regular Solidity division. + return a / b; + } + + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0. + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by + * Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0 = x * y; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + if (denominator <= prod1) { + revert MathOverflowedMulDiv(); + } + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. + // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. + + uint256 twos = denominator & (0 - denominator); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also + // works in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded + * towards zero. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // โ†’ `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // โ†’ `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256 of a positive value rounded towards zero. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); + } + } + + /** + * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. + */ + function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { + return uint8(rounding) % 2 == 1; + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) +// This file was procedurally generated from scripts/generate/templates/SafeCast.js. + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. `SafeCast` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeCast { + /** + * @dev Value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + + /** + * @dev An int value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedIntToUint(int256 value); + + /** + * @dev Value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); + + /** + * @dev An uint value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedUintToInt(uint256 value); + + /** + * @dev Returns the downcasted uint248 from uint256, reverting on + * overflow (when the input is greater than largest uint248). + * + * Counterpart to Solidity's `uint248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toUint248(uint256 value) internal pure returns (uint248) { + if (value > type(uint248).max) { + revert SafeCastOverflowedUintDowncast(248, value); + } + return uint248(value); + } + + /** + * @dev Returns the downcasted uint240 from uint256, reverting on + * overflow (when the input is greater than largest uint240). + * + * Counterpart to Solidity's `uint240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toUint240(uint256 value) internal pure returns (uint240) { + if (value > type(uint240).max) { + revert SafeCastOverflowedUintDowncast(240, value); + } + return uint240(value); + } + + /** + * @dev Returns the downcasted uint232 from uint256, reverting on + * overflow (when the input is greater than largest uint232). + * + * Counterpart to Solidity's `uint232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toUint232(uint256 value) internal pure returns (uint232) { + if (value > type(uint232).max) { + revert SafeCastOverflowedUintDowncast(232, value); + } + return uint232(value); + } + + /** + * @dev Returns the downcasted uint224 from uint256, reverting on + * overflow (when the input is greater than largest uint224). + * + * Counterpart to Solidity's `uint224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toUint224(uint256 value) internal pure returns (uint224) { + if (value > type(uint224).max) { + revert SafeCastOverflowedUintDowncast(224, value); + } + return uint224(value); + } + + /** + * @dev Returns the downcasted uint216 from uint256, reverting on + * overflow (when the input is greater than largest uint216). + * + * Counterpart to Solidity's `uint216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toUint216(uint256 value) internal pure returns (uint216) { + if (value > type(uint216).max) { + revert SafeCastOverflowedUintDowncast(216, value); + } + return uint216(value); + } + + /** + * @dev Returns the downcasted uint208 from uint256, reverting on + * overflow (when the input is greater than largest uint208). + * + * Counterpart to Solidity's `uint208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toUint208(uint256 value) internal pure returns (uint208) { + if (value > type(uint208).max) { + revert SafeCastOverflowedUintDowncast(208, value); + } + return uint208(value); + } + + /** + * @dev Returns the downcasted uint200 from uint256, reverting on + * overflow (when the input is greater than largest uint200). + * + * Counterpart to Solidity's `uint200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toUint200(uint256 value) internal pure returns (uint200) { + if (value > type(uint200).max) { + revert SafeCastOverflowedUintDowncast(200, value); + } + return uint200(value); + } + + /** + * @dev Returns the downcasted uint192 from uint256, reverting on + * overflow (when the input is greater than largest uint192). + * + * Counterpart to Solidity's `uint192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toUint192(uint256 value) internal pure returns (uint192) { + if (value > type(uint192).max) { + revert SafeCastOverflowedUintDowncast(192, value); + } + return uint192(value); + } + + /** + * @dev Returns the downcasted uint184 from uint256, reverting on + * overflow (when the input is greater than largest uint184). + * + * Counterpart to Solidity's `uint184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toUint184(uint256 value) internal pure returns (uint184) { + if (value > type(uint184).max) { + revert SafeCastOverflowedUintDowncast(184, value); + } + return uint184(value); + } + + /** + * @dev Returns the downcasted uint176 from uint256, reverting on + * overflow (when the input is greater than largest uint176). + * + * Counterpart to Solidity's `uint176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toUint176(uint256 value) internal pure returns (uint176) { + if (value > type(uint176).max) { + revert SafeCastOverflowedUintDowncast(176, value); + } + return uint176(value); + } + + /** + * @dev Returns the downcasted uint168 from uint256, reverting on + * overflow (when the input is greater than largest uint168). + * + * Counterpart to Solidity's `uint168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toUint168(uint256 value) internal pure returns (uint168) { + if (value > type(uint168).max) { + revert SafeCastOverflowedUintDowncast(168, value); + } + return uint168(value); + } + + /** + * @dev Returns the downcasted uint160 from uint256, reverting on + * overflow (when the input is greater than largest uint160). + * + * Counterpart to Solidity's `uint160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toUint160(uint256 value) internal pure returns (uint160) { + if (value > type(uint160).max) { + revert SafeCastOverflowedUintDowncast(160, value); + } + return uint160(value); + } + + /** + * @dev Returns the downcasted uint152 from uint256, reverting on + * overflow (when the input is greater than largest uint152). + * + * Counterpart to Solidity's `uint152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toUint152(uint256 value) internal pure returns (uint152) { + if (value > type(uint152).max) { + revert SafeCastOverflowedUintDowncast(152, value); + } + return uint152(value); + } + + /** + * @dev Returns the downcasted uint144 from uint256, reverting on + * overflow (when the input is greater than largest uint144). + * + * Counterpart to Solidity's `uint144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toUint144(uint256 value) internal pure returns (uint144) { + if (value > type(uint144).max) { + revert SafeCastOverflowedUintDowncast(144, value); + } + return uint144(value); + } + + /** + * @dev Returns the downcasted uint136 from uint256, reverting on + * overflow (when the input is greater than largest uint136). + * + * Counterpart to Solidity's `uint136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toUint136(uint256 value) internal pure returns (uint136) { + if (value > type(uint136).max) { + revert SafeCastOverflowedUintDowncast(136, value); + } + return uint136(value); + } + + /** + * @dev Returns the downcasted uint128 from uint256, reverting on + * overflow (when the input is greater than largest uint128). + * + * Counterpart to Solidity's `uint128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toUint128(uint256 value) internal pure returns (uint128) { + if (value > type(uint128).max) { + revert SafeCastOverflowedUintDowncast(128, value); + } + return uint128(value); + } + + /** + * @dev Returns the downcasted uint120 from uint256, reverting on + * overflow (when the input is greater than largest uint120). + * + * Counterpart to Solidity's `uint120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toUint120(uint256 value) internal pure returns (uint120) { + if (value > type(uint120).max) { + revert SafeCastOverflowedUintDowncast(120, value); + } + return uint120(value); + } + + /** + * @dev Returns the downcasted uint112 from uint256, reverting on + * overflow (when the input is greater than largest uint112). + * + * Counterpart to Solidity's `uint112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toUint112(uint256 value) internal pure returns (uint112) { + if (value > type(uint112).max) { + revert SafeCastOverflowedUintDowncast(112, value); + } + return uint112(value); + } + + /** + * @dev Returns the downcasted uint104 from uint256, reverting on + * overflow (when the input is greater than largest uint104). + * + * Counterpart to Solidity's `uint104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toUint104(uint256 value) internal pure returns (uint104) { + if (value > type(uint104).max) { + revert SafeCastOverflowedUintDowncast(104, value); + } + return uint104(value); + } + + /** + * @dev Returns the downcasted uint96 from uint256, reverting on + * overflow (when the input is greater than largest uint96). + * + * Counterpart to Solidity's `uint96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toUint96(uint256 value) internal pure returns (uint96) { + if (value > type(uint96).max) { + revert SafeCastOverflowedUintDowncast(96, value); + } + return uint96(value); + } + + /** + * @dev Returns the downcasted uint88 from uint256, reverting on + * overflow (when the input is greater than largest uint88). + * + * Counterpart to Solidity's `uint88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toUint88(uint256 value) internal pure returns (uint88) { + if (value > type(uint88).max) { + revert SafeCastOverflowedUintDowncast(88, value); + } + return uint88(value); + } + + /** + * @dev Returns the downcasted uint80 from uint256, reverting on + * overflow (when the input is greater than largest uint80). + * + * Counterpart to Solidity's `uint80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toUint80(uint256 value) internal pure returns (uint80) { + if (value > type(uint80).max) { + revert SafeCastOverflowedUintDowncast(80, value); + } + return uint80(value); + } + + /** + * @dev Returns the downcasted uint72 from uint256, reverting on + * overflow (when the input is greater than largest uint72). + * + * Counterpart to Solidity's `uint72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toUint72(uint256 value) internal pure returns (uint72) { + if (value > type(uint72).max) { + revert SafeCastOverflowedUintDowncast(72, value); + } + return uint72(value); + } + + /** + * @dev Returns the downcasted uint64 from uint256, reverting on + * overflow (when the input is greater than largest uint64). + * + * Counterpart to Solidity's `uint64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toUint64(uint256 value) internal pure returns (uint64) { + if (value > type(uint64).max) { + revert SafeCastOverflowedUintDowncast(64, value); + } + return uint64(value); + } + + /** + * @dev Returns the downcasted uint56 from uint256, reverting on + * overflow (when the input is greater than largest uint56). + * + * Counterpart to Solidity's `uint56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toUint56(uint256 value) internal pure returns (uint56) { + if (value > type(uint56).max) { + revert SafeCastOverflowedUintDowncast(56, value); + } + return uint56(value); + } + + /** + * @dev Returns the downcasted uint48 from uint256, reverting on + * overflow (when the input is greater than largest uint48). + * + * Counterpart to Solidity's `uint48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toUint48(uint256 value) internal pure returns (uint48) { + if (value > type(uint48).max) { + revert SafeCastOverflowedUintDowncast(48, value); + } + return uint48(value); + } + + /** + * @dev Returns the downcasted uint40 from uint256, reverting on + * overflow (when the input is greater than largest uint40). + * + * Counterpart to Solidity's `uint40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toUint40(uint256 value) internal pure returns (uint40) { + if (value > type(uint40).max) { + revert SafeCastOverflowedUintDowncast(40, value); + } + return uint40(value); + } + + /** + * @dev Returns the downcasted uint32 from uint256, reverting on + * overflow (when the input is greater than largest uint32). + * + * Counterpart to Solidity's `uint32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toUint32(uint256 value) internal pure returns (uint32) { + if (value > type(uint32).max) { + revert SafeCastOverflowedUintDowncast(32, value); + } + return uint32(value); + } + + /** + * @dev Returns the downcasted uint24 from uint256, reverting on + * overflow (when the input is greater than largest uint24). + * + * Counterpart to Solidity's `uint24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toUint24(uint256 value) internal pure returns (uint24) { + if (value > type(uint24).max) { + revert SafeCastOverflowedUintDowncast(24, value); + } + return uint24(value); + } + + /** + * @dev Returns the downcasted uint16 from uint256, reverting on + * overflow (when the input is greater than largest uint16). + * + * Counterpart to Solidity's `uint16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toUint16(uint256 value) internal pure returns (uint16) { + if (value > type(uint16).max) { + revert SafeCastOverflowedUintDowncast(16, value); + } + return uint16(value); + } + + /** + * @dev Returns the downcasted uint8 from uint256, reverting on + * overflow (when the input is greater than largest uint8). + * + * Counterpart to Solidity's `uint8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toUint8(uint256 value) internal pure returns (uint8) { + if (value > type(uint8).max) { + revert SafeCastOverflowedUintDowncast(8, value); + } + return uint8(value); + } + + /** + * @dev Converts a signed int256 into an unsigned uint256. + * + * Requirements: + * + * - input must be greater than or equal to 0. + */ + function toUint256(int256 value) internal pure returns (uint256) { + if (value < 0) { + revert SafeCastOverflowedIntToUint(value); + } + return uint256(value); + } + + /** + * @dev Returns the downcasted int248 from int256, reverting on + * overflow (when the input is less than smallest int248 or + * greater than largest int248). + * + * Counterpart to Solidity's `int248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toInt248(int256 value) internal pure returns (int248 downcasted) { + downcasted = int248(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(248, value); + } + } + + /** + * @dev Returns the downcasted int240 from int256, reverting on + * overflow (when the input is less than smallest int240 or + * greater than largest int240). + * + * Counterpart to Solidity's `int240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toInt240(int256 value) internal pure returns (int240 downcasted) { + downcasted = int240(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(240, value); + } + } + + /** + * @dev Returns the downcasted int232 from int256, reverting on + * overflow (when the input is less than smallest int232 or + * greater than largest int232). + * + * Counterpart to Solidity's `int232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toInt232(int256 value) internal pure returns (int232 downcasted) { + downcasted = int232(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(232, value); + } + } + + /** + * @dev Returns the downcasted int224 from int256, reverting on + * overflow (when the input is less than smallest int224 or + * greater than largest int224). + * + * Counterpart to Solidity's `int224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toInt224(int256 value) internal pure returns (int224 downcasted) { + downcasted = int224(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(224, value); + } + } + + /** + * @dev Returns the downcasted int216 from int256, reverting on + * overflow (when the input is less than smallest int216 or + * greater than largest int216). + * + * Counterpart to Solidity's `int216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toInt216(int256 value) internal pure returns (int216 downcasted) { + downcasted = int216(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(216, value); + } + } + + /** + * @dev Returns the downcasted int208 from int256, reverting on + * overflow (when the input is less than smallest int208 or + * greater than largest int208). + * + * Counterpart to Solidity's `int208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toInt208(int256 value) internal pure returns (int208 downcasted) { + downcasted = int208(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(208, value); + } + } + + /** + * @dev Returns the downcasted int200 from int256, reverting on + * overflow (when the input is less than smallest int200 or + * greater than largest int200). + * + * Counterpart to Solidity's `int200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toInt200(int256 value) internal pure returns (int200 downcasted) { + downcasted = int200(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(200, value); + } + } + + /** + * @dev Returns the downcasted int192 from int256, reverting on + * overflow (when the input is less than smallest int192 or + * greater than largest int192). + * + * Counterpart to Solidity's `int192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toInt192(int256 value) internal pure returns (int192 downcasted) { + downcasted = int192(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(192, value); + } + } + + /** + * @dev Returns the downcasted int184 from int256, reverting on + * overflow (when the input is less than smallest int184 or + * greater than largest int184). + * + * Counterpart to Solidity's `int184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toInt184(int256 value) internal pure returns (int184 downcasted) { + downcasted = int184(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(184, value); + } + } + + /** + * @dev Returns the downcasted int176 from int256, reverting on + * overflow (when the input is less than smallest int176 or + * greater than largest int176). + * + * Counterpart to Solidity's `int176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toInt176(int256 value) internal pure returns (int176 downcasted) { + downcasted = int176(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(176, value); + } + } + + /** + * @dev Returns the downcasted int168 from int256, reverting on + * overflow (when the input is less than smallest int168 or + * greater than largest int168). + * + * Counterpart to Solidity's `int168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toInt168(int256 value) internal pure returns (int168 downcasted) { + downcasted = int168(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(168, value); + } + } + + /** + * @dev Returns the downcasted int160 from int256, reverting on + * overflow (when the input is less than smallest int160 or + * greater than largest int160). + * + * Counterpart to Solidity's `int160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toInt160(int256 value) internal pure returns (int160 downcasted) { + downcasted = int160(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(160, value); + } + } + + /** + * @dev Returns the downcasted int152 from int256, reverting on + * overflow (when the input is less than smallest int152 or + * greater than largest int152). + * + * Counterpart to Solidity's `int152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toInt152(int256 value) internal pure returns (int152 downcasted) { + downcasted = int152(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(152, value); + } + } + + /** + * @dev Returns the downcasted int144 from int256, reverting on + * overflow (when the input is less than smallest int144 or + * greater than largest int144). + * + * Counterpart to Solidity's `int144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toInt144(int256 value) internal pure returns (int144 downcasted) { + downcasted = int144(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(144, value); + } + } + + /** + * @dev Returns the downcasted int136 from int256, reverting on + * overflow (when the input is less than smallest int136 or + * greater than largest int136). + * + * Counterpart to Solidity's `int136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toInt136(int256 value) internal pure returns (int136 downcasted) { + downcasted = int136(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(136, value); + } + } + + /** + * @dev Returns the downcasted int128 from int256, reverting on + * overflow (when the input is less than smallest int128 or + * greater than largest int128). + * + * Counterpart to Solidity's `int128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toInt128(int256 value) internal pure returns (int128 downcasted) { + downcasted = int128(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(128, value); + } + } + + /** + * @dev Returns the downcasted int120 from int256, reverting on + * overflow (when the input is less than smallest int120 or + * greater than largest int120). + * + * Counterpart to Solidity's `int120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toInt120(int256 value) internal pure returns (int120 downcasted) { + downcasted = int120(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(120, value); + } + } + + /** + * @dev Returns the downcasted int112 from int256, reverting on + * overflow (when the input is less than smallest int112 or + * greater than largest int112). + * + * Counterpart to Solidity's `int112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toInt112(int256 value) internal pure returns (int112 downcasted) { + downcasted = int112(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(112, value); + } + } + + /** + * @dev Returns the downcasted int104 from int256, reverting on + * overflow (when the input is less than smallest int104 or + * greater than largest int104). + * + * Counterpart to Solidity's `int104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toInt104(int256 value) internal pure returns (int104 downcasted) { + downcasted = int104(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(104, value); + } + } + + /** + * @dev Returns the downcasted int96 from int256, reverting on + * overflow (when the input is less than smallest int96 or + * greater than largest int96). + * + * Counterpart to Solidity's `int96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toInt96(int256 value) internal pure returns (int96 downcasted) { + downcasted = int96(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(96, value); + } + } + + /** + * @dev Returns the downcasted int88 from int256, reverting on + * overflow (when the input is less than smallest int88 or + * greater than largest int88). + * + * Counterpart to Solidity's `int88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toInt88(int256 value) internal pure returns (int88 downcasted) { + downcasted = int88(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(88, value); + } + } + + /** + * @dev Returns the downcasted int80 from int256, reverting on + * overflow (when the input is less than smallest int80 or + * greater than largest int80). + * + * Counterpart to Solidity's `int80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toInt80(int256 value) internal pure returns (int80 downcasted) { + downcasted = int80(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(80, value); + } + } + + /** + * @dev Returns the downcasted int72 from int256, reverting on + * overflow (when the input is less than smallest int72 or + * greater than largest int72). + * + * Counterpart to Solidity's `int72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toInt72(int256 value) internal pure returns (int72 downcasted) { + downcasted = int72(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(72, value); + } + } + + /** + * @dev Returns the downcasted int64 from int256, reverting on + * overflow (when the input is less than smallest int64 or + * greater than largest int64). + * + * Counterpart to Solidity's `int64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toInt64(int256 value) internal pure returns (int64 downcasted) { + downcasted = int64(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(64, value); + } + } + + /** + * @dev Returns the downcasted int56 from int256, reverting on + * overflow (when the input is less than smallest int56 or + * greater than largest int56). + * + * Counterpart to Solidity's `int56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toInt56(int256 value) internal pure returns (int56 downcasted) { + downcasted = int56(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(56, value); + } + } + + /** + * @dev Returns the downcasted int48 from int256, reverting on + * overflow (when the input is less than smallest int48 or + * greater than largest int48). + * + * Counterpart to Solidity's `int48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toInt48(int256 value) internal pure returns (int48 downcasted) { + downcasted = int48(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(48, value); + } + } + + /** + * @dev Returns the downcasted int40 from int256, reverting on + * overflow (when the input is less than smallest int40 or + * greater than largest int40). + * + * Counterpart to Solidity's `int40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toInt40(int256 value) internal pure returns (int40 downcasted) { + downcasted = int40(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(40, value); + } + } + + /** + * @dev Returns the downcasted int32 from int256, reverting on + * overflow (when the input is less than smallest int32 or + * greater than largest int32). + * + * Counterpart to Solidity's `int32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toInt32(int256 value) internal pure returns (int32 downcasted) { + downcasted = int32(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(32, value); + } + } + + /** + * @dev Returns the downcasted int24 from int256, reverting on + * overflow (when the input is less than smallest int24 or + * greater than largest int24). + * + * Counterpart to Solidity's `int24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toInt24(int256 value) internal pure returns (int24 downcasted) { + downcasted = int24(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(24, value); + } + } + + /** + * @dev Returns the downcasted int16 from int256, reverting on + * overflow (when the input is less than smallest int16 or + * greater than largest int16). + * + * Counterpart to Solidity's `int16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toInt16(int256 value) internal pure returns (int16 downcasted) { + downcasted = int16(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(16, value); + } + } + + /** + * @dev Returns the downcasted int8 from int256, reverting on + * overflow (when the input is less than smallest int8 or + * greater than largest int8). + * + * Counterpart to Solidity's `int8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toInt8(int256 value) internal pure returns (int8 downcasted) { + downcasted = int8(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(8, value); + } + } + + /** + * @dev Converts an unsigned uint256 into a signed int256. + * + * Requirements: + * + * - input must be less than or equal to maxInt256. + */ + function toInt256(uint256 value) internal pure returns (int256) { + // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive + if (value > uint256(type(int256).max)) { + revert SafeCastOverflowedUintToInt(value); + } + return int256(value); + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } + } +} + +// lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) + +/** + * @dev Standard ERC20 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. + */ +interface IERC20Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC20InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC20InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `spender`โ€™s `allowance`. Used in transfers. + * @param spender Address that may be allowed to operate on tokens without being their owner. + * @param allowance Amount of tokens a `spender` is allowed to operate with. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC20InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `spender` to be approved. Used in approvals. + * @param spender Address that may be allowed to operate on tokens without being their owner. + */ + error ERC20InvalidSpender(address spender); +} + +/** + * @dev Standard ERC721 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. + */ +interface IERC721Errors { + /** + * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. + * Used in balance queries. + * @param owner Address of the current owner of a token. + */ + error ERC721InvalidOwner(address owner); + + /** + * @dev Indicates a `tokenId` whose `owner` is the zero address. + * @param tokenId Identifier number of a token. + */ + error ERC721NonexistentToken(uint256 tokenId); + + /** + * @dev Indicates an error related to the ownership over a particular token. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param tokenId Identifier number of a token. + * @param owner Address of the current owner of a token. + */ + error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC721InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC721InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`โ€™s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param tokenId Identifier number of a token. + */ + error ERC721InsufficientApproval(address operator, uint256 tokenId); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC721InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC721InvalidOperator(address operator); +} + +/** + * @dev Standard ERC1155 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. + */ +interface IERC1155Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + * @param tokenId Identifier number of a token. + */ + error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC1155InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC1155InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`โ€™s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param owner Address of the current owner of a token. + */ + error ERC1155MissingApprovalForAll(address operator, address owner); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC1155InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC1155InvalidOperator(address operator); + + /** + * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. + * Used in batch transfers. + * @param idsLength Length of the array of token identifiers + * @param valuesLength Length of the array of token amounts + */ + error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); +} + +// lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol) +// This file was procedurally generated from scripts/generate/templates/Checkpoints.js. + +/** + * @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + */ +library Checkpoints { + /** + * @dev A value was attempted to be inserted on a past checkpoint. + */ + error CheckpointUnorderedInsertion(); + + struct Trace224 { + Checkpoint224[] _checkpoints; + } + + struct Checkpoint224 { + uint32 _key; + uint224 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the + * library. + */ + function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if + * there is none. + */ + function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + */ + function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + * + * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high + * keys). + */ + function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) { + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._key) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ + function latest(Trace224 storage self) internal view returns (uint224) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace224 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint224 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint224({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint224({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` + * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive + * `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or + * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and + * exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _lowerBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint224[] storage self, + uint256 pos + ) private pure returns (Checkpoint224 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace208 { + Checkpoint208[] _checkpoints; + } + + struct Checkpoint208 { + uint48 _key; + uint208 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the + * library. + */ + function push(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if + * there is none. + */ + function lowerLookup(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + */ + function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + * + * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high + * keys). + */ + function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._key) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ + function latest(Trace208 storage self) internal view returns (uint208) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint208 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace208 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint208[] storage self, uint48 key, uint208 value) private returns (uint208, uint208) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint208 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint208({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint208({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` + * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive + * `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Checkpoint208[] storage self, + uint48 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or + * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and + * exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _lowerBinaryLookup( + Checkpoint208[] storage self, + uint48 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint208[] storage self, + uint256 pos + ) private pure returns (Checkpoint208 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace160 { + Checkpoint160[] _checkpoints; + } + + struct Checkpoint160 { + uint96 _key; + uint160 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the + * library. + */ + function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if + * there is none. + */ + function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + */ + function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + * + * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high + * keys). + */ + function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) { + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._key) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ + function latest(Trace160 storage self) internal view returns (uint160) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace160 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint160 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint160({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint160({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` + * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive + * `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or + * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and + * exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _lowerBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint160[] storage self, + uint256 pos + ) private pure returns (Checkpoint160 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract ContextUpgradeable is Initializable { + function __Context_init() internal onlyInitializing { + } + + function __Context_init_unchained() internal onlyInitializing { + } + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } + + function _contextSuffixLength() internal view virtual returns (uint256) { + return 0; + } +} + +// lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} + +// src/interfaces/IERC20Votes.sol + +interface IERC20Votes is IERC20 { + /** + * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based + * checkpoints (and voting), in which case {CLOCK_MODE} should be overridden as well to match. + */ + function clock() external returns (uint48); + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) external view returns (address); + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) external; + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external; + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) external returns (uint256); + + /** + * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + */ + function getPastVotes(address account, uint256 timepoint) external returns (uint256); + + /** + * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + */ + function getPastTotalSupply(uint256 timepoint) external returns (uint256); +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/NoncesUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol) + +/** + * @dev Provides tracking nonces for addresses. Nonces will only increment. + */ +abstract contract NoncesUpgradeable is Initializable { + /** + * @dev The nonce used for an `account` is not the expected current nonce. + */ + error InvalidAccountNonce(address account, uint256 currentNonce); + + /// @custom:storage-location erc7201:openzeppelin.storage.Nonces + struct NoncesStorage { + mapping(address account => uint256) _nonces; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Nonces")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant NoncesStorageLocation = 0x5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00; + + function _getNoncesStorage() private pure returns (NoncesStorage storage $) { + assembly { + $.slot := NoncesStorageLocation + } + } + + function __Nonces_init() internal onlyInitializing { + } + + function __Nonces_init_unchained() internal onlyInitializing { + } + /** + * @dev Returns the next unused nonce for an address. + */ + function nonces(address owner) public view virtual returns (uint256) { + NoncesStorage storage $ = _getNoncesStorage(); + return $._nonces[owner]; + } + + /** + * @dev Consumes a nonce. + * + * Returns the current value and increments nonce. + */ + function _useNonce(address owner) internal virtual returns (uint256) { + NoncesStorage storage $ = _getNoncesStorage(); + // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be + // decremented or reset. This guarantees that the nonce never overflows. + unchecked { + // It is important to do x++ and not ++x here. + return $._nonces[owner]++; + } + } + + /** + * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. + */ + function _useCheckedNonce(address owner, uint256 nonce) internal virtual { + uint256 current = _useNonce(owner); + if (nonce != current) { + revert InvalidAccountNonce(owner, current); + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuardUpgradeable is Initializable { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant NOT_ENTERED = 1; + uint256 private constant ENTERED = 2; + + /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard + struct ReentrancyGuardStorage { + uint256 _status; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; + + function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { + assembly { + $.slot := ReentrancyGuardStorageLocation + } + } + + /** + * @dev Unauthorized reentrant call. + */ + error ReentrancyGuardReentrantCall(); + + function __ReentrancyGuard_init() internal onlyInitializing { + __ReentrancyGuard_init_unchained(); + } + + function __ReentrancyGuard_init_unchained() internal onlyInitializing { + ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); + $._status = NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + _nonReentrantBefore(); + _; + _nonReentrantAfter(); + } + + function _nonReentrantBefore() private { + ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); + // On the first call to nonReentrant, _status will be NOT_ENTERED + if ($._status == ENTERED) { + revert ReentrancyGuardReentrantCall(); + } + + // Any calls to nonReentrant after this point will fail + $._status = ENTERED; + } + + function _nonReentrantAfter() private { + ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + $._status = NOT_ENTERED; + } + + /** + * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a + * `nonReentrant` function in the call stack. + */ + function _reentrancyGuardEntered() internal view returns (bool) { + ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); + return $._status == ENTERED; + } +} + +// lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5805.sol) + +interface IERC5805 is IERC6372, IVotes {} + +// lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is set to the address provided by the deployer. This can + * later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { + /// @custom:storage-location erc7201:openzeppelin.storage.Ownable + struct OwnableStorage { + address _owner; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; + + function _getOwnableStorage() private pure returns (OwnableStorage storage $) { + assembly { + $.slot := OwnableStorageLocation + } + } + + /** + * @dev The caller account is not authorized to perform an operation. + */ + error OwnableUnauthorizedAccount(address account); + + /** + * @dev The owner is not a valid owner account. (eg. `address(0)`) + */ + error OwnableInvalidOwner(address owner); + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the address provided by the deployer as the initial owner. + */ + function __Ownable_init(address initialOwner) internal onlyInitializing { + __Ownable_init_unchained(initialOwner); + } + + function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { + if (initialOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(initialOwner); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + OwnableStorage storage $ = _getOwnableStorage(); + return $._owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + if (owner() != _msgSender()) { + revert OwnableUnauthorizedAccount(_msgSender()); + } + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + if (newOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + OwnableStorage storage $ = _getOwnableStorage(); + address oldOwner = $._owner; + $._owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + +// lib/openzeppelin-contracts/contracts/utils/Strings.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant HEX_DIGITS = "0123456789abcdef"; + uint8 private constant ADDRESS_LENGTH = 20; + + /** + * @dev The `value` string doesn't fit in the specified `length`. + */ + error StringsInsufficientHexLength(uint256 value, uint256 length); + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toStringSigned(int256 value) internal pure returns (string memory) { + return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + uint256 localValue = value; + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = HEX_DIGITS[localValue & 0xf]; + localValue >>= 4; + } + if (localValue != 0) { + revert StringsInsufficientHexLength(value, length); + } + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal + * representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); + } +} + +// lib/openzeppelin-contracts/contracts/utils/types/Time.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol) + +/** + * @dev This library provides helpers for manipulating time-related objects. + * + * It uses the following types: + * - `uint48` for timepoints + * - `uint32` for durations + * + * While the library doesn't provide specific types for timepoints and duration, it does provide: + * - a `Delay` type to represent duration that can be programmed to change value automatically at a given point + * - additional helper functions + */ +library Time { + using Time for *; + + /** + * @dev Get the block timestamp as a Timepoint. + */ + function timestamp() internal view returns (uint48) { + return SafeCast.toUint48(block.timestamp); + } + + /** + * @dev Get the block number as a Timepoint. + */ + function blockNumber() internal view returns (uint48) { + return SafeCast.toUint48(block.number); + } + + // ==================================================== Delay ===================================================== + /** + * @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the + * future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value. + * This allows updating the delay applied to some operation while keeping some guarantees. + * + * In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for + * some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set + * the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should + * still apply for some time. + * + * + * The `Delay` type is 112 bits long, and packs the following: + * + * ``` + * | [uint48]: effect date (timepoint) + * | | [uint32]: value before (duration) + * โ†“ โ†“ โ†“ [uint32]: value after (duration) + * 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC + * ``` + * + * NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently + * supported. + */ + type Delay is uint112; + + /** + * @dev Wrap a duration into a Delay to add the one-step "update in the future" feature + */ + function toDelay(uint32 duration) internal pure returns (Delay) { + return Delay.wrap(duration); + } + + /** + * @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled + * change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered. + */ + function _getFullAt(Delay self, uint48 timepoint) private pure returns (uint32, uint32, uint48) { + (uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack(); + return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect); + } + + /** + * @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the + * effect timepoint is 0, then the pending value should not be considered. + */ + function getFull(Delay self) internal view returns (uint32, uint32, uint48) { + return _getFullAt(self, timestamp()); + } + + /** + * @dev Get the current value. + */ + function get(Delay self) internal view returns (uint32) { + (uint32 delay, , ) = self.getFull(); + return delay; + } + + /** + * @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to + * enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the + * new delay becomes effective. + */ + function withUpdate( + Delay self, + uint32 newValue, + uint32 minSetback + ) internal view returns (Delay updatedDelay, uint48 effect) { + uint32 value = self.get(); + uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0)); + effect = timestamp() + setback; + return (pack(value, newValue, effect), effect); + } + + /** + * @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint). + */ + function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) { + uint112 raw = Delay.unwrap(self); + + valueAfter = uint32(raw); + valueBefore = uint32(raw >> 32); + effect = uint48(raw >> 64); + + return (valueBefore, valueAfter, effect); + } + + /** + * @dev pack the components into a Delay object. + */ + function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) { + return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter)); + } +} + +// lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) + +/** + * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. + * + * The library provides methods for generating a hash of a message that conforms to the + * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] + * specifications. + */ +library MessageHashUtils { + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x45` (`personal_sign` messages). + * + * The digest is calculated by prefixing a bytes32 `messageHash` with + * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the + * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. + * + * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with + * keccak256, although any bytes32 value can be safely used because the final digest will + * be re-hashed. + * + * See {ECDSA-recover}. + */ + function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash + mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix + digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) + } + } + + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x45` (`personal_sign` messages). + * + * The digest is calculated by prefixing an arbitrary `message` with + * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the + * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. + * + * See {ECDSA-recover}. + */ + function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { + return + keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); + } + + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x00` (data with intended validator). + * + * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended + * `validator` address. Then hashing the result. + * + * See {ECDSA-recover}. + */ + function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(hex"19_00", validator, data)); + } + + /** + * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). + * + * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with + * `\x19\x01` and hashing the result. It corresponds to the hash signed by the + * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. + * + * See {ECDSA-recover}. + */ + function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) + mstore(ptr, hex"19_01") + mstore(add(ptr, 0x02), domainSeparator) + mstore(add(ptr, 0x22), structHash) + digest := keccak256(ptr, 0x42) + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/access/Ownable2StepUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) + +/** + * @dev Contract module which provides access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is specified at deployment time in the constructor for `Ownable`. This + * can later be changed with {transferOwnership} and {acceptOwnership}. + * + * This module is used through inheritance. It will make available all functions + * from parent (Ownable). + */ +abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable { + /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step + struct Ownable2StepStorage { + address _pendingOwner; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00; + + function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) { + assembly { + $.slot := Ownable2StepStorageLocation + } + } + + event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); + + function __Ownable2Step_init() internal onlyInitializing { + } + + function __Ownable2Step_init_unchained() internal onlyInitializing { + } + /** + * @dev Returns the address of the pending owner. + */ + function pendingOwner() public view virtual returns (address) { + Ownable2StepStorage storage $ = _getOwnable2StepStorage(); + return $._pendingOwner; + } + + /** + * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual override onlyOwner { + Ownable2StepStorage storage $ = _getOwnable2StepStorage(); + $._pendingOwner = newOwner; + emit OwnershipTransferStarted(owner(), newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual override { + Ownable2StepStorage storage $ = _getOwnable2StepStorage(); + delete $._pendingOwner; + super._transferOwnership(newOwner); + } + + /** + * @dev The new owner accepts the ownership transfer. + */ + function acceptOwnership() public virtual { + address sender = _msgSender(); + if (pendingOwner() != sender) { + revert OwnableUnauthorizedAccount(sender); + } + _transferOwnership(sender); + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC20 + * applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + */ +abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors { + /// @custom:storage-location erc7201:openzeppelin.storage.ERC20 + struct ERC20Storage { + mapping(address account => uint256) _balances; + + mapping(address account => mapping(address spender => uint256)) _allowances; + + uint256 _totalSupply; + + string _name; + string _symbol; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00; + + function _getERC20Storage() private pure returns (ERC20Storage storage $) { + assembly { + $.slot := ERC20StorageLocation + } + } + + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { + __ERC20_init_unchained(name_, symbol_); + } + + function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { + ERC20Storage storage $ = _getERC20Storage(); + $._name = name_; + $._symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual returns (string memory) { + ERC20Storage storage $ = _getERC20Storage(); + return $._name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual returns (string memory) { + ERC20Storage storage $ = _getERC20Storage(); + return $._symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual returns (uint256) { + ERC20Storage storage $ = _getERC20Storage(); + return $._totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual returns (uint256) { + ERC20Storage storage $ = _getERC20Storage(); + return $._balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `value`. + */ + function transfer(address to, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, value); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual returns (uint256) { + ERC20Storage storage $ = _getERC20Storage(); + return $._allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, value); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `value`. + * - the caller must have allowance for ``from``'s tokens of at least + * `value`. + */ + function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, value); + _transfer(from, to, value); + return true; + } + + /** + * @dev Moves a `value` amount of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _transfer(address from, address to, uint256 value) internal { + if (from == address(0)) { + revert ERC20InvalidSender(address(0)); + } + if (to == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(from, to, value); + } + + /** + * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding + * this function. + * + * Emits a {Transfer} event. + */ + function _update(address from, address to, uint256 value) internal virtual { + ERC20Storage storage $ = _getERC20Storage(); + if (from == address(0)) { + // Overflow check required: The rest of the code assumes that totalSupply never overflows + $._totalSupply += value; + } else { + uint256 fromBalance = $._balances[from]; + if (fromBalance < value) { + revert ERC20InsufficientBalance(from, fromBalance, value); + } + unchecked { + // Overflow not possible: value <= fromBalance <= totalSupply. + $._balances[from] = fromBalance - value; + } + } + + if (to == address(0)) { + unchecked { + // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. + $._totalSupply -= value; + } + } else { + unchecked { + // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. + $._balances[to] += value; + } + } + + emit Transfer(from, to, value); + } + + /** + * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). + * Relies on the `_update` mechanism + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _mint(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(address(0), account, value); + } + + /** + * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead + */ + function _burn(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidSender(address(0)); + } + _update(account, address(0), value); + } + + /** + * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + * + * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. + */ + function _approve(address owner, address spender, uint256 value) internal { + _approve(owner, spender, value, true); + } + + /** + * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. + * + * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by + * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any + * `Approval` event during `transferFrom` operations. + * + * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to + * true using the following override: + * ``` + * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { + * super._approve(owner, spender, value, true); + * } + * ``` + * + * Requirements are the same as {_approve}. + */ + function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { + ERC20Storage storage $ = _getERC20Storage(); + if (owner == address(0)) { + revert ERC20InvalidApprover(address(0)); + } + if (spender == address(0)) { + revert ERC20InvalidSpender(address(0)); + } + $._allowances[owner][spender] = value; + if (emitEvent) { + emit Approval(owner, spender, value); + } + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `value`. + * + * Does not update the allowance value in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Does not emit an {Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 value) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + if (currentAllowance < value) { + revert ERC20InsufficientAllowance(spender, currentAllowance, value); + } + unchecked { + _approve(owner, spender, currentAllowance - value, false); + } + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol) + +/** + * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. + * + * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose + * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract + * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to + * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. + * + * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding + * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA + * ({_hashTypedDataV4}). + * + * The implementation of the domain separator was designed to be as efficient as possible while still properly updating + * the chain id to protect against replay attacks on an eventual fork of the chain. + * + * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method + * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. + * + * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain + * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the + * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. + */ +abstract contract EIP712Upgradeable is Initializable, IERC5267 { + bytes32 private constant TYPE_HASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + + /// @custom:storage-location erc7201:openzeppelin.storage.EIP712 + struct EIP712Storage { + /// @custom:oz-renamed-from _HASHED_NAME + bytes32 _hashedName; + /// @custom:oz-renamed-from _HASHED_VERSION + bytes32 _hashedVersion; + + string _name; + string _version; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.EIP712")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100; + + function _getEIP712Storage() private pure returns (EIP712Storage storage $) { + assembly { + $.slot := EIP712StorageLocation + } + } + + /** + * @dev Initializes the domain separator and parameter caches. + * + * The meaning of `name` and `version` is specified in + * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: + * + * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. + * - `version`: the current major version of the signing domain. + * + * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart + * contract upgrade]. + */ + function __EIP712_init(string memory name, string memory version) internal onlyInitializing { + __EIP712_init_unchained(name, version); + } + + function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { + EIP712Storage storage $ = _getEIP712Storage(); + $._name = name; + $._version = version; + + // Reset prior values in storage if upgrading + $._hashedName = 0; + $._hashedVersion = 0; + } + + /** + * @dev Returns the domain separator for the current chain. + */ + function _domainSeparatorV4() internal view returns (bytes32) { + return _buildDomainSeparator(); + } + + function _buildDomainSeparator() private view returns (bytes32) { + return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this))); + } + + /** + * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this + * function returns the hash of the fully encoded EIP712 message for this domain. + * + * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: + * + * ```solidity + * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( + * keccak256("Mail(address to,string contents)"), + * mailTo, + * keccak256(bytes(mailContents)) + * ))); + * address signer = ECDSA.recover(digest, signature); + * ``` + */ + function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { + return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); + } + + /** + * @dev See {IERC-5267}. + */ + function eip712Domain() + public + view + virtual + returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ) + { + EIP712Storage storage $ = _getEIP712Storage(); + // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized + // and the EIP712 domain is not reliable, as it will be missing name and version. + require($._hashedName == 0 && $._hashedVersion == 0, "EIP712: Uninitialized"); + + return ( + hex"0f", // 01111 + _EIP712Name(), + _EIP712Version(), + block.chainid, + address(this), + bytes32(0), + new uint256[](0) + ); + } + + /** + * @dev The name parameter for the EIP712 domain. + * + * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs + * are a concern. + */ + function _EIP712Name() internal view virtual returns (string memory) { + EIP712Storage storage $ = _getEIP712Storage(); + return $._name; + } + + /** + * @dev The version parameter for the EIP712 domain. + * + * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs + * are a concern. + */ + function _EIP712Version() internal view virtual returns (string memory) { + EIP712Storage storage $ = _getEIP712Storage(); + return $._version; + } + + /** + * @dev The hash of the name parameter for the EIP712 domain. + * + * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. + */ + function _EIP712NameHash() internal view returns (bytes32) { + EIP712Storage storage $ = _getEIP712Storage(); + string memory name = _EIP712Name(); + if (bytes(name).length > 0) { + return keccak256(bytes(name)); + } else { + // If the name is empty, the contract may have been upgraded without initializing the new storage. + // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. + bytes32 hashedName = $._hashedName; + if (hashedName != 0) { + return hashedName; + } else { + return keccak256(""); + } + } + } + + /** + * @dev The hash of the version parameter for the EIP712 domain. + * + * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. + */ + function _EIP712VersionHash() internal view returns (bytes32) { + EIP712Storage storage $ = _getEIP712Storage(); + string memory version = _EIP712Version(); + if (bytes(version).length > 0) { + return keccak256(bytes(version)); + } else { + // If the version is empty, the contract may have been upgraded without initializing the new storage. + // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. + bytes32 hashedVersion = $._hashedVersion; + if (hashedVersion != 0) { + return hashedVersion; + } else { + return keccak256(""); + } + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/governance/utils/VotesUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/Votes.sol) + +/** + * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be + * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of + * "representative" that will pool delegated voting units from different accounts and can then use it to vote in + * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to + * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative. + * + * This contract is often combined with a token contract such that voting units correspond to token units. For an + * example, see {ERC721Votes}. + * + * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed + * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the + * cost of this history tracking optional. + * + * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return + * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the + * previous example, it would be included in {ERC721-_update}). + */ +abstract contract VotesUpgradeable is Initializable, ContextUpgradeable, EIP712Upgradeable, NoncesUpgradeable, IERC5805 { + using Checkpoints for Checkpoints.Trace208; + + bytes32 private constant DELEGATION_TYPEHASH = + keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); + + /// @custom:storage-location erc7201:openzeppelin.storage.Votes + struct VotesStorage { + mapping(address account => address) _delegatee; + + mapping(address delegatee => Checkpoints.Trace208) _delegateCheckpoints; + + Checkpoints.Trace208 _totalCheckpoints; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Votes")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant VotesStorageLocation = 0xe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00; + + function _getVotesStorage() private pure returns (VotesStorage storage $) { + assembly { + $.slot := VotesStorageLocation + } + } + + /** + * @dev The clock was incorrectly modified. + */ + error ERC6372InconsistentClock(); + + /** + * @dev Lookup to future votes is not available. + */ + error ERC5805FutureLookup(uint256 timepoint, uint48 clock); + + function __Votes_init() internal onlyInitializing { + } + + function __Votes_init_unchained() internal onlyInitializing { + } + /** + * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based + * checkpoints (and voting), in which case {CLOCK_MODE} should be overridden as well to match. + */ + function clock() public view virtual returns (uint48) { + return Time.blockNumber(); + } + + /** + * @dev Machine-readable description of the clock as specified in EIP-6372. + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual returns (string memory) { + // Check that the clock was not modified + if (clock() != Time.blockNumber()) { + revert ERC6372InconsistentClock(); + } + return "mode=blocknumber&from=default"; + } + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) public view virtual returns (uint256) { + VotesStorage storage $ = _getVotesStorage(); + return $._delegateCheckpoints[account].latest(); + } + + /** + * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastVotes(address account, uint256 timepoint) public view virtual returns (uint256) { + VotesStorage storage $ = _getVotesStorage(); + uint48 currentTimepoint = clock(); + if (timepoint >= currentTimepoint) { + revert ERC5805FutureLookup(timepoint, currentTimepoint); + } + return $._delegateCheckpoints[account].upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + * + * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. + * Votes that have not been delegated are still part of total supply, even though they would not participate in a + * vote. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastTotalSupply(uint256 timepoint) public view virtual returns (uint256) { + VotesStorage storage $ = _getVotesStorage(); + uint48 currentTimepoint = clock(); + if (timepoint >= currentTimepoint) { + revert ERC5805FutureLookup(timepoint, currentTimepoint); + } + return $._totalCheckpoints.upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @dev Returns the current total supply of votes. + */ + function _getTotalSupply() internal view virtual returns (uint256) { + VotesStorage storage $ = _getVotesStorage(); + return $._totalCheckpoints.latest(); + } + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) public view virtual returns (address) { + VotesStorage storage $ = _getVotesStorage(); + return $._delegatee[account]; + } + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) public virtual { + address account = _msgSender(); + _delegate(account, delegatee); + } + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig( + address delegatee, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + if (block.timestamp > expiry) { + revert VotesExpiredSignature(expiry); + } + address signer = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))), + v, + r, + s + ); + _useCheckedNonce(signer, nonce); + _delegate(signer, delegatee); + } + + /** + * @dev Delegate all of `account`'s voting units to `delegatee`. + * + * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}. + */ + function _delegate(address account, address delegatee) internal virtual { + VotesStorage storage $ = _getVotesStorage(); + address oldDelegate = delegates(account); + $._delegatee[account] = delegatee; + + emit DelegateChanged(account, oldDelegate, delegatee); + _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account)); + } + + /** + * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to` + * should be zero. Total supply of voting units will be adjusted with mints and burns. + */ + function _transferVotingUnits(address from, address to, uint256 amount) internal virtual { + VotesStorage storage $ = _getVotesStorage(); + if (from == address(0)) { + _push($._totalCheckpoints, _add, SafeCast.toUint208(amount)); + } + if (to == address(0)) { + _push($._totalCheckpoints, _subtract, SafeCast.toUint208(amount)); + } + _moveDelegateVotes(delegates(from), delegates(to), amount); + } + + /** + * @dev Moves delegated votes from one delegate to another. + */ + function _moveDelegateVotes(address from, address to, uint256 amount) private { + VotesStorage storage $ = _getVotesStorage(); + if (from != to && amount > 0) { + if (from != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + $._delegateCheckpoints[from], + _subtract, + SafeCast.toUint208(amount) + ); + emit DelegateVotesChanged(from, oldValue, newValue); + } + if (to != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + $._delegateCheckpoints[to], + _add, + SafeCast.toUint208(amount) + ); + emit DelegateVotesChanged(to, oldValue, newValue); + } + } + } + + /** + * @dev Get number of checkpoints for `account`. + */ + function _numCheckpoints(address account) internal view virtual returns (uint32) { + VotesStorage storage $ = _getVotesStorage(); + return SafeCast.toUint32($._delegateCheckpoints[account].length()); + } + + /** + * @dev Get the `pos`-th checkpoint for `account`. + */ + function _checkpoints( + address account, + uint32 pos + ) internal view virtual returns (Checkpoints.Checkpoint208 memory) { + VotesStorage storage $ = _getVotesStorage(); + return $._delegateCheckpoints[account].at(pos); + } + + function _push( + Checkpoints.Trace208 storage store, + function(uint208, uint208) view returns (uint208) op, + uint208 delta + ) private returns (uint208, uint208) { + return store.push(clock(), op(store.latest(), delta)); + } + + function _add(uint208 a, uint208 b) private pure returns (uint208) { + return a + b; + } + + function _subtract(uint208 a, uint208 b) private pure returns (uint208) { + return a - b; + } + + /** + * @dev Must return the voting units held by an account. + */ + function _getVotingUnits(address) internal view virtual returns (uint256); +} + +// lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Votes.sol) + +/** + * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's, + * and supports token supply up to 2^208^ - 1, while COMP is limited to 2^96^ - 1. + * + * NOTE: This contract does not provide interface compatibility with Compound's COMP token. + * + * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either + * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting + * power can be queried through the public accessors {getVotes} and {getPastVotes}. + * + * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it + * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. + */ +abstract contract ERC20VotesUpgradeable is Initializable, ERC20Upgradeable, VotesUpgradeable { + /** + * @dev Total supply cap has been exceeded, introducing a risk of votes overflowing. + */ + error ERC20ExceededSafeSupply(uint256 increasedSupply, uint256 cap); + + function __ERC20Votes_init() internal onlyInitializing { + } + + function __ERC20Votes_init_unchained() internal onlyInitializing { + } + /** + * @dev Maximum token supply. Defaults to `type(uint208).max` (2^208^ - 1). + * + * This maximum is enforced in {_update}. It limits the total supply of the token, which is otherwise a uint256, + * so that checkpoints can be stored in the Trace208 structure used by {{Votes}}. Increasing this value will not + * remove the underlying limitation, and will cause {_update} to fail because of a math overflow in + * {_transferVotingUnits}. An override could be used to further restrict the total supply (to a lower value) if + * additional logic requires it. When resolving override conflicts on this function, the minimum should be + * returned. + */ + function _maxSupply() internal view virtual returns (uint256) { + return type(uint208).max; + } + + /** + * @dev Move voting power when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _update(address from, address to, uint256 value) internal virtual override { + super._update(from, to, value); + if (from == address(0)) { + uint256 supply = totalSupply(); + uint256 cap = _maxSupply(); + if (supply > cap) { + revert ERC20ExceededSafeSupply(supply, cap); + } + } + _transferVotingUnits(from, to, value); + } + + /** + * @dev Returns the voting units of an `account`. + * + * WARNING: Overriding this function may compromise the internal vote accounting. + * `ERC20Votes` assumes tokens map to voting units 1:1 and this is not easy to change. + */ + function _getVotingUnits(address account) internal view virtual override returns (uint256) { + return balanceOf(account); + } + + /** + * @dev Get number of checkpoints for `account`. + */ + function numCheckpoints(address account) public view virtual returns (uint32) { + return _numCheckpoints(account); + } + + /** + * @dev Get the `pos`-th checkpoint for `account`. + */ + function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoints.Checkpoint208 memory) { + return _checkpoints(account, pos); + } +} + +// src/ButteredBread.sol + +/** + * @title Breadchain Buttered Bread + * @notice Deposit LP tokens (Butter) to earn scaling rewards + * @author Breadchain Collective + * @custom:coauthor @RonTuretzky + * @custom:coauthor @daopunk + * @custom:coauthor @bagelface + */ +contract ButteredBread is IButteredBread, ERC20VotesUpgradeable, Ownable2StepUpgradeable, ReentrancyGuardUpgradeable { + /// @notice Value used for calculating the precision of scaling factors + uint256 public constant FIXED_POINT_PERCENT = 100; + /// @notice `IERC20Votes` contract used for powering `ButteredBread` voting + IERC20Votes public bread; + /// @notice Access control for Breadchain sanctioned liquidity pools + mapping(address lp => bool allowed) public allowlistedLPs; + /// @notice How much ButteredBread should be minted for a Liquidity Pool token (Butter) + mapping(address lp => uint256 factor) public scalingFactors; + /// @notice Butter balance by account and Liquidity Pool token deposited + mapping(address account => mapping(address lp => LPData)) internal _accountToLPData; + + /// @dev Applied to functions to only allow access for sanctioned liquidity pools + modifier onlyAllowed(address _lp) { + if (!allowlistedLPs[_lp]) revert NotAllowListed(); + _; + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @param _initData See `IButteredBread` + function initialize(InitData calldata _initData) external initializer { + if (_initData.liquidityPools.length != _initData.scalingFactors.length) revert InvalidValue(); + bread = IERC20Votes(_initData.breadToken); + + __ERC20_init(_initData.name, _initData.symbol); + __EIP712_init(_initData.name, "1"); + __ERC20Votes_init(); + __Ownable_init(msg.sender); + __ReentrancyGuard_init(); + + for (uint256 i; i < _initData.liquidityPools.length; ++i) { + scalingFactors[_initData.liquidityPools[i]] = _initData.scalingFactors[i]; + allowlistedLPs[_initData.liquidityPools[i]] = true; + } + } + + /** + * @notice Return token balance of account for a specified LP + * @param _account Voting account + * @param _lp Liquidity Pool token + * @return _lpBalance Balance of LP tokens for an account by LP address + */ + function accountToLPBalance(address _account, address _lp) external view returns (uint256 _lpBalance) { + _lpBalance = _accountToLPData[_account][_lp].balance; + } + + /// @notice Sync this delegation with user delegate selection on $BREAD + function syncDelegation() external { + _syncDelegation(msg.sender); + } + + /** + * @notice Deposit LP tokens and mint ButteredBread + * NOTE: Additional ButteredBread can be minted/burned due to scaling factor changes + * @param _lp Liquidity Pool token + * @param _amount Value of LP token + */ + function deposit(address _lp, uint256 _amount) external onlyAllowed(_lp) nonReentrant { + if (_amount == 0) revert AmountZero(); + _deposit(msg.sender, _lp, _amount); + } + + /** + * @notice Withdraw LP tokens and burn ButteredBread + * NOTE: Additional ButteredBread can be minted/burned due to scaling factor changes + * @param _lp Liquidity Pool token + * @param _amount Value of LP token + */ + function withdraw(address _lp, uint256 _amount) external onlyAllowed(_lp) nonReentrant { + if (_amount == 0) revert AmountZero(); + _withdraw(msg.sender, _lp, _amount); + } + + /** + * @notice Allow or deny LP token + * @dev Must set scaling factor before sanctioning LP token + * @dev WARNING: When adding a new LP token, ensure that it has 18 decimals + * @param _lp Liquidity Pool token + * @param _allowed Sanction status of LP token + */ + function modifyAllowList(address _lp, bool _allowed) external onlyOwner { + if (scalingFactors[_lp] == 0) revert UnsetVariable(); + allowlistedLPs[_lp] = _allowed; + } + + /** + * @notice Set LP token scaling factor + * @param _lp Liquidity Pool token + * @param _factor Scaling percentage incentive of LP token (e.g. 100 = 1X, 150 = 1.5X, 1000 = 10X) + * @param _holders List of accounts to update with new scaling factor + */ + function modifyScalingFactor(address _lp, uint256 _factor, address[] calldata _holders) external onlyOwner { + _modifyScalingFactor(_lp, _factor, _holders); + } + + /// @notice `ButteredBread` tokens are non-transferable + function transfer(address, uint256) public virtual override returns (bool) { + revert NonTransferable(); + } + + /// @notice `ButteredBread` tokens are non-transferable + function transferFrom(address, address, uint256) public virtual override returns (bool) { + revert NonTransferable(); + } + + /// @notice `ButteredBread` delegation is determined by `BreadToken` + function delegate(address) public virtual override { + revert NonDelegatable(); + } + + /// @notice Get the LP data (balance and scaling factor) of a specific LP for a given account + /// @param _holder The address of the account to get the data for + /// @param _lp The address of the LP to get the data for + /// @return LPData memory The LP data containing balance and scaling factor for the given account + function getLPData(address _holder, address _lp) external view returns (LPData memory) { + return _accountToLPData[_holder][_lp]; + } + + /// @notice Deposit LP tokens and mint ButteredBread with corresponding LP scaling factor + function _deposit(address _account, address _lp, uint256 _amount) internal { + bool success = IERC20(_lp).transferFrom(_account, address(this), _amount); + if (!success) revert TransferFailed(); + + _syncDelegation(_account); + + /// @dev ensure proper accounting in case of admin error in `modifyScalingFactor` where not all holders are updated + _syncVotingWeight(_account, _lp); + _accountToLPData[_account][_lp].balance += _amount; + + _mint(_account, _amount * scalingFactors[_lp] / FIXED_POINT_PERCENT); + + emit ButterAdded(_account, _lp, _amount); + } + + /// @notice Withdraw LP tokens and burn ButteredBread with corresponding LP scaling factor + function _withdraw(address _account, address _lp, uint256 _amount) internal { + if (_amount > _accountToLPData[_account][_lp].balance) revert InsufficientFunds(); + _syncDelegation(_account); + + /// @dev ensure proper accounting in case of admin error in `modifyScalingFactor` where not all holders are updated + _syncVotingWeight(_account, _lp); + _accountToLPData[_account][_lp].balance -= _amount; + + _burn(_account, _amount * scalingFactors[_lp] / FIXED_POINT_PERCENT); + bool success = IERC20(_lp).transfer(_account, _amount); + if (!success) revert TransferFailed(); + + emit ButterRemoved(_account, _lp, _amount); + } + + function _modifyScalingFactor(address _lp, uint256 _factor, address[] calldata _holders) internal { + if (_factor < FIXED_POINT_PERCENT) revert InvalidValue(); + + uint256 old = scalingFactors[_lp]; + scalingFactors[_lp] = _factor; + emit ScalingFactorModified(_lp, old, _factor); + + for (uint256 i = 0; i < _holders.length; i++) { + _syncVotingWeight(_holders[i], _lp); + } + } + + /// @notice Sync this delegation with delegate selection on $BREAD + function _syncDelegation(address _account) internal { + _delegate(_account, bread.delegates(_account)); + if (this.delegates(_account) == address(0)) _delegate(_account, _account); + } + + /// @notice Sync voting weight with scaling factor + function _syncVotingWeight(address _account, address _lp) internal { + uint256 currentScalingFactor = scalingFactors[_lp]; + uint256 initialScalingFactor = _accountToLPData[_account][_lp].scalingFactor; + + if (currentScalingFactor != initialScalingFactor) { + uint256 lpBalance = _accountToLPData[_account][_lp].balance; + _accountToLPData[_account][_lp].scalingFactor = currentScalingFactor; + + if (lpBalance > 0) { + if (currentScalingFactor > initialScalingFactor) { + _mint( + _account, + (lpBalance * currentScalingFactor - lpBalance * initialScalingFactor) / FIXED_POINT_PERCENT + ); + } else { + _burn( + _account, + (lpBalance * initialScalingFactor - lpBalance * currentScalingFactor) / FIXED_POINT_PERCENT + ); + } + } + } + } +} + diff --git a/test/upgrades/current/VotingMultipliers.sol b/test/upgrades/current/VotingMultipliers.sol new file mode 100644 index 00000000..8633f269 --- /dev/null +++ b/test/upgrades/current/VotingMultipliers.sol @@ -0,0 +1,1085 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.20 ^0.8.22; + +// src/interfaces/multipliers/IMultiplier.sol + +interface IMultiplier { + /// @notice Updates the multiplying factor for a specific user + /// @param _user The address of the user to update the multiplying factor for + function updateMultiplyingFactor(address _user) external; + + /// @notice Returns the multiplying factor for `_user`. + function getMultiplyingFactor(address _user) external view returns (uint256); + + /// @notice Returns the validity period of the multiplier for `_user`. + function validUntil(address _user) external view returns (uint256); +} + +// lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ```solidity + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Storage of the initializable contract. + * + * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions + * when using with upgradeable contracts. + * + * @custom:storage-location erc7201:openzeppelin.storage.Initializable + */ + struct InitializableStorage { + /** + * @dev Indicates that the contract has been initialized. + */ + uint64 _initialized; + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool _initializing; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; + + /** + * @dev The contract is already initialized. + */ + error InvalidInitialization(); + + /** + * @dev The contract is not initializing. + */ + error NotInitializing(); + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint64 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any + * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in + * production. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + // Cache values to avoid duplicated sloads + bool isTopLevelCall = !$._initializing; + uint64 initialized = $._initialized; + + // Allowed calls: + // - initialSetup: the contract is not in the initializing state and no previous version was + // initialized + // - construction: the contract is initialized at version 1 (no reininitialization) and the + // current contract is just being deployed + bool initialSetup = initialized == 0 && isTopLevelCall; + bool construction = initialized == 1 && address(this).code.length == 0; + + if (!initialSetup && !construction) { + revert InvalidInitialization(); + } + $._initialized = 1; + if (isTopLevelCall) { + $._initializing = true; + } + _; + if (isTopLevelCall) { + $._initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint64 version) { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing || $._initialized >= version) { + revert InvalidInitialization(); + } + $._initialized = version; + $._initializing = true; + _; + $._initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + _checkInitializing(); + _; + } + + /** + * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. + */ + function _checkInitializing() internal view virtual { + if (!_isInitializing()) { + revert NotInitializing(); + } + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing) { + revert InvalidInitialization(); + } + if ($._initialized != type(uint64).max) { + $._initialized = type(uint64).max; + emit Initialized(type(uint64).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint64) { + return _getInitializableStorage()._initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _getInitializableStorage()._initializing; + } + + /** + * @dev Returns a pointer to the storage namespace. + */ + // solhint-disable-next-line var-name-mixedcase + function _getInitializableStorage() private pure returns (InitializableStorage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + /** + * @dev Muldiv operation overflow. + */ + error MathOverflowedMulDiv(); + + enum Rounding { + Floor, // Toward negative infinity + Ceil, // Toward positive infinity + Trunc, // Toward zero + Expand // Away from zero + } + + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with an overflow flag. + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds towards infinity instead + * of rounding towards zero. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + if (b == 0) { + // Guarantee the same behavior as in a regular Solidity division. + return a / b; + } + + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0. + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by + * Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0 = x * y; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + if (denominator <= prod1) { + revert MathOverflowedMulDiv(); + } + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. + // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. + + uint256 twos = denominator & (0 - denominator); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also + // works in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded + * towards zero. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // โ†’ `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // โ†’ `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256 of a positive value rounded towards zero. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); + } + } + + /** + * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. + */ + function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { + return uint8(rounding) % 2 == 1; + } +} + +// src/libraries/MultiplierConstants.sol + +library MultiplierConstants { + /// @notice The base multiplier value (100% in fixed-point representation) + uint256 public constant BASE_MULTIPLIER = 1e18; +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract ContextUpgradeable is Initializable { + function __Context_init() internal onlyInitializing { + } + + function __Context_init_unchained() internal onlyInitializing { + } + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } + + function _contextSuffixLength() internal view virtual returns (uint256) { + return 0; + } +} + +// src/interfaces/IVotingMultipliers.sol + +/// @title IVotingMultipliers +/// @notice Interface for the VotingMultipliers contract +/// @dev This interface defines the structure and functions for managing voting multipliers +interface IVotingMultipliers { + /// @notice Thrown when attempting to add a multiplier that is already allowlisted + error MultiplierAlreadyAllowlisted(); + /// @notice Thrown when attempting to remove a multiplier that is not allowlisted + error MultiplierNotAllowlisted(); + /// @notice Thrown when an invalid multiplier index is provided + error InvalidMultiplierIndex(); + + /// @notice Emitted when a new multiplier is added to the allowlist + /// @param multiplier The address of the added multiplier + event MultiplierAdded(IMultiplier indexed multiplier); + /// @notice Emitted when a multiplier is removed from the allowlist + /// @param multiplier The address of the removed multiplier + event MultiplierRemoved(IMultiplier indexed multiplier); + + /// @notice Returns the multiplier at the specified index in the allowlist + /// @param index The index of the multiplier in the allowlist + /// @return The multiplier contract at the specified index + function allowlistedMultipliers(uint256 index) external view returns (IMultiplier); + /// @notice Returns the array of allowlisted multipliers + /// @return IMultiplier[] The array of allowlisted multiplier contracts + function allowlistedMultipliers() external view returns (IMultiplier[] memory); + /// @notice Calculates the total multiplier for a given _user + /// @param __user The address of the _user + /// @return The total multiplier value for the _user + function getTotalMultipliers(address __user) external view returns (uint256); + /// @notice Adds a multiplier to the allowlist + /// @param _multiplier The multiplier contract to be added + function addMultiplier(IMultiplier _multiplier) external; + /// @notice Removes a multiplier from the allowlist + /// @param _multiplier The multiplier contract to be removed + function removeMultiplier(IMultiplier _multiplier) external; +} + +// lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is set to the address provided by the deployer. This can + * later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { + /// @custom:storage-location erc7201:openzeppelin.storage.Ownable + struct OwnableStorage { + address _owner; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; + + function _getOwnableStorage() private pure returns (OwnableStorage storage $) { + assembly { + $.slot := OwnableStorageLocation + } + } + + /** + * @dev The caller account is not authorized to perform an operation. + */ + error OwnableUnauthorizedAccount(address account); + + /** + * @dev The owner is not a valid owner account. (eg. `address(0)`) + */ + error OwnableInvalidOwner(address owner); + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the address provided by the deployer as the initial owner. + */ + function __Ownable_init(address initialOwner) internal onlyInitializing { + __Ownable_init_unchained(initialOwner); + } + + function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { + if (initialOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(initialOwner); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + OwnableStorage storage $ = _getOwnableStorage(); + return $._owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + if (owner() != _msgSender()) { + revert OwnableUnauthorizedAccount(_msgSender()); + } + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + if (newOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + OwnableStorage storage $ = _getOwnableStorage(); + address oldOwner = $._owner; + $._owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/access/Ownable2StepUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) + +/** + * @dev Contract module which provides access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is specified at deployment time in the constructor for `Ownable`. This + * can later be changed with {transferOwnership} and {acceptOwnership}. + * + * This module is used through inheritance. It will make available all functions + * from parent (Ownable). + */ +abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable { + /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step + struct Ownable2StepStorage { + address _pendingOwner; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00; + + function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) { + assembly { + $.slot := Ownable2StepStorageLocation + } + } + + event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); + + function __Ownable2Step_init() internal onlyInitializing { + } + + function __Ownable2Step_init_unchained() internal onlyInitializing { + } + /** + * @dev Returns the address of the pending owner. + */ + function pendingOwner() public view virtual returns (address) { + Ownable2StepStorage storage $ = _getOwnable2StepStorage(); + return $._pendingOwner; + } + + /** + * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual override onlyOwner { + Ownable2StepStorage storage $ = _getOwnable2StepStorage(); + $._pendingOwner = newOwner; + emit OwnershipTransferStarted(owner(), newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual override { + Ownable2StepStorage storage $ = _getOwnable2StepStorage(); + delete $._pendingOwner; + super._transferOwnership(newOwner); + } + + /** + * @dev The new owner accepts the ownership transfer. + */ + function acceptOwnership() public virtual { + address sender = _msgSender(); + if (pendingOwner() != sender) { + revert OwnableUnauthorizedAccount(sender); + } + _transferOwnership(sender); + } +} + +// src/VotingMultipliers.sol + +/// @title VotingMultipliers +/// @notice A contract for managing voting multipliers +/// @dev Implements IVotingMultipliers interface +contract VotingMultipliers is Ownable2StepUpgradeable, IVotingMultipliers { + /// @custom:storage-location erc7201:breadchain.VotingMultipliers.storage + struct VotingMultipliersStorage { + IMultiplier[] allowlistedMultipliers; + } + + // keccak256(abi.encode(uint256(keccak256("breadchain.VotingMultipliers.storage")) - 1)) & ~bytes32(uint256(0xff)); + bytes32 private constant VOTING_MULTIPLIERS_STORAGE_LOCATION = 0xf8ea84bd4d45550952f40e913fd59ad03bae30b4f3dc5a09695fefe1d0465d00; + + /// @notice Initializes the contract + function initialize() public initializer { + __Ownable_init(msg.sender); + } + + function _getVotingMultipliersStorage() private pure returns (VotingMultipliersStorage storage $) { + assembly { + $.slot := VOTING_MULTIPLIERS_STORAGE_LOCATION + } + } + + /// @notice Returns the multiplier at the given index + /// @param index The index of the multiplier + /// @return multiplier The multiplier at the given index + function allowlistedMultipliers(uint256 index) external view returns (IMultiplier multiplier) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + return $.allowlistedMultipliers[index]; + } + + /// @notice Returns the array of allowlisted multipliers + /// @return IMultiplier[] The array of allowlisted multipliers + function allowlistedMultipliers() external view returns (IMultiplier[] memory) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + return $.allowlistedMultipliers; + } + + /// @notice Adds a multiplier to the allowlist + /// @param _multiplier The multiplier contract to be added + function addMultiplier(IMultiplier _multiplier) external onlyOwner { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + // Check if the multiplier is already allowlisted + for (uint256 i = 0; i < $.allowlistedMultipliers.length; i++) { + if ($.allowlistedMultipliers[i] == _multiplier) { + revert MultiplierAlreadyAllowlisted(); + } + } + $.allowlistedMultipliers.push(_multiplier); + emit MultiplierAdded(_multiplier); + } + + /// @notice Removes a multiplier from the allowlist + /// @param _multiplier The multiplier contract to be removed + function removeMultiplier(IMultiplier _multiplier) external onlyOwner { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + bool isallowlisted = false; + for (uint256 i = 0; i < $.allowlistedMultipliers.length; i++) { + if ($.allowlistedMultipliers[i] == _multiplier) { + $.allowlistedMultipliers[i] = $.allowlistedMultipliers[$.allowlistedMultipliers.length - 1]; + $.allowlistedMultipliers.pop(); + isallowlisted = true; + emit MultiplierRemoved(_multiplier); + break; + } + } + if (!isallowlisted) { + revert MultiplierNotAllowlisted(); + } + } + + /// @notice Gets the indexes of valid multipliers for a user + /// @param _user The address of the user + /// @return uint256[] Array of valid multiplier indexes + function getValidMultiplierIndexes(address _user) public view returns (uint256[] memory) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + uint256[] memory validIndexes = new uint256[]($.allowlistedMultipliers.length); + uint256 count = 0; + + for (uint256 i = 0; i < $.allowlistedMultipliers.length; i++) { + if ( + block.number <= $.allowlistedMultipliers[i].validUntil(_user) + && $.allowlistedMultipliers[i].getMultiplyingFactor(_user) > 0 + ) { + validIndexes[count] = i; + count++; + } + } + + // Create correctly sized array + uint256[] memory result = new uint256[](count); + for (uint256 i = 0; i < count; i++) { + result[i] = validIndexes[i]; + } + return result; + } + + /// @notice Calculates the total multiplier for a given user using specific multiplier indexes + /// @notice Performs the updateMultiplyingFactor function for each multiplier to ensure the multiplier is up to date + /// @param _user The address of the user + /// @param _multiplierIndexes Array of multiplier indexes to use + /// @return The total multiplier value for the user + function calculateTotalMultipliers(address _user, uint256[] calldata _multiplierIndexes) public returns (uint256) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + uint256 _totalMultiplier = MultiplierConstants.BASE_MULTIPLIER; + + for (uint256 i = 0; i < _multiplierIndexes.length; i++) { + uint256 index = _multiplierIndexes[i]; + if (index >= $.allowlistedMultipliers.length) { + revert InvalidMultiplierIndex(); + } + + IMultiplier multiplier = $.allowlistedMultipliers[index]; + multiplier.updateMultiplyingFactor(_user); + if (block.number <= multiplier.validUntil(_user)) { + uint256 factor = multiplier.getMultiplyingFactor(_user); + if (factor > MultiplierConstants.BASE_MULTIPLIER) { + // Add only the bonus amount to the total + _totalMultiplier += (factor - MultiplierConstants.BASE_MULTIPLIER); + } + } + } + return Math.max(_totalMultiplier, MultiplierConstants.BASE_MULTIPLIER); + } + + /// @notice Calculates the total multiplier for a given user + /// @param _user The address of the _user + /// @return The total multiplier value for the _user + /// @dev This function is intended for frontend and testing purposes + function getTotalMultipliers(address _user) public view returns (uint256) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + uint256 _totalMultiplier = MultiplierConstants.BASE_MULTIPLIER; + for (uint256 i = 0; i < $.allowlistedMultipliers.length; i++) { + IMultiplier multiplier = $.allowlistedMultipliers[i]; + if (block.number <= multiplier.validUntil(_user)) { + uint256 factor = multiplier.getMultiplyingFactor(_user); + if (factor > MultiplierConstants.BASE_MULTIPLIER) { + // Add only the bonus amount to the total + _totalMultiplier += (factor - MultiplierConstants.BASE_MULTIPLIER); + } + } + } + return Math.max(_totalMultiplier, MultiplierConstants.BASE_MULTIPLIER); + } +} + diff --git a/test/upgrades/current/YieldDistributor.sol b/test/upgrades/current/YieldDistributor.sol new file mode 100644 index 00000000..3c2a4d69 --- /dev/null +++ b/test/upgrades/current/YieldDistributor.sol @@ -0,0 +1,5741 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0 ^0.8.20 ^0.8.22; + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Address.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev The ETH balance of the account is not enough to perform the operation. + */ + error AddressInsufficientBalance(address account); + + /** + * @dev There's no code at `target` (it is not a contract). + */ + error AddressEmptyCode(address target); + + /** + * @dev A call to an address target failed. The target may have reverted. + */ + error FailedInnerCall(); + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + if (address(this).balance < amount) { + revert AddressInsufficientBalance(address(this)); + } + + (bool success, ) = recipient.call{value: amount}(""); + if (!success) { + revert FailedInnerCall(); + } + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason or custom error, it is bubbled + * up by this function (like regular Solidity function calls). However, if + * the call reverted with no returned reason, this function reverts with a + * {FailedInnerCall} error. + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + if (address(this).balance < value) { + revert AddressInsufficientBalance(address(this)); + } + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target + * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an + * unsuccessful call. + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata + ) internal view returns (bytes memory) { + if (!success) { + _revert(returndata); + } else { + // only check if target is a contract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + if (returndata.length == 0 && target.code.length == 0) { + revert AddressEmptyCode(target); + } + return returndata; + } + } + + /** + * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the + * revert reason or with a default {FailedInnerCall} error. + */ + function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { + if (!success) { + _revert(returndata); + } else { + return returndata; + } + } + + /** + * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. + */ + function _revert(bytes memory returndata) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert FailedInnerCall(); + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) + +/** + * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. + * + * These functions can be used to verify that a message was signed by the holder + * of the private keys of a given address. + */ +library ECDSA { + enum RecoverError { + NoError, + InvalidSignature, + InvalidSignatureLength, + InvalidSignatureS + } + + /** + * @dev The signature derives the `address(0)`. + */ + error ECDSAInvalidSignature(); + + /** + * @dev The signature has an invalid length. + */ + error ECDSAInvalidSignatureLength(uint256 length); + + /** + * @dev The signature has an S value that is in the upper half order. + */ + error ECDSAInvalidSignatureS(bytes32 s); + + /** + * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not + * return address(0) without also returning an error description. Errors are documented using an enum (error type) + * and a bytes32 providing additional information about the error. + * + * If no error is returned, then the address can be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + * + * Documentation for signature generation: + * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] + * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] + */ + function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { + if (signature.length == 65) { + bytes32 r; + bytes32 s; + uint8 v; + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + /// @solidity memory-safe-assembly + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := byte(0, mload(add(signature, 0x60))) + } + return tryRecover(hash, v, r, s); + } else { + return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature`. This address can then be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + */ + function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. + * + * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] + */ + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { + unchecked { + bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + // We do not check for an overflow here since the shift operation results in 0 or 1. + uint8 v = uint8((uint256(vs) >> 255) + 27); + return tryRecover(hash, v, r, s); + } + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. + */ + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function tryRecover( + bytes32 hash, + uint8 v, + bytes32 r, + bytes32 s + ) internal pure returns (address, RecoverError, bytes32) { + // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature + // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines + // the valid range for s in (301): 0 < s < secp256k1n รท 2 + 1, and for v in (302): v โˆˆ {27, 28}. Most + // signatures from current libraries generate a unique signature with an s-value in the lower half order. + // + // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value + // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or + // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept + // these malleable signatures as well. + if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + return (address(0), RecoverError.InvalidSignatureS, s); + } + + // If the signature is valid (and not malleable), return the signer address + address signer = ecrecover(hash, v, r, s); + if (signer == address(0)) { + return (address(0), RecoverError.InvalidSignature, bytes32(0)); + } + + return (signer, RecoverError.NoError, bytes32(0)); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. + */ + function _throwError(RecoverError error, bytes32 errorArg) private pure { + if (error == RecoverError.NoError) { + return; // no error: do nothing + } else if (error == RecoverError.InvalidSignature) { + revert ECDSAInvalidSignature(); + } else if (error == RecoverError.InvalidSignatureLength) { + revert ECDSAInvalidSignatureLength(uint256(errorArg)); + } else if (error == RecoverError.InvalidSignatureS) { + revert ECDSAInvalidSignatureS(errorArg); + } + } +} + +// lib/bread-token-v2/src/interfaces/IBread.sol + +interface IBread{ + function claimYield(uint256 amount, address receiver) external ; + function yieldAccrued() external view returns (uint256); + function setYieldClaimer(address _yieldClaimer) external ; + +} + +// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20_0 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the value of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the value of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves a `value` amount of tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 value) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 value) external returns (bool); + + /** + * @dev Moves a `value` amount of tokens from `from` to `to` using the + * allowance mechanism. `value` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 value) external returns (bool); +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20_1 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the value of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the value of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves a `value` amount of tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 value) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 value) external returns (bool); + + /** + * @dev Moves a `value` amount of tokens from `from` to `to` using the + * allowance mechanism. `value` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 value) external returns (bool); +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) + +/** + * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by + * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't + * need to send a transaction, and thus is not required to hold Ether at all. + * + * ==== Security Considerations + * + * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature + * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be + * considered as an intention to spend the allowance in any specific way. The second is that because permits have + * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should + * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be + * generally recommended is: + * + * ```solidity + * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { + * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} + * doThing(..., value); + * } + * + * function doThing(..., uint256 value) public { + * token.safeTransferFrom(msg.sender, address(this), value); + * ... + * } + * ``` + * + * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of + * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also + * {SafeERC20-safeTransferFrom}). + * + * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so + * contracts should have entry points that don't rely on permit. + */ +interface IERC20Permit { + /** + * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, + * given ``owner``'s signed approval. + * + * IMPORTANT: The same issues {IERC20-approve} has related to transaction + * ordering also apply here. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `deadline` must be a timestamp in the future. + * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` + * over the EIP712-formatted function arguments. + * - the signature must use ``owner``'s current nonce (see {nonces}). + * + * For more information on the signature format, see the + * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP + * section]. + * + * CAUTION: See Security Considerations above. + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @dev Returns the current nonce for `owner`. This value must be + * included whenever a signature is generated for {permit}. + * + * Every successful call to {permit} increases ``owner``'s nonce by one. This + * prevents a signature from being used multiple times. + */ + function nonces(address owner) external view returns (uint256); + + /** + * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view returns (bytes32); +} + +// lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) + +interface IERC5267 { + /** + * @dev MAY be emitted to signal that the domain could have changed. + */ + event EIP712DomainChanged(); + + /** + * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 + * signature. + */ + function eip712Domain() + external + view + returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ); +} + +// lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol) + +interface IERC6372 { + /** + * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting). + */ + function clock() external view returns (uint48); + + /** + * @dev Description of the clock + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() external view returns (string memory); +} + +// src/interfaces/multipliers/IMultiplier.sol + +interface IMultiplier { + /// @notice Updates the multiplying factor for a specific user + /// @param _user The address of the user to update the multiplying factor for + function updateMultiplyingFactor(address _user) external; + + /// @notice Returns the multiplying factor for `_user`. + function getMultiplyingFactor(address _user) external view returns (uint256); + + /// @notice Returns the validity period of the multiplier for `_user`. + function validUntil(address _user) external view returns (uint256); +} + +// lib/bread-token-v2/src/interfaces/ISXDAI.sol + +interface ISXDAI { + function deposit(uint256 assets, address receiver) external returns (uint256); + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256); + + function convertToAssets(uint256 shares) external view returns (uint256); +} + +// lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol) + +/** + * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. + */ +interface IVotes { + /** + * @dev The signature used has expired. + */ + error VotesExpiredSignature(uint256 expiry); + + /** + * @dev Emitted when an account changes their delegate. + */ + event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); + + /** + * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units. + */ + event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes); + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) external view returns (uint256); + + /** + * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + */ + function getPastVotes(address account, uint256 timepoint) external view returns (uint256); + + /** + * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + * + * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. + * Votes that have not been delegated are still part of total supply, even though they would not participate in a + * vote. + */ + function getPastTotalSupply(uint256 timepoint) external view returns (uint256); + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) external view returns (address); + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) external; + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external; +} + +// lib/bread-token-v2/src/interfaces/IWXDAI.sol + +interface IWXDAI { + function deposit() external payable; + function withdraw(uint256) external; +} + +// src/interfaces/IYieldDistributor.sol + +/** + * @title `YieldDistributor` interface + */ +interface IYieldDistributor { + /// @notice The error emitted when attempting to add a project that is already in the `projects` array + error AlreadyMemberProject(); + /// @notice The error emitted when a user attempts to vote without the minimum required voting power + error BelowMinRequiredVotingPower(); + /// @notice The error emitted when attempting to calculate voting power for a period that has not yet ended + error EndAfterCurrentBlock(); + /// @notice The error emitted when attempting to vote with a point value greater than `pointsMax` + error ExceedsMaxPoints(); + /// @notice The error emitted when attempting to vote with an incorrect number of projects + error IncorrectNumberOfProjects(); + /// @notice The error emitted when attempting to instantiate a variable with a zero value + error MustBeGreaterThanZero(); + /// @notice The error emitted when attempting to add or remove a project that is already queued for addition or removal + error ProjectAlreadyQueued(); + /// @notice The error emitted when attempting to remove a project that is not in the `projects` array + error ProjectNotFound(); + /// @notice The error emitted when attempting to calculate voting power for a period with a start block greater than the end block + error StartMustBeBeforeEnd(); + /// @notice The error emitted when attempting to distribute yield when access conditions are not met + error YieldNotResolved(); + /// @notice The error emitted if a user with zero points attempts to cast votes + error ZeroVotePoints(); + + /// @notice The event emitted when an account casts a vote + event BreadHolderVoted(address indexed account, uint256[] points, address[] projects); + /// @notice The event emitted when a project is added as eligibile for yield distribution + event ProjectAdded(address project); + /// @notice The event emitted when a project is removed as eligibile for yield distribution + event ProjectRemoved(address project); + /// @notice The event emitted when yield is distributed + event YieldDistributed(uint256 yield, uint256 totalVotes, uint256[] projectDistributions); +} + +// lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ```solidity + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Storage of the initializable contract. + * + * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions + * when using with upgradeable contracts. + * + * @custom:storage-location erc7201:openzeppelin.storage.Initializable + */ + struct InitializableStorage { + /** + * @dev Indicates that the contract has been initialized. + */ + uint64 _initialized; + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool _initializing; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; + + /** + * @dev The contract is already initialized. + */ + error InvalidInitialization(); + + /** + * @dev The contract is not initializing. + */ + error NotInitializing(); + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint64 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any + * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in + * production. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + // Cache values to avoid duplicated sloads + bool isTopLevelCall = !$._initializing; + uint64 initialized = $._initialized; + + // Allowed calls: + // - initialSetup: the contract is not in the initializing state and no previous version was + // initialized + // - construction: the contract is initialized at version 1 (no reininitialization) and the + // current contract is just being deployed + bool initialSetup = initialized == 0 && isTopLevelCall; + bool construction = initialized == 1 && address(this).code.length == 0; + + if (!initialSetup && !construction) { + revert InvalidInitialization(); + } + $._initialized = 1; + if (isTopLevelCall) { + $._initializing = true; + } + _; + if (isTopLevelCall) { + $._initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint64 version) { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing || $._initialized >= version) { + revert InvalidInitialization(); + } + $._initialized = version; + $._initializing = true; + _; + $._initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + _checkInitializing(); + _; + } + + /** + * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. + */ + function _checkInitializing() internal view virtual { + if (!_isInitializing()) { + revert NotInitializing(); + } + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing) { + revert InvalidInitialization(); + } + if ($._initialized != type(uint64).max) { + $._initialized = type(uint64).max; + emit Initialized(type(uint64).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint64) { + return _getInitializableStorage()._initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _getInitializableStorage()._initializing; + } + + /** + * @dev Returns a pointer to the storage namespace. + */ + // solhint-disable-next-line var-name-mixedcase + function _getInitializableStorage() private pure returns (InitializableStorage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + /** + * @dev Muldiv operation overflow. + */ + error MathOverflowedMulDiv(); + + enum Rounding { + Floor, // Toward negative infinity + Ceil, // Toward positive infinity + Trunc, // Toward zero + Expand // Away from zero + } + + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with an overflow flag. + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds towards infinity instead + * of rounding towards zero. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + if (b == 0) { + // Guarantee the same behavior as in a regular Solidity division. + return a / b; + } + + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0. + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by + * Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0 = x * y; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + if (denominator <= prod1) { + revert MathOverflowedMulDiv(); + } + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. + // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. + + uint256 twos = denominator & (0 - denominator); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also + // works in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded + * towards zero. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // โ†’ `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // โ†’ `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256 of a positive value rounded towards zero. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); + } + } + + /** + * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. + */ + function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { + return uint8(rounding) % 2 == 1; + } +} + +// src/libraries/MultiplierConstants.sol + +library MultiplierConstants { + /// @notice The base multiplier value (100% in fixed-point representation) + uint256 public constant BASE_MULTIPLIER = 1e18; +} + +// lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) +// This file was procedurally generated from scripts/generate/templates/SafeCast.js. + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. `SafeCast` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeCast { + /** + * @dev Value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + + /** + * @dev An int value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedIntToUint(int256 value); + + /** + * @dev Value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); + + /** + * @dev An uint value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedUintToInt(uint256 value); + + /** + * @dev Returns the downcasted uint248 from uint256, reverting on + * overflow (when the input is greater than largest uint248). + * + * Counterpart to Solidity's `uint248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toUint248(uint256 value) internal pure returns (uint248) { + if (value > type(uint248).max) { + revert SafeCastOverflowedUintDowncast(248, value); + } + return uint248(value); + } + + /** + * @dev Returns the downcasted uint240 from uint256, reverting on + * overflow (when the input is greater than largest uint240). + * + * Counterpart to Solidity's `uint240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toUint240(uint256 value) internal pure returns (uint240) { + if (value > type(uint240).max) { + revert SafeCastOverflowedUintDowncast(240, value); + } + return uint240(value); + } + + /** + * @dev Returns the downcasted uint232 from uint256, reverting on + * overflow (when the input is greater than largest uint232). + * + * Counterpart to Solidity's `uint232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toUint232(uint256 value) internal pure returns (uint232) { + if (value > type(uint232).max) { + revert SafeCastOverflowedUintDowncast(232, value); + } + return uint232(value); + } + + /** + * @dev Returns the downcasted uint224 from uint256, reverting on + * overflow (when the input is greater than largest uint224). + * + * Counterpart to Solidity's `uint224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toUint224(uint256 value) internal pure returns (uint224) { + if (value > type(uint224).max) { + revert SafeCastOverflowedUintDowncast(224, value); + } + return uint224(value); + } + + /** + * @dev Returns the downcasted uint216 from uint256, reverting on + * overflow (when the input is greater than largest uint216). + * + * Counterpart to Solidity's `uint216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toUint216(uint256 value) internal pure returns (uint216) { + if (value > type(uint216).max) { + revert SafeCastOverflowedUintDowncast(216, value); + } + return uint216(value); + } + + /** + * @dev Returns the downcasted uint208 from uint256, reverting on + * overflow (when the input is greater than largest uint208). + * + * Counterpart to Solidity's `uint208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toUint208(uint256 value) internal pure returns (uint208) { + if (value > type(uint208).max) { + revert SafeCastOverflowedUintDowncast(208, value); + } + return uint208(value); + } + + /** + * @dev Returns the downcasted uint200 from uint256, reverting on + * overflow (when the input is greater than largest uint200). + * + * Counterpart to Solidity's `uint200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toUint200(uint256 value) internal pure returns (uint200) { + if (value > type(uint200).max) { + revert SafeCastOverflowedUintDowncast(200, value); + } + return uint200(value); + } + + /** + * @dev Returns the downcasted uint192 from uint256, reverting on + * overflow (when the input is greater than largest uint192). + * + * Counterpart to Solidity's `uint192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toUint192(uint256 value) internal pure returns (uint192) { + if (value > type(uint192).max) { + revert SafeCastOverflowedUintDowncast(192, value); + } + return uint192(value); + } + + /** + * @dev Returns the downcasted uint184 from uint256, reverting on + * overflow (when the input is greater than largest uint184). + * + * Counterpart to Solidity's `uint184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toUint184(uint256 value) internal pure returns (uint184) { + if (value > type(uint184).max) { + revert SafeCastOverflowedUintDowncast(184, value); + } + return uint184(value); + } + + /** + * @dev Returns the downcasted uint176 from uint256, reverting on + * overflow (when the input is greater than largest uint176). + * + * Counterpart to Solidity's `uint176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toUint176(uint256 value) internal pure returns (uint176) { + if (value > type(uint176).max) { + revert SafeCastOverflowedUintDowncast(176, value); + } + return uint176(value); + } + + /** + * @dev Returns the downcasted uint168 from uint256, reverting on + * overflow (when the input is greater than largest uint168). + * + * Counterpart to Solidity's `uint168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toUint168(uint256 value) internal pure returns (uint168) { + if (value > type(uint168).max) { + revert SafeCastOverflowedUintDowncast(168, value); + } + return uint168(value); + } + + /** + * @dev Returns the downcasted uint160 from uint256, reverting on + * overflow (when the input is greater than largest uint160). + * + * Counterpart to Solidity's `uint160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toUint160(uint256 value) internal pure returns (uint160) { + if (value > type(uint160).max) { + revert SafeCastOverflowedUintDowncast(160, value); + } + return uint160(value); + } + + /** + * @dev Returns the downcasted uint152 from uint256, reverting on + * overflow (when the input is greater than largest uint152). + * + * Counterpart to Solidity's `uint152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toUint152(uint256 value) internal pure returns (uint152) { + if (value > type(uint152).max) { + revert SafeCastOverflowedUintDowncast(152, value); + } + return uint152(value); + } + + /** + * @dev Returns the downcasted uint144 from uint256, reverting on + * overflow (when the input is greater than largest uint144). + * + * Counterpart to Solidity's `uint144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toUint144(uint256 value) internal pure returns (uint144) { + if (value > type(uint144).max) { + revert SafeCastOverflowedUintDowncast(144, value); + } + return uint144(value); + } + + /** + * @dev Returns the downcasted uint136 from uint256, reverting on + * overflow (when the input is greater than largest uint136). + * + * Counterpart to Solidity's `uint136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toUint136(uint256 value) internal pure returns (uint136) { + if (value > type(uint136).max) { + revert SafeCastOverflowedUintDowncast(136, value); + } + return uint136(value); + } + + /** + * @dev Returns the downcasted uint128 from uint256, reverting on + * overflow (when the input is greater than largest uint128). + * + * Counterpart to Solidity's `uint128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toUint128(uint256 value) internal pure returns (uint128) { + if (value > type(uint128).max) { + revert SafeCastOverflowedUintDowncast(128, value); + } + return uint128(value); + } + + /** + * @dev Returns the downcasted uint120 from uint256, reverting on + * overflow (when the input is greater than largest uint120). + * + * Counterpart to Solidity's `uint120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toUint120(uint256 value) internal pure returns (uint120) { + if (value > type(uint120).max) { + revert SafeCastOverflowedUintDowncast(120, value); + } + return uint120(value); + } + + /** + * @dev Returns the downcasted uint112 from uint256, reverting on + * overflow (when the input is greater than largest uint112). + * + * Counterpart to Solidity's `uint112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toUint112(uint256 value) internal pure returns (uint112) { + if (value > type(uint112).max) { + revert SafeCastOverflowedUintDowncast(112, value); + } + return uint112(value); + } + + /** + * @dev Returns the downcasted uint104 from uint256, reverting on + * overflow (when the input is greater than largest uint104). + * + * Counterpart to Solidity's `uint104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toUint104(uint256 value) internal pure returns (uint104) { + if (value > type(uint104).max) { + revert SafeCastOverflowedUintDowncast(104, value); + } + return uint104(value); + } + + /** + * @dev Returns the downcasted uint96 from uint256, reverting on + * overflow (when the input is greater than largest uint96). + * + * Counterpart to Solidity's `uint96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toUint96(uint256 value) internal pure returns (uint96) { + if (value > type(uint96).max) { + revert SafeCastOverflowedUintDowncast(96, value); + } + return uint96(value); + } + + /** + * @dev Returns the downcasted uint88 from uint256, reverting on + * overflow (when the input is greater than largest uint88). + * + * Counterpart to Solidity's `uint88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toUint88(uint256 value) internal pure returns (uint88) { + if (value > type(uint88).max) { + revert SafeCastOverflowedUintDowncast(88, value); + } + return uint88(value); + } + + /** + * @dev Returns the downcasted uint80 from uint256, reverting on + * overflow (when the input is greater than largest uint80). + * + * Counterpart to Solidity's `uint80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toUint80(uint256 value) internal pure returns (uint80) { + if (value > type(uint80).max) { + revert SafeCastOverflowedUintDowncast(80, value); + } + return uint80(value); + } + + /** + * @dev Returns the downcasted uint72 from uint256, reverting on + * overflow (when the input is greater than largest uint72). + * + * Counterpart to Solidity's `uint72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toUint72(uint256 value) internal pure returns (uint72) { + if (value > type(uint72).max) { + revert SafeCastOverflowedUintDowncast(72, value); + } + return uint72(value); + } + + /** + * @dev Returns the downcasted uint64 from uint256, reverting on + * overflow (when the input is greater than largest uint64). + * + * Counterpart to Solidity's `uint64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toUint64(uint256 value) internal pure returns (uint64) { + if (value > type(uint64).max) { + revert SafeCastOverflowedUintDowncast(64, value); + } + return uint64(value); + } + + /** + * @dev Returns the downcasted uint56 from uint256, reverting on + * overflow (when the input is greater than largest uint56). + * + * Counterpart to Solidity's `uint56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toUint56(uint256 value) internal pure returns (uint56) { + if (value > type(uint56).max) { + revert SafeCastOverflowedUintDowncast(56, value); + } + return uint56(value); + } + + /** + * @dev Returns the downcasted uint48 from uint256, reverting on + * overflow (when the input is greater than largest uint48). + * + * Counterpart to Solidity's `uint48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toUint48(uint256 value) internal pure returns (uint48) { + if (value > type(uint48).max) { + revert SafeCastOverflowedUintDowncast(48, value); + } + return uint48(value); + } + + /** + * @dev Returns the downcasted uint40 from uint256, reverting on + * overflow (when the input is greater than largest uint40). + * + * Counterpart to Solidity's `uint40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toUint40(uint256 value) internal pure returns (uint40) { + if (value > type(uint40).max) { + revert SafeCastOverflowedUintDowncast(40, value); + } + return uint40(value); + } + + /** + * @dev Returns the downcasted uint32 from uint256, reverting on + * overflow (when the input is greater than largest uint32). + * + * Counterpart to Solidity's `uint32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toUint32(uint256 value) internal pure returns (uint32) { + if (value > type(uint32).max) { + revert SafeCastOverflowedUintDowncast(32, value); + } + return uint32(value); + } + + /** + * @dev Returns the downcasted uint24 from uint256, reverting on + * overflow (when the input is greater than largest uint24). + * + * Counterpart to Solidity's `uint24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toUint24(uint256 value) internal pure returns (uint24) { + if (value > type(uint24).max) { + revert SafeCastOverflowedUintDowncast(24, value); + } + return uint24(value); + } + + /** + * @dev Returns the downcasted uint16 from uint256, reverting on + * overflow (when the input is greater than largest uint16). + * + * Counterpart to Solidity's `uint16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toUint16(uint256 value) internal pure returns (uint16) { + if (value > type(uint16).max) { + revert SafeCastOverflowedUintDowncast(16, value); + } + return uint16(value); + } + + /** + * @dev Returns the downcasted uint8 from uint256, reverting on + * overflow (when the input is greater than largest uint8). + * + * Counterpart to Solidity's `uint8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toUint8(uint256 value) internal pure returns (uint8) { + if (value > type(uint8).max) { + revert SafeCastOverflowedUintDowncast(8, value); + } + return uint8(value); + } + + /** + * @dev Converts a signed int256 into an unsigned uint256. + * + * Requirements: + * + * - input must be greater than or equal to 0. + */ + function toUint256(int256 value) internal pure returns (uint256) { + if (value < 0) { + revert SafeCastOverflowedIntToUint(value); + } + return uint256(value); + } + + /** + * @dev Returns the downcasted int248 from int256, reverting on + * overflow (when the input is less than smallest int248 or + * greater than largest int248). + * + * Counterpart to Solidity's `int248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toInt248(int256 value) internal pure returns (int248 downcasted) { + downcasted = int248(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(248, value); + } + } + + /** + * @dev Returns the downcasted int240 from int256, reverting on + * overflow (when the input is less than smallest int240 or + * greater than largest int240). + * + * Counterpart to Solidity's `int240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toInt240(int256 value) internal pure returns (int240 downcasted) { + downcasted = int240(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(240, value); + } + } + + /** + * @dev Returns the downcasted int232 from int256, reverting on + * overflow (when the input is less than smallest int232 or + * greater than largest int232). + * + * Counterpart to Solidity's `int232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toInt232(int256 value) internal pure returns (int232 downcasted) { + downcasted = int232(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(232, value); + } + } + + /** + * @dev Returns the downcasted int224 from int256, reverting on + * overflow (when the input is less than smallest int224 or + * greater than largest int224). + * + * Counterpart to Solidity's `int224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toInt224(int256 value) internal pure returns (int224 downcasted) { + downcasted = int224(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(224, value); + } + } + + /** + * @dev Returns the downcasted int216 from int256, reverting on + * overflow (when the input is less than smallest int216 or + * greater than largest int216). + * + * Counterpart to Solidity's `int216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toInt216(int256 value) internal pure returns (int216 downcasted) { + downcasted = int216(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(216, value); + } + } + + /** + * @dev Returns the downcasted int208 from int256, reverting on + * overflow (when the input is less than smallest int208 or + * greater than largest int208). + * + * Counterpart to Solidity's `int208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toInt208(int256 value) internal pure returns (int208 downcasted) { + downcasted = int208(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(208, value); + } + } + + /** + * @dev Returns the downcasted int200 from int256, reverting on + * overflow (when the input is less than smallest int200 or + * greater than largest int200). + * + * Counterpart to Solidity's `int200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toInt200(int256 value) internal pure returns (int200 downcasted) { + downcasted = int200(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(200, value); + } + } + + /** + * @dev Returns the downcasted int192 from int256, reverting on + * overflow (when the input is less than smallest int192 or + * greater than largest int192). + * + * Counterpart to Solidity's `int192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toInt192(int256 value) internal pure returns (int192 downcasted) { + downcasted = int192(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(192, value); + } + } + + /** + * @dev Returns the downcasted int184 from int256, reverting on + * overflow (when the input is less than smallest int184 or + * greater than largest int184). + * + * Counterpart to Solidity's `int184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toInt184(int256 value) internal pure returns (int184 downcasted) { + downcasted = int184(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(184, value); + } + } + + /** + * @dev Returns the downcasted int176 from int256, reverting on + * overflow (when the input is less than smallest int176 or + * greater than largest int176). + * + * Counterpart to Solidity's `int176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toInt176(int256 value) internal pure returns (int176 downcasted) { + downcasted = int176(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(176, value); + } + } + + /** + * @dev Returns the downcasted int168 from int256, reverting on + * overflow (when the input is less than smallest int168 or + * greater than largest int168). + * + * Counterpart to Solidity's `int168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toInt168(int256 value) internal pure returns (int168 downcasted) { + downcasted = int168(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(168, value); + } + } + + /** + * @dev Returns the downcasted int160 from int256, reverting on + * overflow (when the input is less than smallest int160 or + * greater than largest int160). + * + * Counterpart to Solidity's `int160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toInt160(int256 value) internal pure returns (int160 downcasted) { + downcasted = int160(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(160, value); + } + } + + /** + * @dev Returns the downcasted int152 from int256, reverting on + * overflow (when the input is less than smallest int152 or + * greater than largest int152). + * + * Counterpart to Solidity's `int152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toInt152(int256 value) internal pure returns (int152 downcasted) { + downcasted = int152(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(152, value); + } + } + + /** + * @dev Returns the downcasted int144 from int256, reverting on + * overflow (when the input is less than smallest int144 or + * greater than largest int144). + * + * Counterpart to Solidity's `int144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toInt144(int256 value) internal pure returns (int144 downcasted) { + downcasted = int144(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(144, value); + } + } + + /** + * @dev Returns the downcasted int136 from int256, reverting on + * overflow (when the input is less than smallest int136 or + * greater than largest int136). + * + * Counterpart to Solidity's `int136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toInt136(int256 value) internal pure returns (int136 downcasted) { + downcasted = int136(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(136, value); + } + } + + /** + * @dev Returns the downcasted int128 from int256, reverting on + * overflow (when the input is less than smallest int128 or + * greater than largest int128). + * + * Counterpart to Solidity's `int128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toInt128(int256 value) internal pure returns (int128 downcasted) { + downcasted = int128(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(128, value); + } + } + + /** + * @dev Returns the downcasted int120 from int256, reverting on + * overflow (when the input is less than smallest int120 or + * greater than largest int120). + * + * Counterpart to Solidity's `int120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toInt120(int256 value) internal pure returns (int120 downcasted) { + downcasted = int120(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(120, value); + } + } + + /** + * @dev Returns the downcasted int112 from int256, reverting on + * overflow (when the input is less than smallest int112 or + * greater than largest int112). + * + * Counterpart to Solidity's `int112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toInt112(int256 value) internal pure returns (int112 downcasted) { + downcasted = int112(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(112, value); + } + } + + /** + * @dev Returns the downcasted int104 from int256, reverting on + * overflow (when the input is less than smallest int104 or + * greater than largest int104). + * + * Counterpart to Solidity's `int104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toInt104(int256 value) internal pure returns (int104 downcasted) { + downcasted = int104(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(104, value); + } + } + + /** + * @dev Returns the downcasted int96 from int256, reverting on + * overflow (when the input is less than smallest int96 or + * greater than largest int96). + * + * Counterpart to Solidity's `int96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toInt96(int256 value) internal pure returns (int96 downcasted) { + downcasted = int96(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(96, value); + } + } + + /** + * @dev Returns the downcasted int88 from int256, reverting on + * overflow (when the input is less than smallest int88 or + * greater than largest int88). + * + * Counterpart to Solidity's `int88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toInt88(int256 value) internal pure returns (int88 downcasted) { + downcasted = int88(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(88, value); + } + } + + /** + * @dev Returns the downcasted int80 from int256, reverting on + * overflow (when the input is less than smallest int80 or + * greater than largest int80). + * + * Counterpart to Solidity's `int80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toInt80(int256 value) internal pure returns (int80 downcasted) { + downcasted = int80(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(80, value); + } + } + + /** + * @dev Returns the downcasted int72 from int256, reverting on + * overflow (when the input is less than smallest int72 or + * greater than largest int72). + * + * Counterpart to Solidity's `int72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toInt72(int256 value) internal pure returns (int72 downcasted) { + downcasted = int72(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(72, value); + } + } + + /** + * @dev Returns the downcasted int64 from int256, reverting on + * overflow (when the input is less than smallest int64 or + * greater than largest int64). + * + * Counterpart to Solidity's `int64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toInt64(int256 value) internal pure returns (int64 downcasted) { + downcasted = int64(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(64, value); + } + } + + /** + * @dev Returns the downcasted int56 from int256, reverting on + * overflow (when the input is less than smallest int56 or + * greater than largest int56). + * + * Counterpart to Solidity's `int56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toInt56(int256 value) internal pure returns (int56 downcasted) { + downcasted = int56(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(56, value); + } + } + + /** + * @dev Returns the downcasted int48 from int256, reverting on + * overflow (when the input is less than smallest int48 or + * greater than largest int48). + * + * Counterpart to Solidity's `int48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toInt48(int256 value) internal pure returns (int48 downcasted) { + downcasted = int48(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(48, value); + } + } + + /** + * @dev Returns the downcasted int40 from int256, reverting on + * overflow (when the input is less than smallest int40 or + * greater than largest int40). + * + * Counterpart to Solidity's `int40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toInt40(int256 value) internal pure returns (int40 downcasted) { + downcasted = int40(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(40, value); + } + } + + /** + * @dev Returns the downcasted int32 from int256, reverting on + * overflow (when the input is less than smallest int32 or + * greater than largest int32). + * + * Counterpart to Solidity's `int32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toInt32(int256 value) internal pure returns (int32 downcasted) { + downcasted = int32(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(32, value); + } + } + + /** + * @dev Returns the downcasted int24 from int256, reverting on + * overflow (when the input is less than smallest int24 or + * greater than largest int24). + * + * Counterpart to Solidity's `int24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toInt24(int256 value) internal pure returns (int24 downcasted) { + downcasted = int24(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(24, value); + } + } + + /** + * @dev Returns the downcasted int16 from int256, reverting on + * overflow (when the input is less than smallest int16 or + * greater than largest int16). + * + * Counterpart to Solidity's `int16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toInt16(int256 value) internal pure returns (int16 downcasted) { + downcasted = int16(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(16, value); + } + } + + /** + * @dev Returns the downcasted int8 from int256, reverting on + * overflow (when the input is less than smallest int8 or + * greater than largest int8). + * + * Counterpart to Solidity's `int8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toInt8(int256 value) internal pure returns (int8 downcasted) { + downcasted = int8(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(8, value); + } + } + + /** + * @dev Converts an unsigned uint256 into a signed int256. + * + * Requirements: + * + * - input must be less than or equal to maxInt256. + */ + function toInt256(uint256 value) internal pure returns (int256) { + // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive + if (value > uint256(type(int256).max)) { + revert SafeCastOverflowedUintToInt(value); + } + return int256(value); + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } + } +} + +// lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) + +/** + * @dev Standard ERC20 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. + */ +interface IERC20Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC20InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC20InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `spender`โ€™s `allowance`. Used in transfers. + * @param spender Address that may be allowed to operate on tokens without being their owner. + * @param allowance Amount of tokens a `spender` is allowed to operate with. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC20InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `spender` to be approved. Used in approvals. + * @param spender Address that may be allowed to operate on tokens without being their owner. + */ + error ERC20InvalidSpender(address spender); +} + +/** + * @dev Standard ERC721 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. + */ +interface IERC721Errors { + /** + * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. + * Used in balance queries. + * @param owner Address of the current owner of a token. + */ + error ERC721InvalidOwner(address owner); + + /** + * @dev Indicates a `tokenId` whose `owner` is the zero address. + * @param tokenId Identifier number of a token. + */ + error ERC721NonexistentToken(uint256 tokenId); + + /** + * @dev Indicates an error related to the ownership over a particular token. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param tokenId Identifier number of a token. + * @param owner Address of the current owner of a token. + */ + error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC721InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC721InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`โ€™s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param tokenId Identifier number of a token. + */ + error ERC721InsufficientApproval(address operator, uint256 tokenId); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC721InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC721InvalidOperator(address operator); +} + +/** + * @dev Standard ERC1155 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. + */ +interface IERC1155Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + * @param tokenId Identifier number of a token. + */ + error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC1155InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC1155InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`โ€™s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param owner Address of the current owner of a token. + */ + error ERC1155MissingApprovalForAll(address operator, address owner); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC1155InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC1155InvalidOperator(address operator); + + /** + * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. + * Used in batch transfers. + * @param idsLength Length of the array of token identifiers + * @param valuesLength Length of the array of token amounts + */ + error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); +} + +// lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol) +// This file was procedurally generated from scripts/generate/templates/Checkpoints.js. + +/** + * @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + */ +library Checkpoints { + /** + * @dev A value was attempted to be inserted on a past checkpoint. + */ + error CheckpointUnorderedInsertion(); + + struct Trace224 { + Checkpoint224[] _checkpoints; + } + + struct Checkpoint224 { + uint32 _key; + uint224 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the + * library. + */ + function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if + * there is none. + */ + function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + */ + function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + * + * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high + * keys). + */ + function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) { + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._key) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ + function latest(Trace224 storage self) internal view returns (uint224) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace224 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint224 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint224({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint224({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` + * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive + * `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or + * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and + * exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _lowerBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint224[] storage self, + uint256 pos + ) private pure returns (Checkpoint224 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace208 { + Checkpoint208[] _checkpoints; + } + + struct Checkpoint208 { + uint48 _key; + uint208 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the + * library. + */ + function push(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if + * there is none. + */ + function lowerLookup(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + */ + function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + * + * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high + * keys). + */ + function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._key) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ + function latest(Trace208 storage self) internal view returns (uint208) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint208 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace208 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint208[] storage self, uint48 key, uint208 value) private returns (uint208, uint208) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint208 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint208({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint208({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` + * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive + * `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Checkpoint208[] storage self, + uint48 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or + * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and + * exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _lowerBinaryLookup( + Checkpoint208[] storage self, + uint48 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint208[] storage self, + uint256 pos + ) private pure returns (Checkpoint208 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace160 { + Checkpoint160[] _checkpoints; + } + + struct Checkpoint160 { + uint96 _key; + uint160 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the + * library. + */ + function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if + * there is none. + */ + function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + */ + function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + * + * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high + * keys). + */ + function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) { + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._key) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ + function latest(Trace160 storage self) internal view returns (uint160) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace160 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint160 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint160({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint160({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` + * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive + * `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or + * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and + * exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _lowerBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint160[] storage self, + uint256 pos + ) private pure returns (Checkpoint160 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract ContextUpgradeable is Initializable { + function __Context_init() internal onlyInitializing { + } + + function __Context_init_unchained() internal onlyInitializing { + } + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } + + function _contextSuffixLength() internal view virtual returns (uint256) { + return 0; + } +} + +// lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + */ +interface IERC20Metadata is IERC20_0 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} + +// src/interfaces/IVotingMultipliers.sol + +/// @title IVotingMultipliers +/// @notice Interface for the VotingMultipliers contract +/// @dev This interface defines the structure and functions for managing voting multipliers +interface IVotingMultipliers { + /// @notice Thrown when attempting to add a multiplier that is already allowlisted + error MultiplierAlreadyAllowlisted(); + /// @notice Thrown when attempting to remove a multiplier that is not allowlisted + error MultiplierNotAllowlisted(); + /// @notice Thrown when an invalid multiplier index is provided + error InvalidMultiplierIndex(); + + /// @notice Emitted when a new multiplier is added to the allowlist + /// @param multiplier The address of the added multiplier + event MultiplierAdded(IMultiplier indexed multiplier); + /// @notice Emitted when a multiplier is removed from the allowlist + /// @param multiplier The address of the removed multiplier + event MultiplierRemoved(IMultiplier indexed multiplier); + + /// @notice Returns the multiplier at the specified index in the allowlist + /// @param index The index of the multiplier in the allowlist + /// @return The multiplier contract at the specified index + function allowlistedMultipliers(uint256 index) external view returns (IMultiplier); + /// @notice Returns the array of allowlisted multipliers + /// @return IMultiplier[] The array of allowlisted multiplier contracts + function allowlistedMultipliers() external view returns (IMultiplier[] memory); + /// @notice Calculates the total multiplier for a given _user + /// @param __user The address of the _user + /// @return The total multiplier value for the _user + function getTotalMultipliers(address __user) external view returns (uint256); + /// @notice Adds a multiplier to the allowlist + /// @param _multiplier The multiplier contract to be added + function addMultiplier(IMultiplier _multiplier) external; + /// @notice Removes a multiplier from the allowlist + /// @param _multiplier The multiplier contract to be removed + function removeMultiplier(IMultiplier _multiplier) external; +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/NoncesUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol) + +/** + * @dev Provides tracking nonces for addresses. Nonces will only increment. + */ +abstract contract NoncesUpgradeable is Initializable { + /** + * @dev The nonce used for an `account` is not the expected current nonce. + */ + error InvalidAccountNonce(address account, uint256 currentNonce); + + /// @custom:storage-location erc7201:openzeppelin.storage.Nonces + struct NoncesStorage { + mapping(address account => uint256) _nonces; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Nonces")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant NoncesStorageLocation = 0x5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00; + + function _getNoncesStorage() private pure returns (NoncesStorage storage $) { + assembly { + $.slot := NoncesStorageLocation + } + } + + function __Nonces_init() internal onlyInitializing { + } + + function __Nonces_init_unchained() internal onlyInitializing { + } + /** + * @dev Returns the next unused nonce for an address. + */ + function nonces(address owner) public view virtual returns (uint256) { + NoncesStorage storage $ = _getNoncesStorage(); + return $._nonces[owner]; + } + + /** + * @dev Consumes a nonce. + * + * Returns the current value and increments nonce. + */ + function _useNonce(address owner) internal virtual returns (uint256) { + NoncesStorage storage $ = _getNoncesStorage(); + // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be + // decremented or reset. This guarantees that the nonce never overflows. + unchecked { + // It is important to do x++ and not ++x here. + return $._nonces[owner]++; + } + } + + /** + * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. + */ + function _useCheckedNonce(address owner, uint256 nonce) internal virtual { + uint256 current = _useNonce(owner); + if (nonce != current) { + revert InvalidAccountNonce(owner, current); + } + } +} + +// lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5805.sol) + +interface IERC5805 is IERC6372, IVotes {} + +// lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is set to the address provided by the deployer. This can + * later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { + /// @custom:storage-location erc7201:openzeppelin.storage.Ownable + struct OwnableStorage { + address _owner; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; + + function _getOwnableStorage() private pure returns (OwnableStorage storage $) { + assembly { + $.slot := OwnableStorageLocation + } + } + + /** + * @dev The caller account is not authorized to perform an operation. + */ + error OwnableUnauthorizedAccount(address account); + + /** + * @dev The owner is not a valid owner account. (eg. `address(0)`) + */ + error OwnableInvalidOwner(address owner); + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the address provided by the deployer as the initial owner. + */ + function __Ownable_init(address initialOwner) internal onlyInitializing { + __Ownable_init_unchained(initialOwner); + } + + function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { + if (initialOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(initialOwner); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + OwnableStorage storage $ = _getOwnableStorage(); + return $._owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + if (owner() != _msgSender()) { + revert OwnableUnauthorizedAccount(_msgSender()); + } + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + if (newOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + OwnableStorage storage $ = _getOwnableStorage(); + address oldOwner = $._owner; + $._owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + +// lib/openzeppelin-contracts/contracts/utils/Strings.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant HEX_DIGITS = "0123456789abcdef"; + uint8 private constant ADDRESS_LENGTH = 20; + + /** + * @dev The `value` string doesn't fit in the specified `length`. + */ + error StringsInsufficientHexLength(uint256 value, uint256 length); + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toStringSigned(int256 value) internal pure returns (string memory) { + return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + uint256 localValue = value; + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = HEX_DIGITS[localValue & 0xf]; + localValue >>= 4; + } + if (localValue != 0) { + revert StringsInsufficientHexLength(value, length); + } + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal + * representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); + } +} + +// lib/openzeppelin-contracts/contracts/utils/types/Time.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol) + +/** + * @dev This library provides helpers for manipulating time-related objects. + * + * It uses the following types: + * - `uint48` for timepoints + * - `uint32` for durations + * + * While the library doesn't provide specific types for timepoints and duration, it does provide: + * - a `Delay` type to represent duration that can be programmed to change value automatically at a given point + * - additional helper functions + */ +library Time { + using Time for *; + + /** + * @dev Get the block timestamp as a Timepoint. + */ + function timestamp() internal view returns (uint48) { + return SafeCast.toUint48(block.timestamp); + } + + /** + * @dev Get the block number as a Timepoint. + */ + function blockNumber() internal view returns (uint48) { + return SafeCast.toUint48(block.number); + } + + // ==================================================== Delay ===================================================== + /** + * @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the + * future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value. + * This allows updating the delay applied to some operation while keeping some guarantees. + * + * In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for + * some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set + * the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should + * still apply for some time. + * + * + * The `Delay` type is 112 bits long, and packs the following: + * + * ``` + * | [uint48]: effect date (timepoint) + * | | [uint32]: value before (duration) + * โ†“ โ†“ โ†“ [uint32]: value after (duration) + * 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC + * ``` + * + * NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently + * supported. + */ + type Delay is uint112; + + /** + * @dev Wrap a duration into a Delay to add the one-step "update in the future" feature + */ + function toDelay(uint32 duration) internal pure returns (Delay) { + return Delay.wrap(duration); + } + + /** + * @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled + * change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered. + */ + function _getFullAt(Delay self, uint48 timepoint) private pure returns (uint32, uint32, uint48) { + (uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack(); + return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect); + } + + /** + * @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the + * effect timepoint is 0, then the pending value should not be considered. + */ + function getFull(Delay self) internal view returns (uint32, uint32, uint48) { + return _getFullAt(self, timestamp()); + } + + /** + * @dev Get the current value. + */ + function get(Delay self) internal view returns (uint32) { + (uint32 delay, , ) = self.getFull(); + return delay; + } + + /** + * @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to + * enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the + * new delay becomes effective. + */ + function withUpdate( + Delay self, + uint32 newValue, + uint32 minSetback + ) internal view returns (Delay updatedDelay, uint48 effect) { + uint32 value = self.get(); + uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0)); + effect = timestamp() + setback; + return (pack(value, newValue, effect), effect); + } + + /** + * @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint). + */ + function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) { + uint112 raw = Delay.unwrap(self); + + valueAfter = uint32(raw); + valueBefore = uint32(raw >> 32); + effect = uint48(raw >> 64); + + return (valueBefore, valueAfter, effect); + } + + /** + * @dev pack the components into a Delay object. + */ + function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) { + return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter)); + } +} + +// lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) + +/** + * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. + * + * The library provides methods for generating a hash of a message that conforms to the + * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] + * specifications. + */ +library MessageHashUtils { + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x45` (`personal_sign` messages). + * + * The digest is calculated by prefixing a bytes32 `messageHash` with + * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the + * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. + * + * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with + * keccak256, although any bytes32 value can be safely used because the final digest will + * be re-hashed. + * + * See {ECDSA-recover}. + */ + function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash + mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix + digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) + } + } + + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x45` (`personal_sign` messages). + * + * The digest is calculated by prefixing an arbitrary `message` with + * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the + * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. + * + * See {ECDSA-recover}. + */ + function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { + return + keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); + } + + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x00` (data with intended validator). + * + * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended + * `validator` address. Then hashing the result. + * + * See {ECDSA-recover}. + */ + function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(hex"19_00", validator, data)); + } + + /** + * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). + * + * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with + * `\x19\x01` and hashing the result. It corresponds to the hash signed by the + * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. + * + * See {ECDSA-recover}. + */ + function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) + mstore(ptr, hex"19_01") + mstore(add(ptr, 0x02), domainSeparator) + mstore(add(ptr, 0x22), structHash) + digest := keccak256(ptr, 0x42) + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/access/Ownable2StepUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) + +/** + * @dev Contract module which provides access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is specified at deployment time in the constructor for `Ownable`. This + * can later be changed with {transferOwnership} and {acceptOwnership}. + * + * This module is used through inheritance. It will make available all functions + * from parent (Ownable). + */ +abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable { + /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step + struct Ownable2StepStorage { + address _pendingOwner; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00; + + function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) { + assembly { + $.slot := Ownable2StepStorageLocation + } + } + + event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); + + function __Ownable2Step_init() internal onlyInitializing { + } + + function __Ownable2Step_init_unchained() internal onlyInitializing { + } + /** + * @dev Returns the address of the pending owner. + */ + function pendingOwner() public view virtual returns (address) { + Ownable2StepStorage storage $ = _getOwnable2StepStorage(); + return $._pendingOwner; + } + + /** + * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual override onlyOwner { + Ownable2StepStorage storage $ = _getOwnable2StepStorage(); + $._pendingOwner = newOwner; + emit OwnershipTransferStarted(owner(), newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual override { + Ownable2StepStorage storage $ = _getOwnable2StepStorage(); + delete $._pendingOwner; + super._transferOwnership(newOwner); + } + + /** + * @dev The new owner accepts the ownership transfer. + */ + function acceptOwnership() public virtual { + address sender = _msgSender(); + if (pendingOwner() != sender) { + revert OwnableUnauthorizedAccount(sender); + } + _transferOwnership(sender); + } +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using Address for address; + + /** + * @dev An operation with an ERC20 token failed. + */ + error SafeERC20FailedOperation(address token); + + /** + * @dev Indicates a failed `decreaseAllowance` request. + */ + error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); + + /** + * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, + * non-reverting calls are assumed to be successful. + */ + function safeTransfer(IERC20_1 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); + } + + /** + * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the + * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. + */ + function safeTransferFrom(IERC20_1 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); + } + + /** + * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, + * non-reverting calls are assumed to be successful. + */ + function safeIncreaseAllowance(IERC20_1 token, address spender, uint256 value) internal { + uint256 oldAllowance = token.allowance(address(this), spender); + forceApprove(token, spender, oldAllowance + value); + } + + /** + * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no + * value, non-reverting calls are assumed to be successful. + */ + function safeDecreaseAllowance(IERC20_1 token, address spender, uint256 requestedDecrease) internal { + unchecked { + uint256 currentAllowance = token.allowance(address(this), spender); + if (currentAllowance < requestedDecrease) { + revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); + } + forceApprove(token, spender, currentAllowance - requestedDecrease); + } + } + + /** + * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, + * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval + * to be set to zero before setting it to a non-zero value, such as USDT. + */ + function forceApprove(IERC20_1 token, address spender, uint256 value) internal { + bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); + + if (!_callOptionalReturnBool(token, approvalCall)) { + _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); + _callOptionalReturn(token, approvalCall); + } + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + */ + function _callOptionalReturn(IERC20_1 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data); + if (returndata.length != 0 && !abi.decode(returndata, (bool))) { + revert SafeERC20FailedOperation(address(token)); + } + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + * + * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. + */ + function _callOptionalReturnBool(IERC20_1 token, bytes memory data) private returns (bool) { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false + // and not revert is the subcall reverts. + + (bool success, bytes memory returndata) = address(token).call(data); + return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC20 + * applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + */ +abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20_0, IERC20Metadata, IERC20Errors { + /// @custom:storage-location erc7201:openzeppelin.storage.ERC20 + struct ERC20Storage { + mapping(address account => uint256) _balances; + + mapping(address account => mapping(address spender => uint256)) _allowances; + + uint256 _totalSupply; + + string _name; + string _symbol; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00; + + function _getERC20Storage() private pure returns (ERC20Storage storage $) { + assembly { + $.slot := ERC20StorageLocation + } + } + + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { + __ERC20_init_unchained(name_, symbol_); + } + + function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { + ERC20Storage storage $ = _getERC20Storage(); + $._name = name_; + $._symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual returns (string memory) { + ERC20Storage storage $ = _getERC20Storage(); + return $._name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual returns (string memory) { + ERC20Storage storage $ = _getERC20Storage(); + return $._symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual returns (uint256) { + ERC20Storage storage $ = _getERC20Storage(); + return $._totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual returns (uint256) { + ERC20Storage storage $ = _getERC20Storage(); + return $._balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `value`. + */ + function transfer(address to, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, value); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual returns (uint256) { + ERC20Storage storage $ = _getERC20Storage(); + return $._allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, value); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `value`. + * - the caller must have allowance for ``from``'s tokens of at least + * `value`. + */ + function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, value); + _transfer(from, to, value); + return true; + } + + /** + * @dev Moves a `value` amount of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _transfer(address from, address to, uint256 value) internal { + if (from == address(0)) { + revert ERC20InvalidSender(address(0)); + } + if (to == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(from, to, value); + } + + /** + * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding + * this function. + * + * Emits a {Transfer} event. + */ + function _update(address from, address to, uint256 value) internal virtual { + ERC20Storage storage $ = _getERC20Storage(); + if (from == address(0)) { + // Overflow check required: The rest of the code assumes that totalSupply never overflows + $._totalSupply += value; + } else { + uint256 fromBalance = $._balances[from]; + if (fromBalance < value) { + revert ERC20InsufficientBalance(from, fromBalance, value); + } + unchecked { + // Overflow not possible: value <= fromBalance <= totalSupply. + $._balances[from] = fromBalance - value; + } + } + + if (to == address(0)) { + unchecked { + // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. + $._totalSupply -= value; + } + } else { + unchecked { + // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. + $._balances[to] += value; + } + } + + emit Transfer(from, to, value); + } + + /** + * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). + * Relies on the `_update` mechanism + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _mint(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(address(0), account, value); + } + + /** + * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead + */ + function _burn(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidSender(address(0)); + } + _update(account, address(0), value); + } + + /** + * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + * + * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. + */ + function _approve(address owner, address spender, uint256 value) internal { + _approve(owner, spender, value, true); + } + + /** + * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. + * + * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by + * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any + * `Approval` event during `transferFrom` operations. + * + * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to + * true using the following override: + * ``` + * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { + * super._approve(owner, spender, value, true); + * } + * ``` + * + * Requirements are the same as {_approve}. + */ + function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { + ERC20Storage storage $ = _getERC20Storage(); + if (owner == address(0)) { + revert ERC20InvalidApprover(address(0)); + } + if (spender == address(0)) { + revert ERC20InvalidSpender(address(0)); + } + $._allowances[owner][spender] = value; + if (emitEvent) { + emit Approval(owner, spender, value); + } + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `value`. + * + * Does not update the allowance value in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Does not emit an {Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 value) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + if (currentAllowance < value) { + revert ERC20InsufficientAllowance(spender, currentAllowance, value); + } + unchecked { + _approve(owner, spender, currentAllowance - value, false); + } + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol) + +/** + * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. + * + * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose + * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract + * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to + * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. + * + * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding + * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA + * ({_hashTypedDataV4}). + * + * The implementation of the domain separator was designed to be as efficient as possible while still properly updating + * the chain id to protect against replay attacks on an eventual fork of the chain. + * + * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method + * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. + * + * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain + * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the + * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. + */ +abstract contract EIP712Upgradeable is Initializable, IERC5267 { + bytes32 private constant TYPE_HASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + + /// @custom:storage-location erc7201:openzeppelin.storage.EIP712 + struct EIP712Storage { + /// @custom:oz-renamed-from _HASHED_NAME + bytes32 _hashedName; + /// @custom:oz-renamed-from _HASHED_VERSION + bytes32 _hashedVersion; + + string _name; + string _version; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.EIP712")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100; + + function _getEIP712Storage() private pure returns (EIP712Storage storage $) { + assembly { + $.slot := EIP712StorageLocation + } + } + + /** + * @dev Initializes the domain separator and parameter caches. + * + * The meaning of `name` and `version` is specified in + * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: + * + * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. + * - `version`: the current major version of the signing domain. + * + * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart + * contract upgrade]. + */ + function __EIP712_init(string memory name, string memory version) internal onlyInitializing { + __EIP712_init_unchained(name, version); + } + + function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { + EIP712Storage storage $ = _getEIP712Storage(); + $._name = name; + $._version = version; + + // Reset prior values in storage if upgrading + $._hashedName = 0; + $._hashedVersion = 0; + } + + /** + * @dev Returns the domain separator for the current chain. + */ + function _domainSeparatorV4() internal view returns (bytes32) { + return _buildDomainSeparator(); + } + + function _buildDomainSeparator() private view returns (bytes32) { + return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this))); + } + + /** + * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this + * function returns the hash of the fully encoded EIP712 message for this domain. + * + * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: + * + * ```solidity + * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( + * keccak256("Mail(address to,string contents)"), + * mailTo, + * keccak256(bytes(mailContents)) + * ))); + * address signer = ECDSA.recover(digest, signature); + * ``` + */ + function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { + return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); + } + + /** + * @dev See {IERC-5267}. + */ + function eip712Domain() + public + view + virtual + returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ) + { + EIP712Storage storage $ = _getEIP712Storage(); + // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized + // and the EIP712 domain is not reliable, as it will be missing name and version. + require($._hashedName == 0 && $._hashedVersion == 0, "EIP712: Uninitialized"); + + return ( + hex"0f", // 01111 + _EIP712Name(), + _EIP712Version(), + block.chainid, + address(this), + bytes32(0), + new uint256[](0) + ); + } + + /** + * @dev The name parameter for the EIP712 domain. + * + * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs + * are a concern. + */ + function _EIP712Name() internal view virtual returns (string memory) { + EIP712Storage storage $ = _getEIP712Storage(); + return $._name; + } + + /** + * @dev The version parameter for the EIP712 domain. + * + * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs + * are a concern. + */ + function _EIP712Version() internal view virtual returns (string memory) { + EIP712Storage storage $ = _getEIP712Storage(); + return $._version; + } + + /** + * @dev The hash of the name parameter for the EIP712 domain. + * + * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. + */ + function _EIP712NameHash() internal view returns (bytes32) { + EIP712Storage storage $ = _getEIP712Storage(); + string memory name = _EIP712Name(); + if (bytes(name).length > 0) { + return keccak256(bytes(name)); + } else { + // If the name is empty, the contract may have been upgraded without initializing the new storage. + // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. + bytes32 hashedName = $._hashedName; + if (hashedName != 0) { + return hashedName; + } else { + return keccak256(""); + } + } + } + + /** + * @dev The hash of the version parameter for the EIP712 domain. + * + * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. + */ + function _EIP712VersionHash() internal view returns (bytes32) { + EIP712Storage storage $ = _getEIP712Storage(); + string memory version = _EIP712Version(); + if (bytes(version).length > 0) { + return keccak256(bytes(version)); + } else { + // If the version is empty, the contract may have been upgraded without initializing the new storage. + // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. + bytes32 hashedVersion = $._hashedVersion; + if (hashedVersion != 0) { + return hashedVersion; + } else { + return keccak256(""); + } + } + } +} + +// src/VotingMultipliers.sol + +/// @title VotingMultipliers +/// @notice A contract for managing voting multipliers +/// @dev Implements IVotingMultipliers interface +contract VotingMultipliers is Ownable2StepUpgradeable, IVotingMultipliers { + /// @custom:storage-location erc7201:breadchain.VotingMultipliers.storage + struct VotingMultipliersStorage { + IMultiplier[] allowlistedMultipliers; + } + + // keccak256(abi.encode(uint256(keccak256("breadchain.VotingMultipliers.storage")) - 1)) & ~bytes32(uint256(0xff)); + bytes32 private constant VOTING_MULTIPLIERS_STORAGE_LOCATION = 0xf8ea84bd4d45550952f40e913fd59ad03bae30b4f3dc5a09695fefe1d0465d00; + + /// @notice Initializes the contract + function initialize() public initializer { + __Ownable_init(msg.sender); + } + + function _getVotingMultipliersStorage() private pure returns (VotingMultipliersStorage storage $) { + assembly { + $.slot := VOTING_MULTIPLIERS_STORAGE_LOCATION + } + } + + /// @notice Returns the multiplier at the given index + /// @param index The index of the multiplier + /// @return multiplier The multiplier at the given index + function allowlistedMultipliers(uint256 index) external view returns (IMultiplier multiplier) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + return $.allowlistedMultipliers[index]; + } + + /// @notice Returns the array of allowlisted multipliers + /// @return IMultiplier[] The array of allowlisted multipliers + function allowlistedMultipliers() external view returns (IMultiplier[] memory) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + return $.allowlistedMultipliers; + } + + /// @notice Adds a multiplier to the allowlist + /// @param _multiplier The multiplier contract to be added + function addMultiplier(IMultiplier _multiplier) external onlyOwner { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + // Check if the multiplier is already allowlisted + for (uint256 i = 0; i < $.allowlistedMultipliers.length; i++) { + if ($.allowlistedMultipliers[i] == _multiplier) { + revert MultiplierAlreadyAllowlisted(); + } + } + $.allowlistedMultipliers.push(_multiplier); + emit MultiplierAdded(_multiplier); + } + + /// @notice Removes a multiplier from the allowlist + /// @param _multiplier The multiplier contract to be removed + function removeMultiplier(IMultiplier _multiplier) external onlyOwner { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + bool isallowlisted = false; + for (uint256 i = 0; i < $.allowlistedMultipliers.length; i++) { + if ($.allowlistedMultipliers[i] == _multiplier) { + $.allowlistedMultipliers[i] = $.allowlistedMultipliers[$.allowlistedMultipliers.length - 1]; + $.allowlistedMultipliers.pop(); + isallowlisted = true; + emit MultiplierRemoved(_multiplier); + break; + } + } + if (!isallowlisted) { + revert MultiplierNotAllowlisted(); + } + } + + /// @notice Gets the indexes of valid multipliers for a user + /// @param _user The address of the user + /// @return uint256[] Array of valid multiplier indexes + function getValidMultiplierIndexes(address _user) public view returns (uint256[] memory) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + uint256[] memory validIndexes = new uint256[]($.allowlistedMultipliers.length); + uint256 count = 0; + + for (uint256 i = 0; i < $.allowlistedMultipliers.length; i++) { + if ( + block.number <= $.allowlistedMultipliers[i].validUntil(_user) + && $.allowlistedMultipliers[i].getMultiplyingFactor(_user) > 0 + ) { + validIndexes[count] = i; + count++; + } + } + + // Create correctly sized array + uint256[] memory result = new uint256[](count); + for (uint256 i = 0; i < count; i++) { + result[i] = validIndexes[i]; + } + return result; + } + + /// @notice Calculates the total multiplier for a given user using specific multiplier indexes + /// @notice Performs the updateMultiplyingFactor function for each multiplier to ensure the multiplier is up to date + /// @param _user The address of the user + /// @param _multiplierIndexes Array of multiplier indexes to use + /// @return The total multiplier value for the user + function calculateTotalMultipliers(address _user, uint256[] calldata _multiplierIndexes) public returns (uint256) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + uint256 _totalMultiplier = MultiplierConstants.BASE_MULTIPLIER; + + for (uint256 i = 0; i < _multiplierIndexes.length; i++) { + uint256 index = _multiplierIndexes[i]; + if (index >= $.allowlistedMultipliers.length) { + revert InvalidMultiplierIndex(); + } + + IMultiplier multiplier = $.allowlistedMultipliers[index]; + multiplier.updateMultiplyingFactor(_user); + if (block.number <= multiplier.validUntil(_user)) { + uint256 factor = multiplier.getMultiplyingFactor(_user); + if (factor > MultiplierConstants.BASE_MULTIPLIER) { + // Add only the bonus amount to the total + _totalMultiplier += (factor - MultiplierConstants.BASE_MULTIPLIER); + } + } + } + return Math.max(_totalMultiplier, MultiplierConstants.BASE_MULTIPLIER); + } + + /// @notice Calculates the total multiplier for a given user + /// @param _user The address of the _user + /// @return The total multiplier value for the _user + /// @dev This function is intended for frontend and testing purposes + function getTotalMultipliers(address _user) public view returns (uint256) { + VotingMultipliersStorage storage $ = _getVotingMultipliersStorage(); + + uint256 _totalMultiplier = MultiplierConstants.BASE_MULTIPLIER; + for (uint256 i = 0; i < $.allowlistedMultipliers.length; i++) { + IMultiplier multiplier = $.allowlistedMultipliers[i]; + if (block.number <= multiplier.validUntil(_user)) { + uint256 factor = multiplier.getMultiplyingFactor(_user); + if (factor > MultiplierConstants.BASE_MULTIPLIER) { + // Add only the bonus amount to the total + _totalMultiplier += (factor - MultiplierConstants.BASE_MULTIPLIER); + } + } + } + return Math.max(_totalMultiplier, MultiplierConstants.BASE_MULTIPLIER); + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/governance/utils/VotesUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/Votes.sol) + +/** + * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be + * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of + * "representative" that will pool delegated voting units from different accounts and can then use it to vote in + * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to + * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative. + * + * This contract is often combined with a token contract such that voting units correspond to token units. For an + * example, see {ERC721Votes}. + * + * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed + * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the + * cost of this history tracking optional. + * + * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return + * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the + * previous example, it would be included in {ERC721-_update}). + */ +abstract contract VotesUpgradeable is Initializable, ContextUpgradeable, EIP712Upgradeable, NoncesUpgradeable, IERC5805 { + using Checkpoints for Checkpoints.Trace208; + + bytes32 private constant DELEGATION_TYPEHASH = + keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); + + /// @custom:storage-location erc7201:openzeppelin.storage.Votes + struct VotesStorage { + mapping(address account => address) _delegatee; + + mapping(address delegatee => Checkpoints.Trace208) _delegateCheckpoints; + + Checkpoints.Trace208 _totalCheckpoints; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Votes")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant VotesStorageLocation = 0xe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00; + + function _getVotesStorage() private pure returns (VotesStorage storage $) { + assembly { + $.slot := VotesStorageLocation + } + } + + /** + * @dev The clock was incorrectly modified. + */ + error ERC6372InconsistentClock(); + + /** + * @dev Lookup to future votes is not available. + */ + error ERC5805FutureLookup(uint256 timepoint, uint48 clock); + + function __Votes_init() internal onlyInitializing { + } + + function __Votes_init_unchained() internal onlyInitializing { + } + /** + * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based + * checkpoints (and voting), in which case {CLOCK_MODE} should be overridden as well to match. + */ + function clock() public view virtual returns (uint48) { + return Time.blockNumber(); + } + + /** + * @dev Machine-readable description of the clock as specified in EIP-6372. + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual returns (string memory) { + // Check that the clock was not modified + if (clock() != Time.blockNumber()) { + revert ERC6372InconsistentClock(); + } + return "mode=blocknumber&from=default"; + } + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) public view virtual returns (uint256) { + VotesStorage storage $ = _getVotesStorage(); + return $._delegateCheckpoints[account].latest(); + } + + /** + * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastVotes(address account, uint256 timepoint) public view virtual returns (uint256) { + VotesStorage storage $ = _getVotesStorage(); + uint48 currentTimepoint = clock(); + if (timepoint >= currentTimepoint) { + revert ERC5805FutureLookup(timepoint, currentTimepoint); + } + return $._delegateCheckpoints[account].upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value at the end of the corresponding block. + * + * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. + * Votes that have not been delegated are still part of total supply, even though they would not participate in a + * vote. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastTotalSupply(uint256 timepoint) public view virtual returns (uint256) { + VotesStorage storage $ = _getVotesStorage(); + uint48 currentTimepoint = clock(); + if (timepoint >= currentTimepoint) { + revert ERC5805FutureLookup(timepoint, currentTimepoint); + } + return $._totalCheckpoints.upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @dev Returns the current total supply of votes. + */ + function _getTotalSupply() internal view virtual returns (uint256) { + VotesStorage storage $ = _getVotesStorage(); + return $._totalCheckpoints.latest(); + } + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) public view virtual returns (address) { + VotesStorage storage $ = _getVotesStorage(); + return $._delegatee[account]; + } + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) public virtual { + address account = _msgSender(); + _delegate(account, delegatee); + } + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig( + address delegatee, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + if (block.timestamp > expiry) { + revert VotesExpiredSignature(expiry); + } + address signer = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))), + v, + r, + s + ); + _useCheckedNonce(signer, nonce); + _delegate(signer, delegatee); + } + + /** + * @dev Delegate all of `account`'s voting units to `delegatee`. + * + * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}. + */ + function _delegate(address account, address delegatee) internal virtual { + VotesStorage storage $ = _getVotesStorage(); + address oldDelegate = delegates(account); + $._delegatee[account] = delegatee; + + emit DelegateChanged(account, oldDelegate, delegatee); + _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account)); + } + + /** + * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to` + * should be zero. Total supply of voting units will be adjusted with mints and burns. + */ + function _transferVotingUnits(address from, address to, uint256 amount) internal virtual { + VotesStorage storage $ = _getVotesStorage(); + if (from == address(0)) { + _push($._totalCheckpoints, _add, SafeCast.toUint208(amount)); + } + if (to == address(0)) { + _push($._totalCheckpoints, _subtract, SafeCast.toUint208(amount)); + } + _moveDelegateVotes(delegates(from), delegates(to), amount); + } + + /** + * @dev Moves delegated votes from one delegate to another. + */ + function _moveDelegateVotes(address from, address to, uint256 amount) private { + VotesStorage storage $ = _getVotesStorage(); + if (from != to && amount > 0) { + if (from != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + $._delegateCheckpoints[from], + _subtract, + SafeCast.toUint208(amount) + ); + emit DelegateVotesChanged(from, oldValue, newValue); + } + if (to != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + $._delegateCheckpoints[to], + _add, + SafeCast.toUint208(amount) + ); + emit DelegateVotesChanged(to, oldValue, newValue); + } + } + } + + /** + * @dev Get number of checkpoints for `account`. + */ + function _numCheckpoints(address account) internal view virtual returns (uint32) { + VotesStorage storage $ = _getVotesStorage(); + return SafeCast.toUint32($._delegateCheckpoints[account].length()); + } + + /** + * @dev Get the `pos`-th checkpoint for `account`. + */ + function _checkpoints( + address account, + uint32 pos + ) internal view virtual returns (Checkpoints.Checkpoint208 memory) { + VotesStorage storage $ = _getVotesStorage(); + return $._delegateCheckpoints[account].at(pos); + } + + function _push( + Checkpoints.Trace208 storage store, + function(uint208, uint208) view returns (uint208) op, + uint208 delta + ) private returns (uint208, uint208) { + return store.push(clock(), op(store.latest(), delta)); + } + + function _add(uint208 a, uint208 b) private pure returns (uint208) { + return a + b; + } + + function _subtract(uint208 a, uint208 b) private pure returns (uint208) { + return a - b; + } + + /** + * @dev Must return the voting units held by an account. + */ + function _getVotingUnits(address) internal view virtual returns (uint256); +} + +// lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Votes.sol) + +/** + * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's, + * and supports token supply up to 2^208^ - 1, while COMP is limited to 2^96^ - 1. + * + * NOTE: This contract does not provide interface compatibility with Compound's COMP token. + * + * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either + * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting + * power can be queried through the public accessors {getVotes} and {getPastVotes}. + * + * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it + * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. + */ +abstract contract ERC20VotesUpgradeable is Initializable, ERC20Upgradeable, VotesUpgradeable { + /** + * @dev Total supply cap has been exceeded, introducing a risk of votes overflowing. + */ + error ERC20ExceededSafeSupply(uint256 increasedSupply, uint256 cap); + + function __ERC20Votes_init() internal onlyInitializing { + } + + function __ERC20Votes_init_unchained() internal onlyInitializing { + } + /** + * @dev Maximum token supply. Defaults to `type(uint208).max` (2^208^ - 1). + * + * This maximum is enforced in {_update}. It limits the total supply of the token, which is otherwise a uint256, + * so that checkpoints can be stored in the Trace208 structure used by {{Votes}}. Increasing this value will not + * remove the underlying limitation, and will cause {_update} to fail because of a math overflow in + * {_transferVotingUnits}. An override could be used to further restrict the total supply (to a lower value) if + * additional logic requires it. When resolving override conflicts on this function, the minimum should be + * returned. + */ + function _maxSupply() internal view virtual returns (uint256) { + return type(uint208).max; + } + + /** + * @dev Move voting power when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _update(address from, address to, uint256 value) internal virtual override { + super._update(from, to, value); + if (from == address(0)) { + uint256 supply = totalSupply(); + uint256 cap = _maxSupply(); + if (supply > cap) { + revert ERC20ExceededSafeSupply(supply, cap); + } + } + _transferVotingUnits(from, to, value); + } + + /** + * @dev Returns the voting units of an `account`. + * + * WARNING: Overriding this function may compromise the internal vote accounting. + * `ERC20Votes` assumes tokens map to voting units 1:1 and this is not easy to change. + */ + function _getVotingUnits(address account) internal view virtual override returns (uint256) { + return balanceOf(account); + } + + /** + * @dev Get number of checkpoints for `account`. + */ + function numCheckpoints(address account) public view virtual returns (uint32) { + return _numCheckpoints(account); + } + + /** + * @dev Get the `pos`-th checkpoint for `account`. + */ + function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoints.Checkpoint208 memory) { + return _checkpoints(account, pos); + } +} + +// lib/bread-token-v2/src/Bread.sol + +// Bread - An ERC20 stablecoin fully collateralized by Gnosis Chain xDAI +// which earns yield via Gnosis Chain sDAI (aka sexyDAI) +// and points this yield to the Breadchain Ecosystem +// implemented by: kassandra.eth + +contract Bread is + ERC20VotesUpgradeable, + OwnableUpgradeable, + IBread +{ + using SafeERC20 for IERC20_1; + + address public yieldClaimer; + error MintZero(); + error BurnZero(); + error ClaimZero(); + error YieldInsufficient(); + error IsCollateral(); + error NativeTransferFailed(); + error OnlyClaimers(); + error MismatchArray(); + error MismatchAmount(); + + IWXDAI public immutable wxDai; + ISXDAI public immutable sexyDai; + + event Minted(address receiver, uint256 amount); + event Burned(address receiver, uint256 amount); + event YieldClaimerSet(address yieldClaimer); + event ClaimedYield(uint256 amount); + + constructor( + address _wxDai, + address _sexyDai + ) { + wxDai = IWXDAI(_wxDai); + sexyDai = ISXDAI(_sexyDai); + } + + function initialize( + string memory name_, + string memory symbol_, + address owner_ + ) external initializer { + __ERC20_init(name_, symbol_); + __Ownable_init(owner_); + } + + function setYieldClaimer(address _yieldClaimer) external onlyOwner { + yieldClaimer = _yieldClaimer; + emit YieldClaimerSet(_yieldClaimer); + } + + function mint(address receiver) external payable { + uint256 val = msg.value; + if (val == 0) revert MintZero(); + + wxDai.deposit{value: val}(); + IERC20_1(address(wxDai)).safeIncreaseAllowance(address(sexyDai), val); + sexyDai.deposit(val, address(this)); + + _mint(receiver, val); + if (this.delegates(receiver) == address(0)) _delegate(receiver, receiver); + } + + function mint(address receiver, uint256 amount) external { + if (amount == 0) revert MintZero(); + + IERC20_1(address(wxDai)).safeTransferFrom(msg.sender, address(this), amount); + + IERC20_1(address(wxDai)).safeIncreaseAllowance(address(sexyDai), amount); + sexyDai.deposit(amount, address(this)); + + _mint(receiver, amount); + if (this.delegates(receiver) == address(0)) _delegate(receiver, receiver); + } + + function burn(uint256 amount, address receiver) external { + if (amount == 0) revert BurnZero(); + _burn(msg.sender, amount); + + sexyDai.withdraw(amount, address(this), address(this)); + wxDai.withdraw(amount); + _nativeTransfer(receiver, amount); + + emit Burned(receiver, amount); + } + + function claimYield(uint256 amount, address receiver) external { + if (msg.sender != owner() && msg.sender != yieldClaimer) revert OnlyClaimers(); + if (amount == 0) revert ClaimZero(); + uint256 yield = _yieldAccrued(); + if (yield < amount) revert YieldInsufficient(); + + _mint(receiver, amount); + if (this.delegates(receiver) == address(0)) _delegate(receiver, receiver); + + emit ClaimedYield(amount); + } + + function rescueToken(address tok, uint256 amount) external onlyOwner { + if (tok == address(sexyDai)) revert IsCollateral(); + IERC20_1(tok).safeTransfer(owner(), amount); + } + + function yieldAccrued() external view returns (uint256) { + return _yieldAccrued(); + } + + function _yieldAccrued() internal view returns (uint256) { + uint256 bal = IERC20_1(address(sexyDai)).balanceOf(address(this)); + uint256 assets = sexyDai.convertToAssets(bal); + uint256 supply = totalSupply(); + return assets > supply ? assets - supply : 0; + } + + function _nativeTransfer(address to, uint256 amount) internal { + bool success; + assembly { + // Transfer the ETH and store if it succeeded or not. + success := call(gas(), to, amount, 0, 0, 0, 0) + } + + if (!success) revert NativeTransferFailed(); + } + + function transfer(address recipient, uint256 amount) public override returns (bool) { + super.transfer(recipient, amount); + if (this.delegates(recipient) == address(0)) _delegate(recipient, recipient); + return true; + } + function transferFrom(address from, address to, uint256 value) public override returns (bool) { + super.transferFrom(from, to, value); + if (this.delegates(to) == address(0)) _delegate(to, to); + return true; + } + +} + +// src/YieldDistributor.sol + +/** + * @title Breadchain Yield Distributor + * @notice Distribute $BREAD yield to eligible member projects based on a voted distribution + * @author Breadchain Collective + * @custom:coauthor postcapitalistcrypto.eth + * @custom:coauthor bagelface.eth + * @custom:coauthor prosalads.eth + * @custom:coauthor kassandra.eth + * @custom:coauthor theblockchainsocialist.eth + * @custom:coauthor github.com/daopunk + * @custom:coauthor github.com/secbajor + */ +contract YieldDistributor is IYieldDistributor, Ownable2StepUpgradeable, VotingMultipliers { + /// @notice The address of the $BREAD token contract + Bread public BREAD; + /// @notice The precision to use for calculations + uint256 public PRECISION; + /// @notice The minimum number of blocks between yield distributions + uint256 public cycleLength; + /// @notice The maximum number of points a voter can allocate to a project + uint256 public maxPoints; + /// @notice The minimum required voting power participants must have to cast a vote + uint256 public minRequiredVotingPower; + /// @notice The block number of the last yield distribution + uint256 public lastClaimedBlockNumber; + /// @notice The total number of votes cast in the current cycle + uint256 public currentVotes; + /// @notice Array of projects eligible for yield distribution + address[] public projects; + /// @notice Array of projects queued for addition to the next cycle + address[] public queuedProjectsForAddition; + /// @notice Array of projects queued for removal from the next cycle + address[] public queuedProjectsForRemoval; + /// @notice The voting power allocated to each project by voters in the current cycle + uint256[] public projectDistributions; + /// @notice The last block number in which a specified account cast a vote + mapping(address => uint256) public accountLastVoted; + /// @notice The voting power allocated to each project by a specific voter in the current cycle + mapping(address => uint256[]) voterDistributions; + /// @notice How much of the yield is divided equally among projects + uint256 public yieldFixedSplitDivisor; + /// @notice The address of the `ButteredBread` token contract + ERC20VotesUpgradeable public BUTTERED_BREAD; + /// @notice The block number before the last yield distribution + uint256 public previousCycleStartingBlock; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize( + address _bread, + address _butteredBread, + uint256 _precision, + uint256 _minRequiredVotingPower, + uint256 _maxPoints, + uint256 _cycleLength, + uint256 _yieldFixedSplitDivisor, + uint256 _lastClaimedBlockNumber, + address[] memory _projects + ) public initializer { + VotingMultipliers.initialize(); + if ( + _bread == address(0) || _butteredBread == address(0) || _precision == 0 || _minRequiredVotingPower == 0 + || _maxPoints == 0 || _cycleLength == 0 || _yieldFixedSplitDivisor == 0 || _lastClaimedBlockNumber == 0 + || _projects.length == 0 + ) { + revert MustBeGreaterThanZero(); + } + + BREAD = Bread(_bread); + BUTTERED_BREAD = ERC20VotesUpgradeable(_butteredBread); + PRECISION = _precision; + minRequiredVotingPower = _minRequiredVotingPower; + maxPoints = _maxPoints; + cycleLength = _cycleLength; + yieldFixedSplitDivisor = _yieldFixedSplitDivisor; + lastClaimedBlockNumber = _lastClaimedBlockNumber; + + projectDistributions = new uint256[](_projects.length); + projects = new address[](_projects.length); + for (uint256 i; i < _projects.length; ++i) { + projects[i] = _projects[i]; + } + } + + /** + * @notice Returns the current distribution of voting power for projects + * @return address[] The current eligible member projects + * @return uint256[] The current distribution of voting power for projects + */ + function getCurrentVotingDistribution() public view returns (address[] memory, uint256[] memory) { + return (projects, projectDistributions); + } + + /** + * @notice Return the current voting power of a user + * @param _account Address of the user to return the voting power for + * @return uint256 The voting power of the user + */ + function getCurrentVotingPower(address _account) public view returns (uint256) { + return this.getVotingPowerForPeriod(BREAD, previousCycleStartingBlock, lastClaimedBlockNumber, _account) + + this.getVotingPowerForPeriod(BUTTERED_BREAD, previousCycleStartingBlock, lastClaimedBlockNumber, _account); + } + + /// @notice Get the current accumulated voting power for a user + /// @dev This is the voting power that has been accumulated since the last yield distribution + /// @param _account Address of the user to get the current accumulated voting power for + /// @return uint256 The current accumulated voting power for the user + function getCurrentAccumulatedVotingPower(address _account) public view returns (uint256) { + return this.getVotingPowerForPeriod(BUTTERED_BREAD, lastClaimedBlockNumber, block.number, _account) + + this.getVotingPowerForPeriod(BREAD, lastClaimedBlockNumber, block.number, _account); + } + + /** + * @notice Return the voting power for a specified user during a specified period of time + * @param _start Start time of the period to return the voting power for + * @param _end End time of the period to return the voting power for + * @param _account Address of user to return the voting power for + * @return uint256 Voting power of the specified user at the specified period of time + */ + function getVotingPowerForPeriod( + ERC20VotesUpgradeable _sourceContract, + uint256 _start, + uint256 _end, + address _account + ) public view returns (uint256) { + if (_start >= _end) revert StartMustBeBeforeEnd(); + if (_end > block.number) revert EndAfterCurrentBlock(); + + /// Initialized as the checkpoint count, but later used to track checkpoint index + uint32 _numCheckpoints = _sourceContract.numCheckpoints(_account); + if (_numCheckpoints == 0) return 0; + + /// No voting power if the first checkpoint is after the end of the interval + Checkpoints.Checkpoint208 memory _currentCheckpoint = _sourceContract.checkpoints(_account, 0); + if (_currentCheckpoint._key > _end) return 0; + + uint256 _totalVotingPower; + + for (uint32 i = _numCheckpoints; i > 0;) { + _currentCheckpoint = _sourceContract.checkpoints(_account, --i); + + if (_currentCheckpoint._key <= _end) { + uint48 _effectiveStart = _currentCheckpoint._key < _start ? uint48(_start) : _currentCheckpoint._key; + _totalVotingPower += _currentCheckpoint._value * (_end - _effectiveStart); + + if (_effectiveStart == _start) break; + _end = _currentCheckpoint._key; + } + } + + return _totalVotingPower; + } + + /** + * @notice Determine if the yield distribution is available + * @dev Resolver function required for Powerpool job registration. For more details, see the Powerpool documentation: + * @dev https://docs.powerpool.finance/powerpool-and-poweragent-network/power-agent/user-guides-and-instructions/i-want-to-automate-my-tasks/job-registration-guide#resolver-job + * @return bool Flag indicating if the yield is able to be distributed + * @return bytes Calldata used by the resolver to distribute the yield + */ + function resolveYieldDistribution() public view returns (bool, bytes memory) { + uint256 _available_yield = BREAD.balanceOf(address(this)) + BREAD.yieldAccrued(); + if ( + /// No votes were cast + /// Already claimed this cycle + currentVotes == 0 || block.number < lastClaimedBlockNumber + cycleLength + || _available_yield / yieldFixedSplitDivisor < projects.length + ) { + /// Yield is insufficient + + return (false, new bytes(0)); + } else { + return (true, abi.encodePacked(this.distributeYield.selector)); + } + } + + /** + * @notice Distribute $BREAD yield to projects based on cast votes + */ + function distributeYield() public { + (bool _resolved,) = resolveYieldDistribution(); + if (!_resolved) revert YieldNotResolved(); + + BREAD.claimYield(BREAD.yieldAccrued(), address(this)); + previousCycleStartingBlock = lastClaimedBlockNumber; + lastClaimedBlockNumber = block.number; + uint256 balance = BREAD.balanceOf(address(this)); + uint256 _fixedYield = balance / yieldFixedSplitDivisor; + uint256 _baseSplit = _fixedYield / projects.length; + uint256 _votedYield = balance - _fixedYield; + + for (uint256 i; i < projects.length; ++i) { + uint256 _votedSplit = ((projectDistributions[i] * _votedYield * PRECISION) / currentVotes) / PRECISION; + BREAD.transfer(projects[i], _votedSplit + _baseSplit); + } + + _updateBreadchainProjects(); + + emit YieldDistributed(balance, currentVotes, projectDistributions); + + delete currentVotes; + projectDistributions = new uint256[](projects.length); + } + + /** + * @notice Cast votes for the distribution of $BREAD yield + * @param _points List of points as integers for each project + */ + function castVote(uint256[] calldata _points) public { + uint256 _currentVotingPower = getCurrentVotingPower(msg.sender); + + if (_currentVotingPower < minRequiredVotingPower) revert BelowMinRequiredVotingPower(); + + _castVote(msg.sender, _points, _currentVotingPower); + } + + /** + * @notice Cast votes for the distribution of $BREAD yield with multipliers + * @param _points List of points as integers for each project + * @param _multiplierIndices List of indices of multipliers to use for each project + */ + function castVoteWithMultipliers(uint256[] calldata _points, uint256[] calldata _multiplierIndices) public { + uint256 _currentVotingPower = getCurrentVotingPower(msg.sender); + uint256 multiplier = calculateTotalMultipliers(msg.sender, _multiplierIndices); + _currentVotingPower = multiplier == 0 ? _currentVotingPower : (_currentVotingPower * multiplier) / PRECISION; + if (_currentVotingPower < minRequiredVotingPower) revert BelowMinRequiredVotingPower(); + _castVote(msg.sender, _points, _currentVotingPower); + } + + /** + * @notice Internal function for casting votes for a specified user + * @param _account Address of user to cast votes for + * @param _points Basis points for calculating the amount of votes cast + * @param _votingPower Amount of voting power being cast + */ + function _castVote(address _account, uint256[] calldata _points, uint256 _votingPower) internal { + if (_points.length != projects.length) revert IncorrectNumberOfProjects(); + + uint256 _totalPoints; + for (uint256 i; i < _points.length; ++i) { + if (_points[i] > maxPoints) revert ExceedsMaxPoints(); + _totalPoints += _points[i]; + } + if (_totalPoints == 0) revert ZeroVotePoints(); + + bool _hasVotedInCycle = accountLastVoted[_account] > lastClaimedBlockNumber; + uint256[] storage _voterDistributions = voterDistributions[_account]; + if (!_hasVotedInCycle) { + delete voterDistributions[_account]; + currentVotes += _votingPower; + } + + for (uint256 i; i < _points.length; ++i) { + if (!_hasVotedInCycle) _voterDistributions.push(0); + else projectDistributions[i] -= _voterDistributions[i]; + + uint256 _currentProjectDistribution = ((_points[i] * _votingPower * PRECISION) / _totalPoints) / PRECISION; + projectDistributions[i] += _currentProjectDistribution; + _voterDistributions[i] = _currentProjectDistribution; + } + + accountLastVoted[_account] = block.number; + + emit BreadHolderVoted(_account, _points, projects); + } + + /** + * @notice Internal function for updating the project list + */ + function _updateBreadchainProjects() internal { + for (uint256 i; i < queuedProjectsForAddition.length; ++i) { + address _project = queuedProjectsForAddition[i]; + + projects.push(_project); + + emit ProjectAdded(_project); + } + + address[] memory _oldProjects = projects; + delete projects; + + for (uint256 i; i < _oldProjects.length; ++i) { + address _project = _oldProjects[i]; + bool _remove; + + for (uint256 j; j < queuedProjectsForRemoval.length; ++j) { + if (_project == queuedProjectsForRemoval[j]) { + _remove = true; + emit ProjectRemoved(_project); + break; + } + } + + if (!_remove) { + projects.push(_project); + } + } + + delete queuedProjectsForAddition; + delete queuedProjectsForRemoval; + } + + /** + * @notice Queue a new project to be added to the project list + * @param _project Project to be added to the project list + */ + function queueProjectAddition(address _project) public onlyOwner { + for (uint256 i; i < projects.length; ++i) { + if (projects[i] == _project) { + revert AlreadyMemberProject(); + } + } + + for (uint256 i; i < queuedProjectsForAddition.length; ++i) { + if (queuedProjectsForAddition[i] == _project) { + revert ProjectAlreadyQueued(); + } + } + + queuedProjectsForAddition.push(_project); + } + + /** + * @notice Queue an existing project to be removed from the project list + * @param _project Project to be removed from the project list + */ + function queueProjectRemoval(address _project) public onlyOwner { + bool _found = false; + for (uint256 i; i < projects.length; ++i) { + if (projects[i] == _project) { + _found = true; + } + } + + if (!_found) revert ProjectNotFound(); + + for (uint256 i; i < queuedProjectsForRemoval.length; ++i) { + if (queuedProjectsForRemoval[i] == _project) { + revert ProjectAlreadyQueued(); + } + } + + queuedProjectsForRemoval.push(_project); + } + + /** + * @notice Set a new minimum required voting power a user must have to vote + * @param _minRequiredVotingPower New minimum required voting power a user must have to vote + */ + function setMinRequiredVotingPower(uint256 _minRequiredVotingPower) public onlyOwner { + if (_minRequiredVotingPower == 0) revert MustBeGreaterThanZero(); + + minRequiredVotingPower = _minRequiredVotingPower; + } + + /** + * @notice Set a new maximum number of points a user can allocate to a project + * @param _maxPoints New maximum number of points a user can allocate to a project + */ + function setMaxPoints(uint256 _maxPoints) public onlyOwner { + if (_maxPoints == 0) revert MustBeGreaterThanZero(); + + maxPoints = _maxPoints; + } + + /** + * @notice Set a new cycle length in blocks + * @param _cycleLength New cycle length in blocks + */ + function setCycleLength(uint256 _cycleLength) public onlyOwner { + if (_cycleLength == 0) revert MustBeGreaterThanZero(); + + cycleLength = _cycleLength; + } + + /** + * @notice Set a new fixed split for the yield distribution + * @param _yieldFixedSplitDivisor New fixed split for the yield distribution + */ + function setYieldFixedSplitDivisor(uint256 _yieldFixedSplitDivisor) public onlyOwner { + if (_yieldFixedSplitDivisor == 0) revert MustBeGreaterThanZero(); + + yieldFixedSplitDivisor = _yieldFixedSplitDivisor; + } + + /** + * @notice Set the ButteredBread token contract + * @param _butteredBread Address of the ButteredBread token contract + */ + function setButteredBread(address _butteredBread) public onlyOwner { + BUTTERED_BREAD = ERC20VotesUpgradeable(_butteredBread); + } +} +