Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 4 internal transactions
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x60806040 | 23064080 | 80 days ago | Contract Creation | 0 ETH | |||
0x61018060 | 23064080 | 80 days ago | Contract Creation | 0 ETH | |||
0x6101a060 | 23064080 | 80 days ago | Contract Creation | 0 ETH | |||
0x60806040 | 23064080 | 80 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
AtomicDeployer
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 100 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {SuccinctStaking} from "../../src/SuccinctStaking.sol"; import {SuccinctVApp} from "../../src/SuccinctVApp.sol"; import {IntermediateSuccinct} from "../../src/tokens/IntermediateSuccinct.sol"; import {ERC1967Proxy} from "../../lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; contract AtomicDeployer { // Staking proxy param address public stakingImpl; // IntermediateSuccinct param address public prove; // Governor params uint48 public votingDelay; uint32 public votingPeriod; uint256 public proposalThreshold; uint256 public quorumFraction; // VApp params address public vappImpl; address public owner; address public auctioneer; address public verifier; uint256 public minDepositAmount; bytes32 public vkey; // Staking params address public dispenser; uint256 public minStakeAmount; uint256 public maxUnstakeRequests; uint256 public unstakePeriod; uint256 public slashCancellationPeriod; bytes32 public genesisStateRoot; address public deployerOwner; constructor() { deployerOwner = msg.sender; } modifier onlyOwner() { require(msg.sender == deployerOwner); _; } function setParams1( address _stakingImpl, address _prove, uint48 _votingDelay, uint32 _votingPeriod, uint256 _proposalThreshold, uint256 _quorumFraction ) external onlyOwner { stakingImpl = _stakingImpl; prove = _prove; votingDelay = _votingDelay; votingPeriod = _votingPeriod; proposalThreshold = _proposalThreshold; quorumFraction = _quorumFraction; } function setParams2( address _vappImpl, address _owner, address _auctioneer, address _verifier, uint256 _minDepositAmount, bytes32 _vkey ) external onlyOwner { vappImpl = _vappImpl; owner = _owner; auctioneer = _auctioneer; verifier = _verifier; minDepositAmount = _minDepositAmount; vkey = _vkey; } function setParams3( address _dispenser, uint256 _minStakeAmount, uint256 _maxUnstakeRequests, uint256 _unstakePeriod, uint256 _slashCancellationPeriod, bytes32 _genesisStateRoot ) external onlyOwner { dispenser = _dispenser; minStakeAmount = _minStakeAmount; maxUnstakeRequests = _maxUnstakeRequests; unstakePeriod = _unstakePeriod; slashCancellationPeriod = _slashCancellationPeriod; genesisStateRoot = _genesisStateRoot; } function deploy(bytes32 salt, bytes calldata iproveCode, bytes calldata governorCode) external onlyOwner returns (address, address, address, address) { address STAKING; { STAKING = address(new ERC1967Proxy{salt: salt}(stakingImpl, "")); } address I_PROVE; { // I_PROVE = address(new IntermediateSuccinct{salt: salt}(prove, STAKING)); bytes memory args = abi.encode(prove, STAKING); bytes memory initCode = abi.encodePacked(iproveCode, args); assembly { I_PROVE := create2(0, add(initCode, 0x20), mload(initCode), salt) if iszero(extcodesize(I_PROVE)) { revert(0, 0) } } } address GOVERNOR; { bytes memory args = abi.encode(I_PROVE, votingDelay, votingPeriod, proposalThreshold, quorumFraction); bytes memory initCode = abi.encodePacked(governorCode, args); assembly { GOVERNOR := create2(0, add(initCode, 0x20), mload(initCode), salt) if iszero(extcodesize(GOVERNOR)) { revert(0, 0) } } } address VAPP; { // Encode the initialize function call data bytes memory vappInitData; { vappInitData = abi.encodeCall( SuccinctVApp.initialize, ( owner, prove, I_PROVE, auctioneer, STAKING, verifier, minDepositAmount, vkey, genesisStateRoot ) ); } VAPP = address(new ERC1967Proxy{salt: salt}(vappImpl, vappInitData)); } SuccinctStaking(STAKING).initialize( owner, GOVERNOR, VAPP, prove, I_PROVE, dispenser, minStakeAmount, maxUnstakeRequests, unstakePeriod, slashCancellationPeriod ); return (STAKING, VAPP, I_PROVE, GOVERNOR); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {ProverRegistry} from "./libraries/ProverRegistry.sol"; import {StakedSuccinct} from "./tokens/StakedSuccinct.sol"; import {ISuccinctStaking} from "./interfaces/ISuccinctStaking.sol"; import {IIntermediateSuccinct} from "./interfaces/IIntermediateSuccinct.sol"; import {IProver} from "./interfaces/IProver.sol"; import {SuccinctGovernor} from "./SuccinctGovernor.sol"; import {Initializable} from "../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol"; import {OwnableUpgradeable} from "../lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol"; import {IERC20} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import {IERC20Permit} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {IERC4626} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol"; import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {Math} from "../lib/openzeppelin-contracts/contracts/utils/math/Math.sol"; import {UUPSUpgradeable} from "../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol"; /// @title SuccinctStaking /// @author Succinct Labs /// @notice Manages staking, unstaking, dispensing, and slashing for the Succinct Prover Network. contract SuccinctStaking is Initializable, OwnableUpgradeable, ProverRegistry, StakedSuccinct, UUPSUpgradeable, ISuccinctStaking { using SafeERC20 for IERC20; /// @dev Fixed‑point base used for slash‑factor math. /// /// This allows for the multiplication of two 1e27‑scaled values without /// overflowing 256 bits while keeping sub‑wei precision. uint256 internal constant SCALAR = 1e27; /// @inheritdoc ISuccinctStaking address public override dispenser; /// @inheritdoc ISuccinctStaking uint256 public override minStakeAmount; /// @inheritdoc ISuccinctStaking uint256 public override maxUnstakeRequests; /// @inheritdoc ISuccinctStaking uint256 public override unstakePeriod; /// @inheritdoc ISuccinctStaking uint256 public override slashCancellationPeriod; /// @inheritdoc ISuccinctStaking uint256 public override dispenseRate; /// @inheritdoc ISuccinctStaking uint256 public override dispenseRateTimestamp; /// @inheritdoc ISuccinctStaking uint256 public override dispenseEarned; /// @inheritdoc ISuccinctStaking uint256 public override dispenseDistributed; /// @dev A mapping from staker to the prover they are staked with. mapping(address => address) internal stakerToProver; /// @dev A mapping from staker to their unstake claims. mapping(address => UnstakeClaim[]) internal unstakeClaims; /// @dev A mapping from prover to their slash claims. mapping(address => SlashClaim[]) internal slashClaims; /// @dev A mapping from prover to their unresolved slash claim count. mapping(address => uint256) internal slashClaimCount; /// @dev A mapping from prover to their unstaking escrow pool. mapping(address => EscrowPool) internal escrowPools; /*////////////////////////////////////////////////////////////// MODIFIER //////////////////////////////////////////////////////////////*/ modifier onlyDispenser() { if (msg.sender != dispenser) revert NotDispenser(); _; } /*////////////////////////////////////////////////////////////// INITIALIZER //////////////////////////////////////////////////////////////*/ /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// @dev We don't do this in the constructor because we must deploy this contract /// first. function initialize( address _owner, address _governor, address _vApp, address _prove, address _intermediateProve, address _dispenser, uint256 _minStakeAmount, uint256 _maxUnstakeRequests, uint256 _unstakePeriod, uint256 _slashCancellationPeriod ) external initializer { // Ensure that parameters critical for functionality are non-zero. _requireNonZeroAddress(_owner); _requireNonZeroAddress(_governor); _requireNonZeroAddress(_vApp); _requireNonZeroAddress(_prove); _requireNonZeroAddress(_intermediateProve); _requireNonZeroAddress(_dispenser); _requireNonZeroNumber(_maxUnstakeRequests); _requireNonZeroNumber(_unstakePeriod); _requireNonZeroNumber(_slashCancellationPeriod); // Setup the initial state. __UUPSUpgradeable_init(); __Ownable_init(_owner); __StakedSuccinct_init(); __ProverRegistry_init(_governor, _vApp, _prove, _intermediateProve); dispenser = _dispenser; minStakeAmount = _minStakeAmount; maxUnstakeRequests = _maxUnstakeRequests; unstakePeriod = _unstakePeriod; slashCancellationPeriod = _slashCancellationPeriod; // Approve the $iPROVE contract to transfer $PROVE from this contract during stake(). IERC20(prove).approve(iProve, type(uint256).max); } /*////////////////////////////////////////////////////////////// VIEW //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISuccinctStaking function stakedTo(address _staker) external view override returns (address) { return stakerToProver[_staker]; } /// @inheritdoc ISuccinctStaking function staked(address _staker) external view override returns (uint256) { // Get the prover that the staker is staked with. address prover = stakerToProver[_staker]; if (prover == address(0)) return 0; // Get the amount of $PROVE the staker would get if the staker's full $stPROVE balance was // unstaked. return previewUnstake(prover, balanceOf(_staker)); } /// @inheritdoc ISuccinctStaking function proverStaked(address _prover) public view override returns (uint256) { // Get the amount of $iPROVE in the prover. uint256 iPROVE = IERC20(iProve).balanceOf(_prover); // Get the amount of $PROVE that would be received if the $iPROVE was redeemed. return IERC4626(iProve).previewRedeem(iPROVE); } /// @inheritdoc ISuccinctStaking function unstakeRequests(address _staker) external view override returns (UnstakeClaim[] memory) { return unstakeClaims[_staker]; } /// @inheritdoc ISuccinctStaking function slashRequests(address _prover) external view override returns (SlashClaim[] memory) { return slashClaims[_prover]; } /// @inheritdoc ISuccinctStaking function escrowPool(address _prover) external view override returns (EscrowPool memory) { return escrowPools[_prover]; } /// @inheritdoc ISuccinctStaking function unstakePending(address _staker) external view override returns (uint256 PROVE) { // Get the prover that the staker is staked with. address prover = stakerToProver[_staker]; if (prover == address(0)) return 0; // Calculate the pending $PROVE by iterating through claims and applying slash factor. UnstakeClaim[] memory claims = unstakeClaims[_staker]; EscrowPool memory pool = escrowPools[prover]; // If everything has been slashed to zero no claim can redeem anything. uint256 currentFactor = pool.slashFactor; if (currentFactor == 0) return 0; for (uint256 i = 0; i < claims.length; i++) { // Apply cumulative slash factor to the escrowed $iPROVE. uint256 iPROVEScaled = Math.mulDiv(claims[i].iPROVEEscrow, currentFactor, claims[i].slashFactor); // Convert $iPROVE to $PROVE. PROVE += IERC4626(iProve).previewRedeem(iPROVEScaled); } } /// @inheritdoc ISuccinctStaking function previewUnstake(address _prover, uint256 _stPROVE) public view override returns (uint256) { // Get the amount of $iPROVE this staker has for this prover. uint256 iPROVE = IERC4626(_prover).previewRedeem(_stPROVE); // Get the amount of $PROVE that would be received if the $iPROVE was redeemed. return IERC4626(iProve).previewRedeem(iPROVE); } /// @inheritdoc ISuccinctStaking function maxDispense() public view override returns (uint256) { // The total earned is the historical accrual plus the current period earnings. uint256 totalEarned = dispenseEarned + (block.timestamp - dispenseRateTimestamp) * dispenseRate; // The maximum amount that can currently be dispensed is the total amount earned minus the // amount already dispensed. return totalEarned - dispenseDistributed; } /*////////////////////////////////////////////////////////////// CORE //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISuccinctStaking function stake(address _prover, uint256 _PROVE) external override onlyForProver(_prover) returns (uint256) { // Transfer $PROVE from the staker to this contract. IERC20(prove).safeTransferFrom(msg.sender, address(this), _PROVE); return _stake(msg.sender, _prover, _PROVE); } /// @inheritdoc ISuccinctStaking function permitAndStake( address _prover, address _from, uint256 _PROVE, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external override onlyForProver(_prover) returns (uint256) { // If the $PROVE allowance is not equal to the amount being staked, permit the prover to // spend the $PROVE from the staker. if (IERC20(prove).allowance(_from, _prover) != _PROVE) { IERC20Permit(prove).permit(_from, _prover, _PROVE, _deadline, _v, _r, _s); } // Transfer $PROVE from the staker to this contract, by utilizing the prover as the // spender. IProver(_prover).transferProveToStaking(_from, _PROVE); return _stake(_from, _prover, _PROVE); } /// @inheritdoc ISuccinctStaking function requestUnstake(uint256 _stPROVE) external override stakingOperation { // Ensure unstaking a non-zero amount. _requireNonZeroNumber(_stPROVE); // Get the prover that the staker is staked with. address prover = stakerToProver[msg.sender]; if (prover == address(0)) revert NotStaked(); // Check that this staker has not already requested too many unstake requests. if (unstakeClaims[msg.sender].length >= maxUnstakeRequests) revert TooManyUnstakeRequests(); // Check that this prover is not in the process of being slashed. _requireProverWithoutSlashRequests(prover); // Get the amount of $stPROVE this staker currently has. uint256 stPROVEBalance = balanceOf(msg.sender); // Check that this staker has enough $stPROVE to unstake this amount. if (stPROVEBalance < _stPROVE) revert InsufficientStakeBalance(); // Escrow the $iPROVE. uint256 iPROVEEscrow = _escrowUnstakeRequest(msg.sender, prover, _stPROVE); // Get the prover's escrow pool. EscrowPool storage pool = escrowPools[prover]; // If the escrow pool hasn't been initialized yet (or a prover was fully slashed), // set the slash factor to the starting value. if (pool.slashFactor == 0) pool.slashFactor = SCALAR; // Update the prover's escrow pool to account for the new escrowed $iPROVE. pool.iPROVEEscrow += iPROVEEscrow; // Record the unstake request. unstakeClaims[msg.sender].push( UnstakeClaim({ iPROVEEscrow: iPROVEEscrow, slashFactor: pool.slashFactor, timestamp: block.timestamp }) ); emit UnstakeRequest(msg.sender, prover, _stPROVE, iPROVEEscrow); } /// @inheritdoc ISuccinctStaking function finishUnstake(address _staker) external override returns (uint256 PROVE) { // Get the prover that the staker is staked with. address prover = stakerToProver[_staker]; if (prover == address(0)) revert NotStaked(); // Get the unstake claims for this staker. UnstakeClaim[] storage claims = unstakeClaims[_staker]; if (claims.length == 0) revert NoUnstakeRequests(); // Check that this prover is not in the process of being slashed. _requireProverWithoutSlashRequests(prover); // Process the available unstake claims. PROVE += _finishUnstake(_staker, prover, claims); // Reset the slash factor if all $iPROVE has been removed. EscrowPool storage pool = escrowPools[prover]; if (pool.iPROVEEscrow == 0 && pool.slashFactor != SCALAR) { pool.slashFactor = SCALAR; } // If the staker has no remaining balance and no pending unstakes, remove the staker's // delegate. This allows them to choose a different prover if they stake again. if (balanceOf(_staker) == 0 && claims.length == 0) { // Remove the staker's prover delegation. stakerToProver[_staker] = address(0); emit ProverUnbound(_staker, prover); } } /*////////////////////////////////////////////////////////////// AUTHORIZED //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISuccinctStaking function requestSlash(address _prover, uint256 _iPROVE) external override onlyVApp onlyForProver(_prover) returns (uint256 index) { // Ensure slashing a non-zero amount. _requireNonZeroNumber(_iPROVE); // Create the slash claim. index = slashClaims[_prover].length; slashClaims[_prover].push( SlashClaim({iPROVE: _iPROVE, timestamp: block.timestamp, resolved: false}) ); // Increment the unresolved claim counter. unchecked { ++slashClaimCount[_prover]; } emit SlashRequest(_prover, _iPROVE, index); } /// @inheritdoc ISuccinctStaking function cancelSlash(address _prover, uint256 _index) external override onlyForProver(_prover) { // Get the slash claim. SlashClaim storage claim = slashClaims[_prover][_index]; // Ensure the claim hasn't already been resolved. if (claim.resolved) revert SlashRequestAlreadyResolved(); // Calculate the deadline for cancellation. Must be after the slash cancellation period // and governance latency has passed. This ensures that governance has had adequate time // to execute a proposal to call `finishSlash()`. uint256 votingDelay = SuccinctGovernor(payable(governor)).votingDelay(); uint256 votingPeriod = SuccinctGovernor(payable(governor)).votingPeriod(); uint256 cancelDeadline = claim.timestamp + slashCancellationPeriod + votingDelay + votingPeriod; // Check if the deadline has passed. if (block.timestamp < cancelDeadline) revert SlashRequestNotReadyToCancel(); // Mark the claim as resolved. claim.resolved = true; // Decrement the unresolved claim counter. unchecked { --slashClaimCount[_prover]; } emit SlashCancel(_prover, claim.iPROVE, _index); } /// @inheritdoc ISuccinctStaking function finishSlash(address _prover, uint256 _index) external override onlyOwner onlyForProver(_prover) returns (uint256 iPROVEBurned) { // Get the slash claim. SlashClaim storage claim = slashClaims[_prover][_index]; // Ensure the claim hasn't already been resolved. if (claim.resolved) revert SlashRequestAlreadyResolved(); // Determine how much can actually be slashed (cannot exceed the prover's current balance). uint256 iPROVEBalance = IERC20(iProve).balanceOf(_prover); // Get the prover's escrow pool to include escrowed funds in total. EscrowPool storage pool = escrowPools[_prover]; uint256 iPROVETotal = iPROVEBalance + pool.iPROVEEscrow; uint256 iPROVEToSlash = claim.iPROVE > iPROVETotal ? iPROVETotal : claim.iPROVE; // Mark the claim as resolved. claim.resolved = true; // Decrement the unresolved claim counter. unchecked { --slashClaimCount[_prover]; } uint256 PROVEBurned = 0; iPROVEBurned = 0; if (iPROVEToSlash > 0) { // Pro‑rata split between vault and escrow. uint256 burnFromEscrow = Math.mulDiv(iPROVEToSlash, pool.iPROVEEscrow, iPROVETotal); uint256 burnFromVault = iPROVEToSlash - burnFromEscrow; // Burn in escrow. if (burnFromEscrow != 0) { pool.iPROVEEscrow -= burnFromEscrow; PROVEBurned += IIntermediateSuccinct(iProve).burn(address(this), burnFromEscrow); iPROVEBurned += burnFromEscrow; } // Burn in vault. if (burnFromVault != 0) { PROVEBurned += IIntermediateSuccinct(iProve).burn(_prover, burnFromVault); iPROVEBurned += burnFromVault; } // Update the prover's slash factor. uint256 iPROVERemaining = iPROVETotal - iPROVEToSlash; if (iPROVERemaining == 0) { // If there is nothing left to slash, set the slash factor to 0. pool.slashFactor = 0; } else { // If there is something left to slash, update the slash factor to the new ratio. uint256 ratio = Math.mulDiv(iPROVERemaining, SCALAR, iPROVETotal); if (pool.slashFactor == 0) pool.slashFactor = SCALAR; pool.slashFactor = Math.mulDiv(pool.slashFactor, ratio, SCALAR); } } emit Slash(_prover, PROVEBurned, iPROVEBurned, _index); // If the slashing caused the price-per-share to drop below the minimum, deactivate the // prover. _deactivateProverIfPriceBelowMin(_prover); } /// @inheritdoc ISuccinctStaking function dispense(uint256 _PROVE) external override onlyDispenser { // Get the maximum amount of $PROVE that can be dispensed. uint256 available = maxDispense(); // If caller passed in type(uint256).max, attempt to dispense the full available amount. uint256 amount = _PROVE == type(uint256).max ? available : _PROVE; // Ensure dispensing a non-zero amount. _requireNonZeroNumber(amount); // If caller passed a specific number, make sure it doesn't exceed available. if (amount > available) revert AmountExceedsAvailableDispense(); // Update the total dispensed amount. dispenseDistributed += amount; // Transfer the amount to the iPROVE vault. This distributes the $PROVE to all stakers. IERC20(prove).safeTransfer(iProve, amount); emit Dispense(amount); } /// @inheritdoc ISuccinctStaking function setDispenser(address _dispenser) external override onlyOwner { _setDispenser(_dispenser); } /// @inheritdoc ISuccinctStaking function updateDispenseRate(uint256 _rate) external override onlyOwner { _updateDispenseRate(_rate); } /*////////////////////////////////////////////////////////////// INTERNAL //////////////////////////////////////////////////////////////*/ /// @dev Deposit a staker's $PROVE to mint $iPROVE, then deposit $iPROVE to mint $PROVER-N, and /// then directly mint $stPROVE to the staker, which acts as the receipt token for staking. function _stake(address _staker, address _prover, uint256 _PROVE) internal stakingOperation returns (uint256 stPROVE) { // Ensure staking a non-zero amount. _requireNonZeroNumber(_PROVE); // Ensure the staking amount is greater than the minimum stake amount. if (_PROVE < minStakeAmount) revert StakeBelowMinimum(); // Check that this prover is active. if (deactivatedProvers[_prover]) revert ProverNotActive(); // Check that this prover is not in the process of being slashed. _requireProverWithoutSlashRequests(_prover); // Ensure the staker is not already staked with a different prover. address existingProver = stakerToProver[_staker]; if (existingProver != address(0) && existingProver != _prover) { revert AlreadyStakedWithDifferentProver(existingProver); } // Set the prover as the staker's delegate. if (existingProver == address(0)) { stakerToProver[_staker] = _prover; emit ProverBound(_staker, _prover); } // Deposit $PROVE to mint $iPROVE, sending it to this contract. uint256 iPROVE = IERC4626(iProve).deposit(_PROVE, address(this)); // Ensure this contract received non-zero $iPROVE. if (iPROVE == 0) revert ZeroReceiptAmount(); // Deposit $iPROVE to mint $PROVER-N, sending it to this contract. // Note: The $stPROVE variable is used because it is 1:1 with the received $PROVER-N. stPROVE = IERC4626(_prover).deposit(iPROVE, address(this)); // Ensure this contract received non-zero $PROVER-N. if (stPROVE == 0) revert ZeroReceiptAmount(); // Mint $stPROVE to the staker as a receipt token representing their ownership of $PROVER-N. _mint(_staker, stPROVE); emit Stake(_staker, _prover, _PROVE, iPROVE, stPROVE); } /// @dev Burn a staker's $stPROVE and withdraw $PROVER-N to receive $iPROVE. function _escrowUnstakeRequest(address _staker, address _prover, uint256 _stPROVE) internal returns (uint256 iPROVE) { // Burn the $stPROVE from the staker. _burn(_staker, _stPROVE); // Withdraw $PROVER-N from this contract to receive $iPROVE. // Note: This can return 0 if the prover has been fully slashed. iPROVE = IERC4626(_prover).redeem(_stPROVE, address(this), address(this)); } /// @dev Withdraw the escrowed $iPROVE to receive $PROVE, which gets sent to the staker. function _finishUnstakeRequest(address _staker, address _prover, UnstakeClaim memory _claim) internal returns (uint256 PROVE) { // Get the prover's escrow pool. EscrowPool storage pool = escrowPools[_prover]; // Apply cumulative slash factor to the escrowed $iPROVE. uint256 iPROVEScaled = Math.mulDiv(_claim.iPROVEEscrow, pool.slashFactor, _claim.slashFactor); // Clamp to the pool’s remaining balance (protects against rounding). if (iPROVEScaled > pool.iPROVEEscrow) { iPROVEScaled = pool.iPROVEEscrow; } // If there is $iPROVE left to redeem, update the escrow pool and redeem. if (iPROVEScaled != 0) { unchecked { pool.iPROVEEscrow -= iPROVEScaled; } // Withdraw $iPROVE from this contract to have the staker receive $PROVE. PROVE = IERC4626(iProve).redeem(iPROVEScaled, _staker, address(this)); } emit Unstake(_staker, _prover, PROVE, iPROVEScaled); } /// @dev Iterate over the unstake claims, processing each one that has passed the unstake /// period. function _finishUnstake(address _staker, address _prover, UnstakeClaim[] storage _claims) internal returns (uint256 PROVE) { uint256 i = 0; while (i < _claims.length) { if (block.timestamp >= _claims[i].timestamp + unstakePeriod) { // Store claim before modifying the array. UnstakeClaim memory claim = _claims[i]; // Swap with the last element and pop. _claims[i] = _claims[_claims.length - 1]; _claims.pop(); // Process the unstake. PROVE += _finishUnstakeRequest(_staker, _prover, claim); } else { i++; } } } /// @dev Set the new dispenser. function _setDispenser(address _dispenser) internal { emit DispenserUpdate(dispenser, _dispenser); dispenser = _dispenser; } /// @dev Set the new dispense rate. function _updateDispenseRate(uint256 _dispenseRate) internal { // Accrue all earnings up to this point at the old rate. dispenseEarned += (block.timestamp - dispenseRateTimestamp) * dispenseRate; // Update the timestamp to mark this new rate taking effect. All time before this timestamp // uses the old rate (already accrued above), and all time after uses the new rate. dispenseRateTimestamp = block.timestamp; emit DispenseRateUpdate(dispenseRate, _dispenseRate); dispenseRate = _dispenseRate; } /// @dev Thrown if a zero address is passed. function _requireNonZeroAddress(address _address) internal pure { if (_address == address(0)) revert ZeroAddress(); } /// @dev Thrown if a zero number is passed. function _requireNonZeroNumber(uint256 _number) internal pure { if (_number == 0) revert ZeroAmount(); } /// @dev Validates that a prover has no pending slash requests. function _requireProverWithoutSlashRequests(address _prover) private view { if (slashClaimCount[_prover] > 0) revert ProverHasSlashRequest(); } /// @dev Authorizes an ERC1967 proxy upgrade to a new implementation contract. function _authorizeUpgrade(address _newImplementation) internal override onlyOwner {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {Receipts} from "./libraries/Receipts.sol"; import { StepPublicValues, TransactionStatus, Receipt, Transaction, TransactionVariant, DepositAction, WithdrawAction, CreateProverAction } from "./libraries/PublicValues.sol"; import {IProver} from "./interfaces/IProver.sol"; import {ISuccinctVApp} from "./interfaces/ISuccinctVApp.sol"; import {ISuccinctStaking} from "./interfaces/ISuccinctStaking.sol"; import {ISP1Verifier} from "../lib/sp1-contracts/contracts/src/ISP1Verifier.sol"; import {Initializable} from "../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol"; import {OwnableUpgradeable} from "../lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol"; import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {UUPSUpgradeable} from "../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol"; import {IERC20Permit} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {IERC20} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import {IERC4626} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol"; import {PausableUpgradeable} from "../lib/openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol"; /// @title SuccinctVApp /// @author Succinct Labs /// @notice Settlement layer for the Succinct Prover Network. /// @dev Processes actions resulting from state transitions. contract SuccinctVApp is Initializable, OwnableUpgradeable, PausableUpgradeable, UUPSUpgradeable, ISuccinctVApp { using SafeERC20 for IERC20; /// @inheritdoc ISuccinctVApp bytes32 public override vkey; /// @inheritdoc ISuccinctVApp address public override prove; /// @inheritdoc ISuccinctVApp address public override iProve; /// @inheritdoc ISuccinctVApp address public override auctioneer; /// @inheritdoc ISuccinctVApp address public override staking; /// @inheritdoc ISuccinctVApp address public override verifier; /// @inheritdoc ISuccinctVApp uint64 public override blockNumber; /// @inheritdoc ISuccinctVApp uint256 public override minDepositAmount; /// @inheritdoc ISuccinctVApp uint64 public override currentOnchainTxId; /// @inheritdoc ISuccinctVApp uint64 public override finalizedOnchainTxId; /// @inheritdoc ISuccinctVApp mapping(uint64 => bytes32) public override roots; /// @inheritdoc ISuccinctVApp mapping(uint64 => uint64) public override timestamps; /// @inheritdoc ISuccinctVApp mapping(uint64 => Transaction) public override transactions; /*////////////////////////////////////////////////////////////// MODIFIER //////////////////////////////////////////////////////////////*/ /// @dev Modifier to ensure that the caller is the auctioneer. modifier onlyAuctioneer() { if (msg.sender != auctioneer) revert NotAuctioneer(); _; } /// @dev Modifier to ensure that the caller is the staking contract. modifier onlyStaking() { if (msg.sender != staking) revert NotStaking(); _; } /*////////////////////////////////////////////////////////////// INITIALIZER //////////////////////////////////////////////////////////////*/ /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// @custom:oz-upgrades-unsafe-allow-initializers function initialize( address _owner, address _prove, address _iProve, address _auctioneer, address _staking, address _verifier, uint256 _minDepositAmount, bytes32 _vkey, bytes32 _genesisStateRoot ) external initializer { // Ensure that parameters critical for functionality are non-zero. if ( _owner == address(0) || _prove == address(0) || _iProve == address(0) || _auctioneer == address(0) || _staking == address(0) || _verifier == address(0) ) { revert ZeroAddress(); } if (_vkey == bytes32(0) || _genesisStateRoot == bytes32(0)) { revert ZeroHash(); } // Set the state variables. __UUPSUpgradeable_init(); __Ownable_init(_owner); vkey = _vkey; prove = _prove; iProve = _iProve; _updateAuctioneer(_auctioneer); _updateStaking(_staking); _updateVerifier(_verifier); _updateMinDepositAmount(_minDepositAmount); // Set the genesis state root. roots[0] = _genesisStateRoot; // Approve the $iPROVE contract to transfer $PROVE from this contract during prover withdrawal. IERC20(prove).approve(_iProve, type(uint256).max); // Emit the events. emit Fork(0, bytes32(0), _vkey); emit Block(0, bytes32(0), _genesisStateRoot); } /*////////////////////////////////////////////////////////////// VIEW //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISuccinctVApp function root() external view override returns (bytes32) { return roots[blockNumber]; } /// @inheritdoc ISuccinctVApp function timestamp() external view override returns (uint64) { return timestamps[blockNumber]; } /*////////////////////////////////////////////////////////////// CORE //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISuccinctVApp function deposit(uint256 _amount) external override whenNotPaused returns (uint64 receipt) { return _deposit(msg.sender, _amount); } /// @inheritdoc ISuccinctVApp function permitAndDeposit( address _from, uint256 _amount, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external override whenNotPaused returns (uint64 receipt) { // If the $PROVE allowance is not equal to the amount being deposited, permit this contract // to spend the $PROVE from the depositor. if (IERC20(prove).allowance(_from, address(this)) != _amount) { IERC20Permit(prove).permit(_from, address(this), _amount, _deadline, _v, _r, _s); } return _deposit(_from, _amount); } /// @inheritdoc ISuccinctVApp function createProver(address _prover, address _owner, uint256 _stakerFeeBips) external onlyStaking whenNotPaused returns (uint64 receipt) { // Validate. if (_owner == address(0)) revert ZeroAddress(); if (_owner != IProver(_prover).owner()) { revert ProverNotOwned(); } // Create the receipt. bytes memory data = abi.encode( CreateProverAction({prover: _prover, owner: _owner, stakerFeeBips: _stakerFeeBips}) ); receipt = _createTransaction(TransactionVariant.CreateProver, data); } /// @inheritdoc ISuccinctVApp function step(bytes calldata _publicValues, bytes calldata _proofBytes) external onlyAuctioneer whenNotPaused returns (uint64, bytes32, bytes32) { // Verify the proof. ISP1Verifier(verifier).verifyProof(vkey, _publicValues, _proofBytes); StepPublicValues memory publicValues = abi.decode(_publicValues, (StepPublicValues)); if (publicValues.newRoot == bytes32(0)) revert InvalidRoot(); // Verify the old root. if (roots[blockNumber] != publicValues.oldRoot) { revert InvalidOldRoot(); } // Assert that the timestamp is not in the future and is increasing. if (publicValues.timestamp > block.timestamp) revert InvalidTimestamp(); if (timestamps[blockNumber] > publicValues.timestamp) { revert TimestampInPast(); } // Ensure the timestamp is not too far in the past (older than 1 hour). if (block.timestamp - publicValues.timestamp > 1 hours) { revert TimestampTooOld(); } // Update the state root. uint64 newBlock = ++blockNumber; roots[newBlock] = publicValues.newRoot; timestamps[newBlock] = publicValues.timestamp; // Handle the receipts. _handleReceipts(publicValues); // Emit the event. emit Block(newBlock, publicValues.oldRoot, publicValues.newRoot); return (newBlock, publicValues.oldRoot, publicValues.newRoot); } /*////////////////////////////////////////////////////////////// AUTHORIZED //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISuccinctVApp function fork(bytes32 _vkey, bytes32 _root) external override onlyOwner returns (uint64, bytes32, bytes32) { // Check that the new vkey and root are not zero. if (_vkey == bytes32(0) || _root == bytes32(0)) revert ZeroHash(); // Save the old vkey for event. bytes32 oldVkey = vkey; // Update the vkey. vkey = _vkey; // Get the old root. bytes32 oldRoot = roots[blockNumber]; // Update the root, timestamp, and produce a new block. uint64 newBlock = ++blockNumber; roots[newBlock] = _root; timestamps[newBlock] = uint64(block.timestamp); // Emit the events. emit Fork(newBlock, oldVkey, _vkey); emit Block(newBlock, oldRoot, _root); return (newBlock, oldRoot, _root); } /// @inheritdoc ISuccinctVApp function updateAuctioneer(address _auctioneer) external override onlyOwner { _updateAuctioneer(_auctioneer); } /// @inheritdoc ISuccinctVApp function updateStaking(address _staking) external override onlyOwner { _updateStaking(_staking); } /// @inheritdoc ISuccinctVApp function updateVerifier(address _verifier) external override onlyOwner { _updateVerifier(_verifier); } /// @inheritdoc ISuccinctVApp function updateMinDepositAmount(uint256 _amount) external override onlyOwner { _updateMinDepositAmount(_amount); } /// @inheritdoc ISuccinctVApp function pause() external override onlyOwner whenNotPaused { _pause(); } /// @inheritdoc ISuccinctVApp function unpause() external override onlyOwner whenPaused { _unpause(); } /*////////////////////////////////////////////////////////////// INTERNAL //////////////////////////////////////////////////////////////*/ /// @dev Credits a deposit receipt and transfers $PROVE from the sender to the VApp. function _deposit(address _from, uint256 _amount) internal returns (uint64 receipt) { // Validate. if (_amount < minDepositAmount) { revert TransferBelowMinimum(); } // Create the receipt. bytes memory data = abi.encode(DepositAction({account: _from, amount: _amount})); receipt = _createTransaction(TransactionVariant.Deposit, data); // Transfer $PROVE from the sender to the VApp. IERC20(prove).safeTransferFrom(_from, address(this), _amount); emit Deposit(_from, _amount); } /// @dev Creates a receipt for an action. function _createTransaction(TransactionVariant _transactionVariant, bytes memory _data) internal returns (uint64 onchainTx) { onchainTx = ++currentOnchainTxId; transactions[onchainTx] = Transaction({ variant: _transactionVariant, status: TransactionStatus.Pending, onchainTxId: onchainTx, action: _data }); emit TransactionPending(onchainTx, _transactionVariant, _data); } /// @dev Handles committed actions, reverts if the actions are invalid function _handleReceipts(StepPublicValues memory _publicValues) internal { // Execute the receipts. for (uint64 i = 0; i < _publicValues.receipts.length; i++) { if (_publicValues.receipts[i].onchainTxId != type(uint64).max) { _handleOnchainReceipt(_publicValues.receipts[i]); } else { _handleOffchainReceipt(_publicValues.receipts[i]); } } } /// @dev Handles a receipt sourced from an onchain transaction. function _handleOnchainReceipt(Receipt memory _receipt) internal { // Increment the finalized onchain transaction ID. uint64 onchainTxId = ++finalizedOnchainTxId; // Ensure that the receipt is the next one to be processed. if (onchainTxId != _receipt.onchainTxId) { revert ReceiptOutOfOrder(onchainTxId, _receipt.onchainTxId); } // Ensure that the receipt has of the expected statuses. if ( _receipt.status == TransactionStatus.None || _receipt.status == TransactionStatus.Pending ) { revert ReceiptStatusInvalid(_receipt.status); } // Ensure that the receipt is consistent with the transaction. Receipts.assertEq(transactions[onchainTxId], _receipt); // Update the transaction status. transactions[onchainTxId].status = _receipt.status; // If the transaction failed, emit the revert event and skip the rest of the loop. if (_receipt.status == TransactionStatus.Reverted) { emit TransactionReverted(onchainTxId, _receipt.variant, _receipt.action); return; } // If the transaction completed, run a handler for the transaction. if (_receipt.variant == TransactionVariant.Deposit) { // No-op. } else if (_receipt.variant == TransactionVariant.CreateProver) { // No-op. } else { revert TransactionVariantInvalid(); } // Emit the completed event. emit TransactionCompleted(onchainTxId, _receipt.variant, _receipt.action); } /// @dev Handles a receipt sourced from an offchain transaction. function _handleOffchainReceipt(Receipt memory _receipt) internal { // Ensure that the receipt has of the expected statuses. if ( _receipt.status == TransactionStatus.None || _receipt.status == TransactionStatus.Pending ) { revert ReceiptStatusInvalid(_receipt.status); } // If the transaction reverted, don't do anything. if (_receipt.status == TransactionStatus.Reverted) { emit TransactionReverted(_receipt.onchainTxId, _receipt.variant, _receipt.action); return; } if (_receipt.variant == TransactionVariant.Withdraw) { WithdrawAction memory withdraw = abi.decode(_receipt.action, (WithdrawAction)); _processWithdraw(withdraw.account, withdraw.amount); } else { revert TransactionVariantInvalid(); } } /// @dev Processes a withdrawal. function _processWithdraw(address _to, uint256 _amount) internal { // If the `_to` is a prover vault, we need to first deposit it to get $iPROVE and then // transfer the $iPROVE to the prover vault. This splits the $PROVE amount amongst all // of the prover stakers. // // Otherwise if the `_to` is not a prover vault, we can just transfer the $PROVE directly. if (ISuccinctStaking(staking).isProver(_to)) { // Deposit $PROVE to mint $iPROVE, sending it to the prover vault. IERC4626(iProve).deposit(_amount, _to); } else { // Transfer the $PROVE from this contract to the `_to` address. IERC20(prove).safeTransfer(_to, _amount); } emit Withdraw(_to, _amount); } /// @dev Updates the auctioneer. function _updateAuctioneer(address _auctioneer) internal { emit AuctioneerUpdate(auctioneer, _auctioneer); auctioneer = _auctioneer; } /// @dev Updates the staking contract. function _updateStaking(address _staking) internal { emit StakingUpdate(staking, _staking); staking = _staking; } /// @dev Updates the verifier. function _updateVerifier(address _verifier) internal { emit VerifierUpdate(verifier, _verifier); verifier = _verifier; } /// @dev Updates the minimum amount for deposit/withdraw operations. function _updateMinDepositAmount(uint256 _amount) internal { emit MinDepositAmountUpdate(minDepositAmount, _amount); minDepositAmount = _amount; } /// @dev Authorizes an ERC1967 proxy upgrade to a new implementation contract. function _authorizeUpgrade(address _newImplementation) internal override onlyOwner {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {IProverRegistry} from "../interfaces/IProverRegistry.sol"; import {IIntermediateSuccinct} from "../interfaces/IIntermediateSuccinct.sol"; import {ERC20} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import {ERC20Burnable} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import {IERC20} from "../../lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import {ERC20Permit} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol"; import {ERC20Votes} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol"; import {ERC4626} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol"; import {Nonces} from "../../lib/openzeppelin-contracts/contracts/utils/Nonces.sol"; string constant NAME = "IntermediateSuccinct"; string constant SYMBOL = "iPROVE"; /// @title IntermediateSuccinct /// @author Succinct Labs /// @notice The intermediary receipt token for receiving periodic $PROVE rewards. /// @dev This contract accepts $PROVE and mints $iPROVE. It is non-transferable outside of /// staking operations. contract IntermediateSuccinct is ERC4626, ERC20Permit, ERC20Votes, IIntermediateSuccinct { /// @inheritdoc IIntermediateSuccinct address public override staking; constructor(address _underlying, address _staking) ERC20(NAME, SYMBOL) ERC4626(IERC20(_underlying)) ERC20Permit(NAME) { staking = _staking; } /// @inheritdoc IIntermediateSuccinct function burn(address _from, uint256 _iPROVE) external override returns (uint256) { if (msg.sender != staking) { revert NonTransferable(); } // Burn the $PROVE uint256 PROVE = previewRedeem(_iPROVE); ERC20Burnable(asset()).burn(PROVE); // Burn the $iPROVE _burn(_from, _iPROVE); return PROVE; } /// @dev Only the staking contract, the vApp, or the prover can transfer in certain /// situations. /// /// Each situation is as follows: /// 1a. The staking contract needs to transfer $iPROVE to a prover during stake(): /// - $iPROVE.deposit() - transfer from address(0) to staking /// - $PROVER-N.deposit() - transfer from staking to prover /// 1b. The staking contract needs to transfer $iPROVE to a prover during unstake(): /// - $PROVER-N.redeem() - transfer from prover to staking /// - $iPROVE.redeem() - transfer from staking to address(0) /// 2. The vApp contract needs to deposit to $iPROVE directly to a prover during /// processWithdraw(to), when `to` is a prover to process it as a prover reward: /// - $iPROVE.deposit() - transfer from address(0) to prover /// /// This function is maximally constrained to only allow for the above situations. function _update(address _from, address _to, uint256 _value) internal override(ERC20, ERC20Votes) { // Check for (1). bool isStakeOrUnstake = msg.sender == staking || (IProverRegistry(staking).isProver(msg.sender) && (_from == staking || _to == staking)); // If not (1), check for (2). bool isProverReward; if (!isStakeOrUnstake) { // vApp can deposit to provers only. isProverReward = msg.sender == IProverRegistry(staking).vapp() && _from == address(0) && IProverRegistry(staking).isProver(_to); } // If not (1) or (2), revert. if (!isStakeOrUnstake && !isProverReward) { revert NonTransferable(); } super._update(_from, _to, _value); } /// @dev Override to allow the staking contract to spend $iPROVE. function _spendAllowance(address _owner, address _spender, uint256 _amount) internal override { if (_spender == staking) { return; } super._spendAllowance(_owner, _spender, _amount); } // The following functions are for overriding the clock and clock mode for IERC6372. This // allows governance to be based on time instead of block number. function clock() public view override returns (uint48) { return uint48(block.timestamp); } function CLOCK_MODE() public pure override returns (string memory) { return "mode=timestamp"; } // The following functions are overrides required by Solidity. function nonces(address _owner) public view override(ERC20Permit, Nonces) returns (uint256) { return super.nonces(_owner); } function decimals() public view virtual override(ERC20, ERC4626) returns (uint8) { return super.decimals(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Proxy.sol) pragma solidity ^0.8.22; import {Proxy} from "../Proxy.sol"; import {ERC1967Utils} from "./ERC1967Utils.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`. * * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. * * Requirements: * * - If `data` is empty, `msg.value` must be zero. */ constructor(address implementation, bytes memory _data) payable { ERC1967Utils.upgradeToAndCall(implementation, _data); } /** * @dev Returns the current implementation address. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ function _implementation() internal view virtual override returns (address) { return ERC1967Utils.getImplementation(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {SuccinctProver} from "../tokens/SuccinctProver.sol"; import {IProver} from "../interfaces/IProver.sol"; import {IProverRegistry} from "../interfaces/IProverRegistry.sol"; import {ISuccinctVApp} from "../interfaces/ISuccinctVApp.sol"; import {Create2} from "../../lib/openzeppelin-contracts/contracts/utils/Create2.sol"; import {IERC20} from "../../lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import {Math} from "../../lib/openzeppelin-contracts/contracts/utils/math/Math.sol"; /// @title ProverRegistry /// @author Succinct Labs /// @notice This contract is used to manage provers. /// @dev Because provers are approved to spend $iPROVE, it is important that tracked /// provers are only contracts with `type(SuccinctProver).creationCode`. abstract contract ProverRegistry is IProverRegistry { /// @dev Minimum price-per-share threshold a prover can be at if slashed. /// /// If slashing would drop the price-per-share below this threshold, the prover is /// permanently deactivated and can no longer be staked to. uint256 internal constant MIN_PROVER_PRICE_PER_SHARE = 1e9; /// @inheritdoc IProverRegistry address public override governor; /// @inheritdoc IProverRegistry address public override vapp; /// @inheritdoc IProverRegistry address public override prove; /// @inheritdoc IProverRegistry address public override iProve; /// @inheritdoc IProverRegistry uint256 public override proverCount; /// @dev A mapping from prover owner to prover vault. mapping(address => address) internal ownerToProver; /// @dev A mapping from prover vault to whether it exists. mapping(address => bool) internal provers; /// @dev A mapping from prover vault to whether it is deactivated. mapping(address => bool) internal deactivatedProvers; /// @dev This empty reserved space to add new variables without shifting down storage. uint256[10] private __gap; /// @dev This call must be sent by the VApp contract. This also acts as a check to ensure that the contract /// has been initialized. modifier onlyVApp() { if (msg.sender != vapp) { revert NotAuthorized(); } _; } /// @dev This call must target a prover that exists in the registry. modifier onlyForProver(address _prover) { if (!provers[_prover]) { revert ProverNotFound(); } _; } function __ProverRegistry_init( address _governor, address _vapp, address _prove, address _iProve ) internal { governor = _governor; vapp = _vapp; prove = _prove; iProve = _iProve; } /// @inheritdoc IProverRegistry function isProver(address _prover) external view override returns (bool) { return provers[_prover]; } /// @inheritdoc IProverRegistry function isDeactivatedProver(address _prover) external view override returns (bool) { return deactivatedProvers[_prover]; } /// @inheritdoc IProverRegistry function getProver(address _owner) external view override returns (address) { return ownerToProver[_owner]; } /// @inheritdoc IProverRegistry function createProver(uint256 _stakerFeeBips) external override returns (address) { if (_stakerFeeBips > 10000) { revert InvalidStakerFeeBips(); } if (ownerToProver[msg.sender] != address(0)) { revert ProverAlreadyExists(); } return _deployProver(msg.sender, _stakerFeeBips); } /// @dev Uses CREATE2 to deploy an instance of SuccinctProver and adds it to the mapping. function _deployProver(address _owner, uint256 _stakerFeeBips) internal returns (address prover) { // Ensure that the contract is initialized. if (iProve == address(0)) { revert NotInitialized(); } // Increment the number of provers. unchecked { ++proverCount; } // Deploy the prover. prover = Create2.deploy( 0, bytes32(uint256(uint160(_owner))), abi.encodePacked( type(SuccinctProver).creationCode, abi.encode(governor, prove, iProve, _owner, proverCount, _stakerFeeBips) ) ); // Update the mappings. ownerToProver[_owner] = prover; provers[prover] = true; // Register the prover with the VApp. ISuccinctVApp(vapp).createProver(prover, _owner, _stakerFeeBips); // Approve the prover as a spender of $iPROVE, so that $iPROVE can be transferred to the // prover during stake(). IERC20(iProve).approve(prover, type(uint256).max); emit ProverDeploy(prover, _owner, _stakerFeeBips); } /// @dev Deactivates a prover if its price-per-share is below the minimum. /// /// Repeatedly slashing a prover and then staking to it reduces the prover's `totalAssets` /// without reducing its `totalSupply`. This drives the price-per-share toward zero. /// After enough cycles, this exponential share inflation would cause an overflow. /// /// By deactivating a prover as soon as its price-per-share falls below /// `MIN_PROVER_PRICE_PER_SHARE`, this overflow vector is eliminated. function _deactivateProverIfPriceBelowMin(address _prover) internal { // If the prover is already deactivated, skip. if (deactivatedProvers[_prover]) return; // If the prover has no shares, skip. uint256 totalSupply = IERC20(_prover).totalSupply(); if (totalSupply == 0) return; // Calculate the prover's price-per-share. uint256 totalAssets = IERC20(iProve).balanceOf(_prover); uint256 pricePerShare = Math.mulDiv(totalAssets, 1e18, totalSupply); // If the prover's price-per-share is below the minimum, deactivate it. if (pricePerShare < MIN_PROVER_PRICE_PER_SHARE) { deactivatedProvers[_prover] = true; emit ProverDeactivation(_prover); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {ERC20Upgradeable} from "../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol"; string constant NAME = "StakedSuccinct"; string constant SYMBOL = "stPROVE"; /// @title StakedSuccinct /// @author Succinct Labs /// @notice The terminal receipt token for staking in the Succinct Prover Network. /// @dev This contract balance stays 1:1 with $PROVER-N vaults to give one unified /// source of truth to track staked $PROVE. It is non-transferable outside of /// staking operations. abstract contract StakedSuccinct is ERC20Upgradeable { error NonTransferable(); /// @dev Only true if in the process of staking or unstaking. bool internal transient isStakingOperation; /// @dev This empty reserved space to add new variables without shifting down storage. uint256[10] private __gap; modifier stakingOperation() { isStakingOperation = true; _; isStakingOperation = false; } function __StakedSuccinct_init() internal onlyInitializing { __ERC20_init(NAME, SYMBOL); } function name() public pure virtual override returns (string memory) { return NAME; } function symbol() public pure virtual override returns (string memory) { return SYMBOL; } /// @dev Only can update balances when staking operations are occuring. This is equivalent to /// the only staking checks that we have on $iPROVE and $PROVER-N tokens. function _update(address _from, address _to, uint256 _value) internal override(ERC20Upgradeable) { if (!isStakingOperation) { revert NonTransferable(); } super._update(_from, _to, _value); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {IProverRegistry} from "./IProverRegistry.sol"; interface ISuccinctStaking is IProverRegistry { /// @dev Represents a claim for unstaking. /// @param iPROVEEscrow The escrowed amount of $iPROVE at request time. /// @param slashFactor The slash factor for the prover when the claim was created (1e27 fp). /// @param timestamp The timestamp when the unstake was requested. Used for comparing against /// the `unstakePeriod()` to determine if the claim can be finished. struct UnstakeClaim { uint256 iPROVEEscrow; uint256 slashFactor; uint256 timestamp; } /// @dev Represents a claim to slash a prover for some amount of $iPROVE. /// @param iPROVE The requested amount of $iPROVE to slash. /// @param timestamp The timestamp when the slash was requested. Used for comparing against /// the `slashCancellationPeriod()` to determine if the claim can be cancelled. /// @param resolved Whether the claim has been resolved (either cancelled or finished). struct SlashClaim { uint256 iPROVE; uint256 timestamp; bool resolved; } /// @dev Represents the escrowed $iPROVE and slash factor for a prover. Escrowed $iPROVE is /// held when a staker unstakes, and allows unstaking to not receive prover rewards but /// still receive the effects of slashing. /// @param iPROVEEscrow The amount of $iPROVE held by this contract for pending unstakes. /// @param slashFactor The slash factor for the prover (1e27 fp). struct EscrowPool { uint256 iPROVEEscrow; uint256 slashFactor; } /// @dev Emitted when a staker first stakes to their delegated prover. This indicates that any /// additional stake from the staker can only be added to this prover, unless unbound. event ProverBound(address indexed staker, address indexed prover); /// @dev Emitted when a staker fully unstakes from their delegated prover. This indicates that /// the staker can now stake to a different prover. event ProverUnbound(address indexed staker, address indexed prover); /// @dev Emitted when a staker stakes into a prover. event Stake( address indexed staker, address indexed prover, uint256 PROVE, uint256 iPROVE, uint256 stPROVE ); /// @dev Emitted when a staker requests to unstake $stPROVE from a prover. event UnstakeRequest( address indexed staker, address indexed prover, uint256 stPROVE, uint256 iPROVESnapshot ); /// @dev Emitted when a staker unstakes from a prover. event Unstake(address indexed staker, address indexed prover, uint256 PROVE, uint256 iPROVE); /// @dev Emitted when a prover is requested to be slashed. event SlashRequest(address indexed prover, uint256 iPROVE, uint256 index); /// @dev Emitted when a prover slash request is canceled. event SlashCancel(address indexed prover, uint256 iPROVE, uint256 index); /// @dev Emitted when a prover slash request is executed. event Slash(address indexed prover, uint256 PROVE, uint256 iPROVE, uint256 index); /// @dev Emitted when stakers are dispensed $PROVE. event Dispense(uint256 PROVE); /// @dev Emitted when the dispenser is updated. event DispenserUpdate(address oldDispenser, address newDispenser); /// @dev Emitted when the dispense rate is updated. event DispenseRateUpdate(uint256 oldDispenseRate, uint256 newDispenseRate); /// @dev Thrown if the staker has insufficient balance to unstake, or if attempting to slash /// more than the prover has. error InsufficientStakeBalance(); /// @dev Thrown if the staker tries to unstake while not staked with the prover. error NotStaked(); /// @dev Thrown if the staker tries to unstake while there is no unstake requests. error NoUnstakeRequests(); /// @dev Thrown if the staker tries to unstake while they already have too many unstake /// requests. error TooManyUnstakeRequests(); /// @dev Thrown if the staker tries to stake or unstake a zero amount. error ZeroAmount(); /// @dev Thrown if staking would result in a receipt token with a zero amount. error ZeroReceiptAmount(); /// @dev Thrown if the staker tries to stake less than the minimum stake amount. error StakeBelowMinimum(); /// @dev Thrown if the staker tries to deposit while already staked with a different prover. error AlreadyStakedWithDifferentProver(address existingProver); /// @dev Thrown if staking or unstaking while the prover has one or more pending slash requests. error ProverHasSlashRequest(); /// @dev Thrown if a slash request has already been resolved. error SlashRequestAlreadyResolved(); /// @dev Thrown if attempting to cancel a slash request before the deadline. error SlashRequestNotReadyToCancel(); /// @dev Thrown if the dispenser is not the owner. error NotDispenser(); /// @dev Thrown if the specified dispense amount exceeds the maximum dispense amount. error AmountExceedsAvailableDispense(); /// @notice The dispenser that can dispense $PROVE to stakers. /// @dev Does not actually hold any $PROVE themselves, simply has the ability to transfer /// $PROVE from the staking contract to the $iPROVE vault, bounded by `maxDispense` /// which itself is bound by `dispenseRate`. Mutable after deployment by owner. function dispenser() external view returns (address); /// @notice The minimum amount of $PROVE that a staker needs to stake. /// @dev The actual `staked` amount may go below this value. Only used as one part in a /// multi-part deterrence against ERC4626 inflation attacks. /// Immutable after deployment. function minStakeAmount() external view returns (uint256); /// @notice The maximum amount of unstake requests a staker can have at a time. /// @dev Ensures that a staker cannot unintentionally self-DoS themselves by creating enough /// unstake requests to cause an out-of-gas error when calling `finishUnstake`. /// Immutable after deployment. function maxUnstakeRequests() external view returns (uint256); /// @notice The minimum delay (in seconds) for an unstake request be finished. /// @dev Ensures that a staker cannot frontrun an upcoming prover slash by unstaking early. /// Should be greater than the longest length that a VApp `step` can be delayed by. /// Immutable after deployment. function unstakePeriod() external view returns (uint256); /// @notice The minimum delay (in seconds), plus governance parameters, for a slash request /// to be cancelled. /// @dev Cancelling a slash requires `slashCancellationPeriod` + `votingDelay` + /// `votingPeriod` to ensure that governance has had sufficient time finish a slash if /// needed. Immutable after deployment. function slashCancellationPeriod() external view returns (uint256); /// @notice The maximum amount of $PROVE that can be dispensed per second. /// @dev Mutable after deployment by owner. function dispenseRate() external view returns (uint256); /// @notice The timestamp when the dispense rate was last updated. function dispenseRateTimestamp() external view returns (uint256); /// @notice The total amount of $PROVE earned through dispense emissions from inception up to dispenseRateTimestamp. function dispenseEarned() external view returns (uint256); /// @notice The total amount of $PROVE distributed through the dispense mechanism. function dispenseDistributed() external view returns (uint256); /// @notice The prover that a staker is staked with. /// @dev A staker can only be staked with one prover at a time. To switch provers, they must /// fully unstake from their current prover first. /// @param staker The address of the staker. /// @return The address of the prover. function stakedTo(address staker) external view returns (address); /// @notice The amount $PROVE that a staker would receive if their full $stPROVE balance was /// unstaked. /// @dev This does not account for any slashing that could occur during the unstaking period. /// @param staker The address of the staker. /// @return The amount of $PROVE. function staked(address staker) external view returns (uint256); /// @notice The amount of $PROVE that a prover has staked to them. /// @param prover The address of the prover. /// @return The amount of $PROVE. function proverStaked(address prover) external view returns (uint256); /// @notice The unstake requests for a staker. /// @param staker The address of the staker. /// @return The unstake requests. function unstakeRequests(address staker) external view returns (UnstakeClaim[] memory); /// @notice The slash requests for a prover. /// @param prover The address of the prover. /// @return The slash requests. function slashRequests(address prover) external view returns (SlashClaim[] memory); /// @notice The escrow pool for a prover. /// @param prover The address of the prover. /// @return The escrow pool. function escrowPool(address prover) external view returns (EscrowPool memory); /// @notice The amount of $PROVE that a staker would receive with their pending unstake requests. /// @dev Returns the sum of snapshotted $PROVE values for all pending unstake claims, adjusted /// for any slashing that occurred after the requests were made. /// @param staker The address of the staker. /// @return The amount of $PROVE. function unstakePending(address staker) external view returns (uint256); /// @notice The amount of $PROVE that a staker would receive if they unstaked from a prover. /// @param prover The address of the prover. /// @param stPROVE The amount of $stPROVE to unstake. /// @return The amount of $PROVE. function previewUnstake(address prover, uint256 stPROVE) external view returns (uint256); /// @notice The maximum amount of $PROVE that can be dispensed currently. /// @dev Calculates the total earned minus total distributed. The total earned includes both /// historical earnings and current period earnings. /// @return The maximum amount of $PROVE available to dispense. function maxDispense() external view returns (uint256); /// @notice Stake $PROVE to a prover. Must have approved $PROVE with this contract as the /// spender. You may only stake to one prover at a time. /// @dev Deposits $PROVE into the iPROVE vault to mint $iPROVE, then deposits $iPROVE into the /// chosen prover to mint $PROVER-N/$stPROVE. /// @param prover The address of the prover to delegate $iPROVE to. /// @param PROVE The amount of $PROVE to deposit. /// @return The amount of $stPROVE received. function stake(address prover, uint256 PROVE) external returns (uint256); /// @notice Stake $PROVE to a prover. You may only stake to one prover at a time. /// @dev Deposits $PROVE to mint $iPROVE, then deposits $iPROVE into the chosen /// prover to mint $PROVER-N/$stPROVE. The prover is the spender of the permit, rather /// than the staking contract, to avoid someone using the permit signature for an /// unintended prover. /// @param prover The address of the prover to delegate $PROVE to. /// @param staker The address if the staker. Must correspond to the signer of the permit /// signature. /// @param PROVE The amount of $PROVE to spend for the deposit. /// @param deadline The deadline for the permit signature. /// @param v The v component of the permit signature. /// @param r The r component of the permit signature. /// @param s The s component of the permit signature. /// @return The amount of $stPROVE the staker received. function permitAndStake( address prover, address staker, uint256 PROVE, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external returns (uint256); /// @notice Creates a request to unstake $stPROVE from the prover for the specified amount. Only /// callable by the staker. /// @dev The staker must have enough $stPROVE that is not already in the unstake request queue. /// The $iPROVE value is snapshotted at request time to prevent earning rewards during /// the unstaking period. /// @param stPROVE The amount of $stPROVE to unstake. function requestUnstake(uint256 stPROVE) external; /// @notice Finishes the unstaking process for the specified address. Callable by anyone. /// Must have first called `requestUnstake()` and waited for the unstake period to pass. /// @dev For each claim, if any snapshotted $iPROVE is lower than the actual $iPROVE that was /// received, then the difference is given back to the prover. /// @param staker The address whose unstake claims to finish. /// @return The amount of $PROVE received. function finishUnstake(address staker) external returns (uint256); /// @notice Creates a request to slash a prover for the specified amount. Only callable by the /// VApp. /// @param prover The address of the prover to slash. /// @param iPROVE The amount of $iPROVE to slash. /// @return The index of the new slash request in this prover's slash requests storage array. /// Because when slash requests are processed, it alters the order of the array, it is /// best to first call `slashRequests(prover)` to get the index of the specific slash /// request that is intended to be executed. function requestSlash(address prover, uint256 iPROVE) external returns (uint256); /// @notice Cancels a slash request. Only possible to call if `requestSlash()` has been called /// for this index, and the `slashPeriod()` plus governance latency has passed. /// @param prover The address of the prover to slash. /// @param index The index of the slash request to cancel. function cancelSlash(address prover, uint256 index) external; /// @notice Finishes the slashing process. Only possible to call if `requestSlash()` has been /// called for this index, and only callable by the owner. Decreases the value of $stPROVE /// for all stakers of that prover. /// @param prover The address of the prover to slash. /// @param index The index of the slash request to finish. /// @return The amount of $iPROVE slashed. function finishSlash(address prover, uint256 index) external returns (uint256); /// @notice Distributes $PROVE rewards to all stakers by transferring to the iPROVE vault. /// Only callable by the dispenser. /// @dev The transferred $PROVE increases the value of iPROVE shares, proportionally benefiting /// all stakers. The amount must not exceed maxDispense() unless type(uint256).max is /// passed, which dispenses the full available amount. /// @param PROVE The amount of $PROVE to dispense. Pass `type(uint256).max` to dispense all /// available rewards. function dispense(uint256 PROVE) external; /// @notice Updates the dispenser. Only callable by the owner. /// @param dispenser The new dispenser. function setDispenser(address dispenser) external; /// @notice Updates the dispense rate. Only callable by the owner. /// @dev When called, this function first accrues all earnings at the old rate up to the /// current timestamp, then sets the new rate for future earnings. /// @param dispenseRate The new dispense rate in $PROVE per second. function updateDispenseRate(uint256 dispenseRate) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; interface IIntermediateSuccinct { /// @dev Thrown when a transfer is attempted. error NonTransferable(); /// @notice Returns the address of the staking contract. function staking() external view returns (address); /// @notice Burn $iPROVE. Only callable by the staking contract. /// @param from The address of the staker. /// @param iPROVE The amount of $iPROVE to burn. /// @return The amount of $PROVE burned. function burn(address from, uint256 iPROVE) external returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; interface IProver { /// @dev Thrown when a zero address is provided. error ZeroAddress(); /// @dev Thrown when the caller is not the prover owner. error NotProverOwner(); /// @dev Thrown when the caller is not the staking contract. error NotStaking(); /// @dev Thrown when a transfer is attempted. error NonTransferable(); /// @notice The staking contract that corresponding to this prover. /// @dev This address cannot be changed. /// @return The address of the staking contract. function staking() external view returns (address); /// @notice The governor used in protocol governance. /// @dev This address cannot be changed. /// @return The address of the governor contract. function governor() external view returns (address); /// @notice The $PROVE token /// @dev This address cannot be changed. /// @return The address of the $PROVE token. function prove() external view returns (address); /// @notice The owner of this prover. The owner was the address that created this prover by /// calling `createProver()` on the staking contract. The owner has control over /// particpiation in governance, collection of prover owner rewards, and the signing /// rights of verifiable prover network actions such as bidding and fulfilling proofs. /// @dev This address cannot be changed. /// @return The address of the prover owner. function owner() external view returns (address); /// @notice The ID of this prover. IDs are assigned sequentially, incrementing /// each time a prover is created. /// @dev This is purely for informational purposes. This ID cannot be changed. /// @return The ID of the prover. function id() external view returns (uint256); /// @notice The staker fee percentage in basis points (one-hundredth of a percent). For a /// given $PROVE reward for fulfilling proofs, this much goes into this prover. /// @dev This fee cannot be changed. /// @return The staker fee percentage in basis points. function stakerFeeBips() external view returns (uint256); /// @notice Create a governance proposal. Only callable by the prover owner. /// @dev This function is a wrapper around `IGovernor.propose`. /// @param targets The addresses of the contracts to call. /// @param values The amounts of ETH to send. /// @param calldatas The calldata for each call. /// @param description The proposal description. /// @return The proposal ID. function propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description ) external returns (uint256); /// @notice Cancel a governance proposal. Only callable by the prover owner. /// @dev This function is a wrapper around `IGovernor.cancel`. /// @param targets The addresses of the contracts to call. /// @param values The amounts of ETH to send. /// @param calldatas The calldata for each call. /// @param descriptionHash The hash of the proposal description. /// @return The proposal ID. function cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external returns (uint256); /// @notice Cast a vote on a governance proposal. Only callable by the prover owner. /// @dev This function is a wrapper around `IGovernor.castVote`. /// @param proposalId The ID of the proposal. /// @param support The vote type (0 = Against, 1 = For, 2 = Abstain). /// @return The voting weight used. function castVote(uint256 proposalId, uint8 support) external returns (uint256); /// @notice Transfer $PROVE to the staking contract. Only callable by the staking contract. /// @dev Since in `SuccinctStaking.permitAndStake()`, the staker approves the prover to spend $PROVE, the /// staking contract needs to transfer the $PROVE utilizing this contract as the spender. /// @param from The address to transfer $PROVE from. /// @param amount The amount of $PROVE to transfer. function transferProveToStaking(address from, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {Governor} from "../lib/openzeppelin-contracts/contracts/governance/Governor.sol"; import {GovernorCountingSimple} from "../lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol"; import {GovernorSettings} from "../lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol"; import {GovernorVotes} from "../lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol"; import {GovernorVotesQuorumFraction} from "../lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; import {IVotes} from "../lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol"; string constant NAME = "SuccinctGovernor"; /// @title SuccinctGovernor /// @author Succinct Labs /// @notice Governor for governance operations in the Succinct Prover Network. /// @dev This contract should only be made owner of the relevant contracts (e.g. SuccinctStaking) /// once sufficient staking (minting of $iPROVE) has occurred. contract SuccinctGovernor is Governor, GovernorSettings, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction { constructor( address _iPROVE, uint48 _votingDelay, uint32 _votingPeriod, uint256 _proposalThreshold, uint256 _quorumFraction ) Governor(NAME) GovernorSettings(_votingDelay, _votingPeriod, _proposalThreshold) GovernorVotes(IVotes(_iPROVE)) GovernorVotesQuorumFraction(_quorumFraction) {} // The following functions are overrides required by Solidity. function votingDelay() public view override(Governor, GovernorSettings) returns (uint256) { return super.votingDelay(); } function votingPeriod() public view override(Governor, GovernorSettings) returns (uint256) { return super.votingPeriod(); } function quorum(uint256 _blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { return super.quorum(_blockNumber); } function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { return super.proposalThreshold(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. * * Adds the {permit} method, which can be used to change an account's ERC-20 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol"; import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. * * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being * set here. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements. */ function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { 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 silently catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { bool success; uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) returnSize := returndatasize() returnValue := mload(0) } return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol) pragma solidity ^0.8.20; import {Panic} from "../Panic.sol"; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an success flag (no overflow). */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow). */ function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow). */ function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). */ function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. * * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute * one branch when needed, making this function more expensive. */ function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) { unchecked { // branchless ternary works because: // b ^ (a ^ b) == a // b ^ 0 == b return b ^ ((a ^ b) * SafeCast.toUint(condition)); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a > b, a, b); } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a < b, a, b); } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. Panic.panic(Panic.DIVISION_BY_ZERO); } // The following calculation ensures accurate ceiling division without overflow. // Since a is non-zero, (a - 1) / b will not overflow. // The largest possible result occurs when (a - 1) / b is type(uint256).max, // but the largest value we can obtain is type(uint256).max - 1, which happens // when a = type(uint256).max and b = 1. unchecked { return SafeCast.toUint(a > 0) * ((a - 1) / b + 1); } } /** * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2²⁵⁶ + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. if (denominator <= prod1) { Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW)); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv ≡ 1 mod 2⁴. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2⁸ inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ inverse *= 2 - denominator * inverse; // inverse mod 2³² inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @dev Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); } /** * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. * * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0. * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. * * If the input value is not inversible, 0 is returned. * * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}. */ function invMod(uint256 a, uint256 n) internal pure returns (uint256) { unchecked { if (n == 0) return 0; // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) // Used to compute integers x and y such that: ax + ny = gcd(a, n). // When the gcd is 1, then the inverse of a modulo n exists and it's x. // ax + ny = 1 // ax = 1 + (-y)n // ax ≡ 1 (mod n) # x is the inverse of a modulo n // If the remainder is 0 the gcd is n right away. uint256 remainder = a % n; uint256 gcd = n; // Therefore the initial coefficients are: // ax + ny = gcd(a, n) = n // 0a + 1n = n int256 x = 0; int256 y = 1; while (remainder != 0) { uint256 quotient = gcd / remainder; (gcd, remainder) = ( // The old remainder is the next gcd to try. remainder, // Compute the next remainder. // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd // where gcd is at most n (capped to type(uint256).max) gcd - remainder * quotient ); (x, y) = ( // Increment the coefficient of a. y, // Decrement the coefficient of n. // Can overflow, but the result is casted to uint256 so that the // next value of y is "wrapped around" to a value between 0 and n - 1. x - y * int256(quotient) ); } if (gcd != 1) return 0; // No inverse exists. return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative. } } /** * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`. * * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that * `a**(p-2)` is the modular multiplicative inverse of a in Fp. * * NOTE: this function does NOT check that `p` is a prime greater than `2`. */ function invModPrime(uint256 a, uint256 p) internal view returns (uint256) { unchecked { return Math.modExp(a, p - 2, p); } } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) * * Requirements: * - modulus can't be zero * - underlying staticcall to precompile must succeed * * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make * sure the chain you're using it on supports the precompiled contract for modular exponentiation * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, * the underlying function will succeed given the lack of a revert, but the result may be incorrectly * interpreted as 0. */ function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { (bool success, uint256 result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying * to operate modulo 0 or if the underlying precompile reverted. * * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack * of a revert, but the result may be incorrectly interpreted as 0. */ function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { if (m == 0) return (false, 0); assembly ("memory-safe") { let ptr := mload(0x40) // | Offset | Content | Content (Hex) | // |-----------|------------|--------------------------------------------------------------------| // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x60:0x7f | value of b | 0x<.............................................................b> | // | 0x80:0x9f | value of e | 0x<.............................................................e> | // | 0xa0:0xbf | value of m | 0x<.............................................................m> | mstore(ptr, 0x20) mstore(add(ptr, 0x20), 0x20) mstore(add(ptr, 0x40), 0x20) mstore(add(ptr, 0x60), b) mstore(add(ptr, 0x80), e) mstore(add(ptr, 0xa0), m) // Given the result < m, it's guaranteed to fit in 32 bytes, // so we can use the memory scratch space located at offset 0. success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) result := mload(0x00) } } /** * @dev Variant of {modExp} that supports inputs of arbitrary length. */ function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { (bool success, bytes memory result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Variant of {tryModExp} that supports inputs of arbitrary length. */ function tryModExp( bytes memory b, bytes memory e, bytes memory m ) internal view returns (bool success, bytes memory result) { if (_zeroBytes(m)) return (false, new bytes(0)); uint256 mLen = m.length; // Encode call args in result and move the free memory pointer result = abi.encodePacked(b.length, e.length, mLen, b, e, m); assembly ("memory-safe") { let dataPtr := add(result, 0x20) // Write result on top of args to avoid allocating extra memory. success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) // Overwrite the length. // result.length > returndatasize() is guaranteed because returndatasize() == m.length mstore(result, mLen) // Set the memory pointer after the returned data. mstore(0x40, add(dataPtr, mLen)) } } /** * @dev Returns whether the provided byte array is zero. */ function _zeroBytes(bytes memory byteArray) private pure returns (bool) { for (uint256 i = 0; i < byteArray.length; ++i) { if (byteArray[i] != 0) { return false; } } return true; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * This method is based on Newton's method for computing square roots; the algorithm is restricted to only * using integer operations. */ function sqrt(uint256 a) internal pure returns (uint256) { unchecked { // Take care of easy edge cases when a == 0 or a == 1 if (a <= 1) { return a; } // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between // the current value as `ε_n = | x_n - sqrt(a) |`. // // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is // bigger than any uint256. // // By noticing that // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar // to the msb function. uint256 aa = a; uint256 xn = 1; if (aa >= (1 << 128)) { aa >>= 128; xn <<= 64; } if (aa >= (1 << 64)) { aa >>= 64; xn <<= 32; } if (aa >= (1 << 32)) { aa >>= 32; xn <<= 16; } if (aa >= (1 << 16)) { aa >>= 16; xn <<= 8; } if (aa >= (1 << 8)) { aa >>= 8; xn <<= 4; } if (aa >= (1 << 4)) { aa >>= 4; xn <<= 2; } if (aa >= (1 << 2)) { xn <<= 1; } // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). // // We can refine our estimation by noticing that the middle of that interval minimizes the error. // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). // This is going to be our x_0 (and ε_0) xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) // From here, Newton's method give us: // x_{n+1} = (x_n + a / x_n) / 2 // // One should note that: // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a // = ((x_n² + a) / (2 * x_n))² - a // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) // = (x_n² - a)² / (2 * x_n)² // = ((x_n² - a) / (2 * x_n))² // ≥ 0 // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n // // This gives us the proof of quadratic convergence of the sequence: // ε_{n+1} = | x_{n+1} - sqrt(a) | // = | (x_n + a / x_n) / 2 - sqrt(a) | // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | // = | (x_n - sqrt(a))² / (2 * x_n) | // = | ε_n² / (2 * x_n) | // = ε_n² / | (2 * x_n) | // // For the first iteration, we have a special case where x_0 is known: // ε_1 = ε_0² / | (2 * x_0) | // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) // ≤ 2**(2*e-4) / (3 * 2**(e-1)) // ≤ 2**(e-3) / 3 // ≤ 2**(e-3-log2(3)) // ≤ 2**(e-4.5) // // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: // ε_{n+1} = ε_n² / | (2 * x_n) | // ≤ (2**(e-k))² / (2 * 2**(e-1)) // ≤ 2**(2*e-2*k) / 2**e // ≤ 2**(e-2*k) xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either // sqrt(a) or sqrt(a) + 1. return xn - SafeCast.toUint(xn > a / xn); } } /** * @dev Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 exp; unchecked { exp = 128 * SafeCast.toUint(value > (1 << 128) - 1); value >>= exp; result += exp; exp = 64 * SafeCast.toUint(value > (1 << 64) - 1); value >>= exp; result += exp; exp = 32 * SafeCast.toUint(value > (1 << 32) - 1); value >>= exp; result += exp; exp = 16 * SafeCast.toUint(value > (1 << 16) - 1); value >>= exp; result += exp; exp = 8 * SafeCast.toUint(value > (1 << 8) - 1); value >>= exp; result += exp; exp = 4 * SafeCast.toUint(value > (1 << 4) - 1); value >>= exp; result += exp; exp = 2 * SafeCast.toUint(value > (1 << 2) - 1); value >>= exp; result += exp; result += SafeCast.toUint(value > 1); } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 isGt; unchecked { isGt = SafeCast.toUint(value > (1 << 128) - 1); value >>= isGt * 128; result += isGt * 16; isGt = SafeCast.toUint(value > (1 << 64) - 1); value >>= isGt * 64; result += isGt * 8; isGt = SafeCast.toUint(value > (1 << 32) - 1); value >>= isGt * 32; result += isGt * 4; isGt = SafeCast.toUint(value > (1 << 16) - 1); value >>= isGt * 16; result += isGt * 2; result += SafeCast.toUint(value > (1 << 8) - 1); } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.22; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC-1967 compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC-1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import { TransactionVariant, Transaction, DepositAction, CreateProverAction, Receipt } from "./PublicValues.sol"; /// @notice Library for handling receipts library Receipts { /// @dev Thrown when an unsupported transaction is encountered. error UnsupportedTransactionVariant(); /// @dev Thrown when the transaction variant does not match the receipt variant. error TransactionVariantMismatch(TransactionVariant variant, TransactionVariant receipt); /// @dev Thrown when the transaction does not match the receipt. error TransactionReceiptMismatch(TransactionVariant variant, uint64 receipt); /// @dev Asserts that the transaction and receipt are consistent. function assertEq(Transaction memory _transaction, Receipt memory _receipt) internal pure { if (_receipt.variant == TransactionVariant.Deposit) { _assertDepositEq(_receipt, _transaction); } else if (_receipt.variant == TransactionVariant.CreateProver) { _assertProverEq(_receipt, _transaction); } else { revert UnsupportedTransactionVariant(); } } /// @dev Asserts that the deposit transaction matches the receipt. function _assertDepositEq(Receipt memory _receipt, Transaction memory _transaction) internal pure { if (_receipt.variant != TransactionVariant.Deposit) { revert TransactionVariantMismatch(_transaction.variant, _receipt.variant); } else if (_transaction.variant != TransactionVariant.Deposit) { revert TransactionVariantMismatch(_transaction.variant, _receipt.variant); } DepositAction memory deposit = abi.decode(_transaction.action, (DepositAction)); DepositAction memory depositReceipt = abi.decode(_receipt.action, (DepositAction)); if (deposit.account != depositReceipt.account) { revert TransactionReceiptMismatch(TransactionVariant.Deposit, _receipt.onchainTxId); } if (deposit.amount != depositReceipt.amount) { revert TransactionReceiptMismatch(TransactionVariant.Deposit, _receipt.onchainTxId); } } /// @dev Asserts that the prover transaction matches the receipt. function _assertProverEq(Receipt memory _receipt, Transaction memory _transaction) internal pure { if (_receipt.variant != TransactionVariant.CreateProver) { revert TransactionVariantMismatch(_transaction.variant, _receipt.variant); } else if (_transaction.variant != TransactionVariant.CreateProver) { revert TransactionVariantMismatch(_transaction.variant, _receipt.variant); } CreateProverAction memory prover = abi.decode(_transaction.action, (CreateProverAction)); CreateProverAction memory proverReceipt = abi.decode(_receipt.action, (CreateProverAction)); if (prover.prover != proverReceipt.prover) { revert TransactionReceiptMismatch(TransactionVariant.CreateProver, _receipt.onchainTxId); } if (prover.owner != proverReceipt.owner) { revert TransactionReceiptMismatch(TransactionVariant.CreateProver, _receipt.onchainTxId); } if (prover.stakerFeeBips != proverReceipt.stakerFeeBips) { revert TransactionReceiptMismatch(TransactionVariant.CreateProver, _receipt.onchainTxId); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @notice A transaction. struct Transaction { /// @notice The variant of the transaction. TransactionVariant variant; /// @notice The status of the transaction. TransactionStatus status; /// @notice The onchain transaction ID. uint64 onchainTxId; /// @notice The action of one of {Deposit, Withdraw, CreateProver}. bytes action; } /// @notice The receipt for a transaction. struct Receipt { /// @notice The variant of the transaction. TransactionVariant variant; /// @notice The status of the transaction. TransactionStatus status; /// @notice The onchain transaction ID. uint64 onchainTxId; /// @notice The action of one of {Deposit, Withdraw, CreateProver}. bytes action; } /// @notice The type of transaction. enum TransactionVariant { Deposit, Withdraw, CreateProver } /// @notice The status of a transaction. enum TransactionStatus { /// The transaction has no initialiezd status. None, /// The transaction has been included in the ledger but is not yet executed. Pending, /// The transaction executed successfully. Completed, /// The transaction reverted during execution. Reverted } /// @notice The action data for a deposit. struct DepositAction { address account; uint256 amount; } /// @notice The action data for a withdraw. struct WithdrawAction { address account; uint256 amount; } /// @notice The action data for an add signer. struct CreateProverAction { address prover; address owner; uint256 stakerFeeBips; } /// @notice The public values encoded as a struct that can be easily deserialized inside Solidity. struct StepPublicValues { bytes32 oldRoot; bytes32 newRoot; uint64 timestamp; Receipt[] receipts; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {TransactionVariant} from "../libraries/PublicValues.sol"; import {TransactionStatus} from "../libraries/PublicValues.sol"; interface ISuccinctVApp { /// @notice Emitted when a receipt is completed. event TransactionCompleted( uint64 indexed onchainTx, TransactionVariant indexed variant, bytes data ); /// @notice Emitted when a receipt is failed. event TransactionReverted( uint64 indexed onchainTx, TransactionVariant indexed variant, bytes data ); /// @notice Emitted when a receipt is pending. event TransactionPending( uint64 indexed onchainTx, TransactionVariant indexed variant, bytes data ); /// @notice Emitted when a new block was committed. event Block(uint64 indexed block, bytes32 oldRoot, bytes32 newRoot); /// @notice Emitted when the program was forked. event Fork(uint64 indexed block, bytes32 oldVkey, bytes32 newVkey); /// @notice Emitted when a deposit is processed. event Deposit(address indexed from, uint256 amount); /// @notice Emitted when a withdrawal is processed. event Withdraw(address indexed to, uint256 amount); /// @notice Emitted when the auctioneer address was updated. event AuctioneerUpdate(address oldAuctioneer, address newAuctioneer); /// @notice Emitted when the staking address was updated. event StakingUpdate(address oldStaking, address newStaking); /// @notice Emitted when the verifier address was updated. event VerifierUpdate(address oldVerifier, address newVerifier); /// @notice Emitted when the minimum deposit was updated. event MinDepositAmountUpdate(uint256 oldMinDepositAmount, uint256 newMinDepositAmount); /// @dev Thrown when the caller is not the auctioneer. error NotAuctioneer(); /// @dev Thrown when the caller is not the staking contract. error NotStaking(); /// @dev Thrown when an address parameter is zero. error ZeroAddress(); /// @dev Thrown when a hash parameter is zero. error ZeroHash(); /// @dev Thrown if the actual balance does not match the expected balance. error BalanceMismatch(); /// @dev Thrown when an amount parameter is invalid. error InvalidAmount(); /// @dev Thrown when a root parameter is invalid. error InvalidRoot(); /// @dev Thrown when an old root parameter is invalid. error InvalidOldRoot(); /// @dev Thrown when a sweep transfer fails. error SweepTransferFailed(); /// @dev Thrown when an invalid vkey is encountered. error InvalidVkey(); /// @dev Thrown when the state is not frozen. error NotFrozen(); /// @dev Thrown when an invalid proof is encountered. error InvalidProof(); /// @dev Thrown when an invalid timestamp is encountered. error InvalidTimestamp(); /// @dev Thrown when a timestamp is in the past. error TimestampInPast(); /// @dev Thrown when a timestamp is too far in the past (more than 1 hour before the current block time). error TimestampTooOld(); /// @dev Thrown when a proof fails. error ProofFailed(); /// @dev Thrown when a deposit is below the minimum. error TransferBelowMinimum(); /// @dev Thrown when trying to register a prover and the owner mismatches the staking contract's /// owner of the prover. error ProverNotOwned(); /// @dev Thrown when public values receipts are sent in an order that does not match the /// onchain transaction order. error ReceiptOutOfOrder(uint64 expected, uint64 given); /// @dev Thrown when a receipt status is invalid. error ReceiptStatusInvalid(TransactionStatus status); /// @dev Thrown when a transaction variant is invalid. error TransactionVariantInvalid(); /// @notice The verification key for the vApp program. function vkey() external view returns (bytes32); /// @notice The address of the $PROVE token. function prove() external view returns (address); /// @notice The address of the $iPROVE token. function iProve() external view returns (address); /// @notice The auctioneer of the VApp. /// @dev This is the only address that can call `step` function on the VApp. /// Mutable after deployment by owner. function auctioneer() external view returns (address); /// @notice The address of the staking contract. function staking() external view returns (address); /// @notice The address of the SP1 verifier contract. /// @dev This can either be a specific SP1Verifier for a specific version, or the /// SP1VerifierGateway which can be used to verify proofs for any version of SP1. /// For the list of supported verifiers on each chain, see: /// https://github.com/succinctlabs/sp1-contracts/tree/main/contracts/deployments function verifier() external view returns (address); /// @notice The block number of the last state update. function blockNumber() external view returns (uint64); /// @notice The minimum amount of $PROVE needed to deposit. /// @dev Since each deposit must be processed by the VApp, this prevents DoS from dust /// amounts. Mutable after deployment by owner. function minDepositAmount() external view returns (uint256); /// @notice The state root for the current block. function root() external view returns (bytes32); /// @notice The timestamp for the current block. function timestamp() external view returns (uint64); /// @notice Tracks the incrementing onchainTx counter. function currentOnchainTxId() external view returns (uint64); /// @notice The onchainTx of the last finalized deposit. function finalizedOnchainTxId() external view returns (uint64); /// @notice State root for each block. function roots(uint64 block) external view returns (bytes32); /// @notice Timestamp for each block. function timestamps(uint64 block) external view returns (uint64); /// @notice Transactions for pending actions. function transactions(uint64 onchainTx) external view returns ( TransactionVariant action, TransactionStatus status, uint64 timestamp, bytes memory data ); /// @notice Deposit $PROVE into the prover network, must have already approved the contract as /// a spender. The depositing account is credited with the $PROVE. Do not deposit with a /// multisig or contract account, as funds will be unrecoverable on the prover network. /// @dev Because the prover network does not support contracts, only secp256k1 ECDSA EOAs can /// interact with this balance. Therefor only EOAs should call this function, and funds /// should only ever be transferred between EOAs on the prover network. /// @param amount The amount of $PROVE to deposit. /// @return receipt The receipt for the deposit. function deposit(uint256 amount) external returns (uint64 receipt); /// @notice Approve and deposit $PROVE in a single call using a permit signature. The depositing /// account is credited with the $PROVE. Do not deposit with a multisig or contract /// account, as funds will be unrecoverable on the prover network. /// @dev Assumes $PROVE implements permit (https://eips.ethereum.org/EIPS/eip-2612). /// Because the prover network does not support contracts, only secp256k1 ECDSA EOAs can /// interact with this balance. Therefor only EOAs should call this function, and funds /// should only ever be transferred between EOAs on the prover network. /// @param from The address to spend the $PROVE from. Must correspond to the signer of the permit /// signature. /// @param amount The amount of $PROVE to spend for the deposit. /// @param deadline The deadline for the permit signature. /// @param v The v component of the permit signature. /// @param r The r component of the permit signature. /// @param s The s component of the permit signature. /// @return receipt The receipt for the deposit. function permitAndDeposit( address from, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external returns (uint64 receipt); /// @notice Register a newly created prover. Only callable by the staking contract. /// @param prover The address of the prover. /// @param owner The address of the prover owner. /// @param stakerFeeBips The staker fee in basis points. function createProver(address prover, address owner, uint256 stakerFeeBips) external returns (uint64 receipt); /// @notice Update the state of the vApp. /// @dev Reverts if the committed actions are invalid. /// @param publicValues The public values for the state update. /// @param proofBytes The proof bytes for the state update. /// @return block The new block number. /// @return oldRoot The old state root. /// @return newRoot The new state root. function step(bytes calldata publicValues, bytes calldata proofBytes) external returns (uint64 block, bytes32 oldRoot, bytes32 newRoot); /// @notice Updates the vapp program verification key, forks the state root. /// @dev Only callable by the owner, executes a state update. Also increments /// the block number. /// @param vkey The new vkey. /// @param root The new root. /// @return block The new block number. /// @return oldRoot The old state root. /// @return newRoot The new state root. function fork(bytes32 vkey, bytes32 root) external returns (uint64 block, bytes32 oldRoot, bytes32 newRoot); /// @notice Updates the auctioneer address. /// @dev Only callable by the owner. /// @param auctioneer The new auctioneer address. function updateAuctioneer(address auctioneer) external; /// @notice Updates the succinct staking contract address. /// @dev Only callable by the owner. /// @param staking The new staking contract address. function updateStaking(address staking) external; /// @notice Updates the verifier address. /// @dev Only callable by the owner. /// @param verifier The new verifier address. function updateVerifier(address verifier) external; /// @notice Updates the minimum amount for deposit operations. /// @dev Only callable by the owner. /// @param amount The new minimum amount. function updateMinDepositAmount(uint256 amount) external; /// @notice Pauses deposit, prover creation, and step. /// @dev Only callable by the owner. function pause() external; /// @notice Unpauses deposit, prover creation, and step. /// @dev Only callable by the owner. function unpause() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /// @title SP1 Verifier Interface /// @author Succinct Labs /// @notice This contract is the interface for the SP1 Verifier. interface ISP1Verifier { /// @notice Verifies a proof with given public values and vkey. /// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of /// target verifier's VERIFIER_HASH. /// @param programVKey The verification key for the RISC-V program. /// @param publicValues The public values encoded as bytes. /// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes. function verifyProof( bytes32 programVKey, bytes calldata publicValues, bytes calldata proofBytes ) external view; } interface ISP1VerifierWithHash is ISP1Verifier { /// @notice Returns the hash of the verifier. function VERIFIER_HASH() external pure returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Pausable struct PausableStorage { bool _paused; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300; function _getPausableStorage() private pure returns (PausableStorage storage $) { assembly { $.slot := PausableStorageLocation } } /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { PausableStorage storage $ = _getPausableStorage(); $._paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { PausableStorage storage $ = _getPausableStorage(); return $._paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; interface IProverRegistry { /// @dev Emitted when a prover is deployed. event ProverDeploy(address indexed prover, address owner, uint256 stakerFeeBips); /// @dev Emitted when a prover is deactivated. event ProverDeactivation(address indexed prover); /// @dev Thrown creating a prover before the registry is initialized. error NotInitialized(); /// @dev Thrown if the caller is not authorized to perform the action. error NotAuthorized(); /// @dev Thrown when an address parameter is zero. error ZeroAddress(); /// @dev Thrown if the specified prover does not exist. error ProverNotFound(); /// @dev Thrown if a prover already exists for this owner. error ProverAlreadyExists(); /// @dev Thrown if the staker fee is greater than 100%. error InvalidStakerFeeBips(); /// @dev Thrown when attempting to stake to a deactivated prover. error ProverNotActive(); /// @notice The address of the governor contract. function governor() external view returns (address); /// @notice The address of the VApp. function vapp() external view returns (address); /// @notice The address of the $PROVE token. function prove() external view returns (address); /// @notice The address of the $iPROVE token. function iProve() external view returns (address); /// @notice The number of provers in the registry. function proverCount() external view returns (uint256); /// @notice Check if a given address is a prover. /// @dev This does not check if the prover is deactivated, use `isDeactivatedProver` to check /// if the prover is deactivated. /// @param prover The address of the prover. /// @return True if the address is a prover, false otherwise. function isProver(address prover) external view returns (bool); /// @notice Check if a given prover is deactivated and cannot be staked to. /// @dev A prover can be deactivated if it is slashed to the point where its price-per-share /// drops below the minimum. /// @param prover The address of the prover. /// @return True if the prover is deactivated, false otherwise. function isDeactivatedProver(address prover) external view returns (bool); /// @notice Get the address of a prover for a given owner. /// @param owner The address of the owner. /// @return The address of the prover. function getProver(address owner) external view returns (address); /// @notice Create a new prover. /// @dev The caller becomes the owner of the new prover. Only one prover can be created per /// owner. It is recommended to use a cold wallet to create a prover, and then /// immediately set a delegated signer to a hot wallet for the prover. /// @param stakerFeeBips The reward percentage in basis points (one-hundredth of a percent) that /// goes to the prover's stakers. This cannot be changed after the prover is created. /// @return The address of the new prover. function createProver(uint256 stakerFeeBips) external returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC20Metadata} from "./extensions/IERC20Metadata.sol"; import {Context} from "../../utils/Context.sol"; import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC-20 * applications. */ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { mapping(address account => uint256) private _balances; mapping(address account => mapping(address spender => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { 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) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (uint256) { 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) { 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}. * * Skips emitting an {Approval} event indicating an allowance update. This is not * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve]. * * 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 { 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: * * ```solidity * 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 { if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } _allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance < type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; import {Context} from "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys a `value` amount of tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 value) public virtual { _burn(_msgSender(), value); } /** * @dev Destroys a `value` amount of tokens from `account`, deducting from * the caller's allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `value`. */ function burnFrom(address account, uint256 value) public virtual { _spendAllowance(account, _msgSender(), value); _burn(account, value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC20Permit.sol) pragma solidity ^0.8.20; import {IERC20Permit} from "./IERC20Permit.sol"; import {ERC20} from "../ERC20.sol"; import {ECDSA} from "../../../utils/cryptography/ECDSA.sol"; import {EIP712} from "../../../utils/cryptography/EIP712.sol"; import {Nonces} from "../../../utils/Nonces.sol"; /** * @dev Implementation of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. * * Adds the {permit} method, which can be used to change an account's ERC-20 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. */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces { bytes32 private constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev Permit deadline has expired. */ error ERC2612ExpiredSignature(uint256 deadline); /** * @dev Mismatched signature. */ error ERC2612InvalidSigner(address signer, address owner); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC-20 token name. */ constructor(string memory name) EIP712(name, "1") {} /** * @inheritdoc IERC20Permit */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { if (block.timestamp > deadline) { revert ERC2612ExpiredSignature(deadline); } bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); if (signer != owner) { revert ERC2612InvalidSigner(signer, owner); } _approve(owner, spender, value); } /** * @inheritdoc IERC20Permit */ function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) { return super.nonces(owner); } /** * @inheritdoc IERC20Permit */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view virtual returns (bytes32) { return _domainSeparatorV4(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC20Votes.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; import {Votes} from "../../../governance/utils/Votes.sol"; import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; /** * @dev Extension of ERC-20 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 {Votes-delegate} function directly, or by providing a signature to be used with {Votes-delegateBySig}. Voting * power can be queried through the public accessors {Votes-getVotes} and {Votes-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 ERC20Votes is ERC20, Votes { /** * @dev Total supply cap has been exceeded, introducing a risk of votes overflowing. */ error ERC20ExceededSafeSupply(uint256 increasedSupply, uint256 cap); /** * @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 * {Votes-_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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC4626.sol) pragma solidity ^0.8.20; import {IERC20, IERC20Metadata, ERC20} from "../ERC20.sol"; import {SafeERC20} from "../utils/SafeERC20.sol"; import {IERC4626} from "../../../interfaces/IERC4626.sol"; import {Math} from "../../../utils/math/Math.sol"; /** * @dev Implementation of the ERC-4626 "Tokenized Vault Standard" as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. * * This extension allows the minting and burning of "shares" (represented using the ERC-20 inheritance) in exchange for * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends * the ERC-20 standard. Any additional extensions included along it would affect the "shares" token represented by this * contract and not the "assets" token which is an independent contract. * * [CAUTION] * ==== * In empty (or nearly empty) ERC-4626 vaults, deposits are at high risk of being stolen through frontrunning * with a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation * attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial * deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may * similarly be affected by slippage. Users can protect against this attack as well as unexpected slippage in general by * verifying the amount received is as expected, using a wrapper that performs these checks such as * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router]. * * Since v4.9, this implementation introduces configurable virtual assets and shares to help developers mitigate that risk. * The `_decimalsOffset()` corresponds to an offset in the decimal representation between the underlying asset's decimals * and the vault decimals. This offset also determines the rate of virtual shares to virtual assets in the vault, which * itself determines the initial exchange rate. While not fully preventing the attack, analysis shows that the default * offset (0) makes it non-profitable even if an attacker is able to capture value from multiple user deposits, as a result * of the value being captured by the virtual shares (out of the attacker's donation) matching the attacker's expected gains. * With a larger offset, the attack becomes orders of magnitude more expensive than it is profitable. More details about the * underlying math can be found xref:erc4626.adoc#inflation-attack[here]. * * The drawback of this approach is that the virtual shares do capture (a very small) part of the value being accrued * to the vault. Also, if the vault experiences losses, the users try to exit the vault, the virtual shares and assets * will cause the first user to exit to experience reduced losses in detriment to the last users that will experience * bigger losses. Developers willing to revert back to the pre-v4.9 behavior just need to override the * `_convertToShares` and `_convertToAssets` functions. * * To learn more, check out our xref:ROOT:erc4626.adoc[ERC-4626 guide]. * ==== */ abstract contract ERC4626 is ERC20, IERC4626 { using Math for uint256; IERC20 private immutable _asset; uint8 private immutable _underlyingDecimals; /** * @dev Attempted to deposit more assets than the max amount for `receiver`. */ error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max); /** * @dev Attempted to mint more shares than the max amount for `receiver`. */ error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max); /** * @dev Attempted to withdraw more assets than the max amount for `receiver`. */ error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max); /** * @dev Attempted to redeem more shares than the max amount for `receiver`. */ error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max); /** * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC-20 or ERC-777). */ constructor(IERC20 asset_) { (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_); _underlyingDecimals = success ? assetDecimals : 18; _asset = asset_; } /** * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way. */ function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool ok, uint8 assetDecimals) { (bool success, bytes memory encodedDecimals) = address(asset_).staticcall( abi.encodeCall(IERC20Metadata.decimals, ()) ); if (success && encodedDecimals.length >= 32) { uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256)); if (returnedDecimals <= type(uint8).max) { return (true, uint8(returnedDecimals)); } } return (false, 0); } /** * @dev Decimals are computed by adding the decimal offset on top of the underlying asset's decimals. This * "original" value is cached during construction of the vault contract. If this read operation fails (e.g., the * asset has not been created yet), a default of 18 is used to represent the underlying asset's decimals. * * See {IERC20Metadata-decimals}. */ function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) { return _underlyingDecimals + _decimalsOffset(); } /** @dev See {IERC4626-asset}. */ function asset() public view virtual returns (address) { return address(_asset); } /** @dev See {IERC4626-totalAssets}. */ function totalAssets() public view virtual returns (uint256) { return _asset.balanceOf(address(this)); } /** @dev See {IERC4626-convertToShares}. */ function convertToShares(uint256 assets) public view virtual returns (uint256) { return _convertToShares(assets, Math.Rounding.Floor); } /** @dev See {IERC4626-convertToAssets}. */ function convertToAssets(uint256 shares) public view virtual returns (uint256) { return _convertToAssets(shares, Math.Rounding.Floor); } /** @dev See {IERC4626-maxDeposit}. */ function maxDeposit(address) public view virtual returns (uint256) { return type(uint256).max; } /** @dev See {IERC4626-maxMint}. */ function maxMint(address) public view virtual returns (uint256) { return type(uint256).max; } /** @dev See {IERC4626-maxWithdraw}. */ function maxWithdraw(address owner) public view virtual returns (uint256) { return _convertToAssets(balanceOf(owner), Math.Rounding.Floor); } /** @dev See {IERC4626-maxRedeem}. */ function maxRedeem(address owner) public view virtual returns (uint256) { return balanceOf(owner); } /** @dev See {IERC4626-previewDeposit}. */ function previewDeposit(uint256 assets) public view virtual returns (uint256) { return _convertToShares(assets, Math.Rounding.Floor); } /** @dev See {IERC4626-previewMint}. */ function previewMint(uint256 shares) public view virtual returns (uint256) { return _convertToAssets(shares, Math.Rounding.Ceil); } /** @dev See {IERC4626-previewWithdraw}. */ function previewWithdraw(uint256 assets) public view virtual returns (uint256) { return _convertToShares(assets, Math.Rounding.Ceil); } /** @dev See {IERC4626-previewRedeem}. */ function previewRedeem(uint256 shares) public view virtual returns (uint256) { return _convertToAssets(shares, Math.Rounding.Floor); } /** @dev See {IERC4626-deposit}. */ function deposit(uint256 assets, address receiver) public virtual returns (uint256) { uint256 maxAssets = maxDeposit(receiver); if (assets > maxAssets) { revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets); } uint256 shares = previewDeposit(assets); _deposit(_msgSender(), receiver, assets, shares); return shares; } /** @dev See {IERC4626-mint}. */ function mint(uint256 shares, address receiver) public virtual returns (uint256) { uint256 maxShares = maxMint(receiver); if (shares > maxShares) { revert ERC4626ExceededMaxMint(receiver, shares, maxShares); } uint256 assets = previewMint(shares); _deposit(_msgSender(), receiver, assets, shares); return assets; } /** @dev See {IERC4626-withdraw}. */ function withdraw(uint256 assets, address receiver, address owner) public virtual returns (uint256) { uint256 maxAssets = maxWithdraw(owner); if (assets > maxAssets) { revert ERC4626ExceededMaxWithdraw(owner, assets, maxAssets); } uint256 shares = previewWithdraw(assets); _withdraw(_msgSender(), receiver, owner, assets, shares); return shares; } /** @dev See {IERC4626-redeem}. */ function redeem(uint256 shares, address receiver, address owner) public virtual returns (uint256) { uint256 maxShares = maxRedeem(owner); if (shares > maxShares) { revert ERC4626ExceededMaxRedeem(owner, shares, maxShares); } uint256 assets = previewRedeem(shares); _withdraw(_msgSender(), receiver, owner, assets, shares); return assets; } /** * @dev Internal conversion function (from assets to shares) with support for rounding direction. */ function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) { return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding); } /** * @dev Internal conversion function (from shares to assets) with support for rounding direction. */ function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256) { return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding); } /** * @dev Deposit/mint common workflow. */ function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual { // If _asset is ERC-777, `transferFrom` can trigger a reentrancy BEFORE the transfer happens through the // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer, // calls the vault, which is assumed not malicious. // // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the // assets are transferred and before the shares are minted, which is a valid state. // slither-disable-next-line reentrancy-no-eth SafeERC20.safeTransferFrom(_asset, caller, address(this), assets); _mint(receiver, shares); emit Deposit(caller, receiver, assets, shares); } /** * @dev Withdraw/redeem common workflow. */ function _withdraw( address caller, address receiver, address owner, uint256 assets, uint256 shares ) internal virtual { if (caller != owner) { _spendAllowance(owner, caller, shares); } // If _asset is ERC-777, `transfer` can trigger a reentrancy AFTER the transfer happens through the // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, // calls the vault, which is assumed not malicious. // // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the // shares are burned and after the assets are transferred, which is a valid state. _burn(owner, shares); SafeERC20.safeTransfer(_asset, receiver, assets); emit Withdraw(caller, receiver, owner, assets, shares); } function _decimalsOffset() internal view virtual returns (uint8) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol) pragma solidity ^0.8.20; /** * @dev Provides tracking nonces for addresses. Nonces will only increment. */ abstract contract Nonces { /** * @dev The nonce used for an `account` is not the expected current nonce. */ error InvalidAccountNonce(address account, uint256 currentNonce); mapping(address account => uint256) private _nonces; /** * @dev Returns the next unused nonce for an address. */ function nonces(address owner) public view virtual returns (uint256) { return _nonces[owner]; } /** * @dev Consumes a nonce. * * Returns the current value and increments nonce. */ function _useNonce(address owner) internal virtual returns (uint256) { // 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); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol) pragma solidity ^0.8.20; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overridden so it returns the address to which the fallback * function and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _fallback() internal virtual { _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.22; import {IBeacon} from "../beacon/IBeacon.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This library provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. */ library ERC1967Utils { /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit IERC1967.Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit IERC1967.AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the ERC-1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit IERC1967.BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {IProver} from "../interfaces/IProver.sol"; import {IGovernor} from "../../lib/openzeppelin-contracts/contracts/governance/IGovernor.sol"; import {ERC20} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import {IERC20} from "../../lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import {ERC20Votes} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol"; import {ERC4626} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol"; import {SafeERC20} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {Strings} from "../../lib/openzeppelin-contracts/contracts/utils/Strings.sol"; string constant NAME_PREFIX = "SuccinctProver-"; string constant SYMBOL_PREFIX = "PROVER-"; /// @title SuccinctProver /// @author Succinct Labs /// @notice The per-prover receipt token for delegating stake to a prover. /// @dev This contract accepts $iPROVE and mints $PROVER-N. It is non-transferable /// outside of staking operations. contract SuccinctProver is ERC4626, IProver { using SafeERC20 for IERC20; using Strings for uint256; /// @inheritdoc IProver address public immutable override staking; /// @inheritdoc IProver address public immutable override governor; /// @inheritdoc IProver address public immutable override prove; /// @inheritdoc IProver address public immutable override owner; /// @inheritdoc IProver uint256 public immutable override id; /// @inheritdoc IProver uint256 public immutable override stakerFeeBips; /// @dev Modifier to ensure that the caller is the prover owner. modifier onlyOwner() { if (msg.sender != owner) revert NotProverOwner(); _; } /// @dev Initializes this vault with $iPROVE as the underlying, with additional parameters. constructor( address _governor, address _prove, address _iProve, address _owner, uint256 _id, uint256 _stakerFeeBips ) ERC20(string.concat(NAME_PREFIX, _id.toString()), string.concat(SYMBOL_PREFIX, _id.toString())) ERC4626(IERC20(_iProve)) { if ( _governor == address(0) || _prove == address(0) || _iProve == address(0) || _owner == address(0) ) { revert ZeroAddress(); } staking = msg.sender; governor = _governor; prove = _prove; owner = _owner; id = _id; stakerFeeBips = _stakerFeeBips; // Self-delegate so that this prover can participate in governance. ERC20Votes(_iProve).delegate(address(this)); } /// @inheritdoc IProver function propose( address[] memory _targets, uint256[] memory _values, bytes[] memory _calldatas, string memory _description ) external override onlyOwner returns (uint256) { return IGovernor(governor).propose(_targets, _values, _calldatas, _description); } /// @inheritdoc IProver function cancel( address[] memory _targets, uint256[] memory _values, bytes[] memory _calldatas, bytes32 _descriptionHash ) external override onlyOwner returns (uint256) { return IGovernor(governor).cancel(_targets, _values, _calldatas, _descriptionHash); } /// @inheritdoc IProver function castVote(uint256 _proposalId, uint8 _support) external override onlyOwner returns (uint256) { return IGovernor(governor).castVote(_proposalId, _support); } /// @inheritdoc IProver function transferProveToStaking(address _from, uint256 _amount) external override { if (msg.sender != staking) { revert NotStaking(); } IERC20(prove).safeTransferFrom(_from, staking, _amount); } /// @dev Override to prevent transfers of $PROVER-N tokens except for stake/unstake. function _update(address _from, address _to, uint256 _value) internal override(ERC20) { if (msg.sender != staking) { revert NonTransferable(); } super._update(_from, _to, _value); } /// @dev Override to allow the staking contract to spend $PROVER-N. function _spendAllowance(address _owner, address _spender, uint256 _amount) internal override { if (_spender == staking) { return; } super._spendAllowance(_owner, _spender, _amount); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. * `CREATE2` can be used to compute in advance the address where a smart * contract will be deployed, which allows for interesting new mechanisms known * as 'counterfactual interactions'. * * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more * information. */ library Create2 { /** * @dev There's no code to deploy. */ error Create2EmptyBytecode(); /** * @dev Deploys a contract using `CREATE2`. The address where the contract * will be deployed can be known in advance via {computeAddress}. * * The bytecode for a contract can be obtained from Solidity with * `type(contractName).creationCode`. * * Requirements: * * - `bytecode` must not be empty. * - `salt` must have not been used for `bytecode` already. * - the factory must have a balance of at least `amount`. * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. */ function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } if (bytecode.length == 0) { revert Create2EmptyBytecode(); } assembly ("memory-safe") { addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) // if no address was created, and returndata is not empty, bubble revert if and(iszero(addr), not(iszero(returndatasize()))) { let p := mload(0x40) returndatacopy(p, 0, returndatasize()) revert(p, returndatasize()) } } if (addr == address(0)) { revert Errors.FailedDeployment(); } } /** * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the * `bytecodeHash` or `salt` will result in a new destination address. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { return computeAddress(salt, bytecodeHash, address(this)); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) { assembly ("memory-safe") { let ptr := mload(0x40) // Get free memory pointer // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | // |-------------------|---------------------------------------------------------------------------| // | bytecodeHash | CCCCCCCCCCCCC...CC | // | salt | BBBBBBBBBBBBB...BB | // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | // | 0xFF | FF | // |-------------------|---------------------------------------------------------------------------| // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | mstore(add(ptr, 0x40), bytecodeHash) mstore(add(ptr, 0x20), salt) mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff mstore8(start, 0xff) addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol"; import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC-20 * applications. */ 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}. * * Skips emitting an {Approval} event indicating an allowance update. This is not * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve]. * * 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: * * ```solidity * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { ERC20Storage storage $ = _getERC20Storage(); if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } $._allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance < type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (governance/Governor.sol) pragma solidity ^0.8.20; import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; import {EIP712} from "../utils/cryptography/EIP712.sol"; import {SignatureChecker} from "../utils/cryptography/SignatureChecker.sol"; import {IERC165, ERC165} from "../utils/introspection/ERC165.sol"; import {SafeCast} from "../utils/math/SafeCast.sol"; import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol"; import {Address} from "../utils/Address.sol"; import {Context} from "../utils/Context.sol"; import {Nonces} from "../utils/Nonces.sol"; import {Strings} from "../utils/Strings.sol"; import {IGovernor, IERC6372} from "./IGovernor.sol"; /** * @dev Core of the governance system, designed to be extended through various modules. * * This contract is abstract and requires several functions to be implemented in various modules: * * - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote} * - A voting module must implement {_getVotes} * - Additionally, {votingPeriod} must also be implemented */ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC721Receiver, IERC1155Receiver { using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,uint8 support,address voter,uint256 nonce)"); bytes32 public constant EXTENDED_BALLOT_TYPEHASH = keccak256( "ExtendedBallot(uint256 proposalId,uint8 support,address voter,uint256 nonce,string reason,bytes params)" ); struct ProposalCore { address proposer; uint48 voteStart; uint32 voteDuration; bool executed; bool canceled; uint48 etaSeconds; } bytes32 private constant ALL_PROPOSAL_STATES_BITMAP = bytes32((2 ** (uint8(type(ProposalState).max) + 1)) - 1); string private _name; mapping(uint256 proposalId => ProposalCore) private _proposals; // This queue keeps track of the governor operating on itself. Calls to functions protected by the {onlyGovernance} // modifier needs to be whitelisted in this queue. Whitelisting is set in {execute}, consumed by the // {onlyGovernance} modifier and eventually reset after {_executeOperations} completes. This ensures that the // execution of {onlyGovernance} protected calls can only be achieved through successful proposals. DoubleEndedQueue.Bytes32Deque private _governanceCall; /** * @dev Restricts a function so it can only be executed through governance proposals. For example, governance * parameter setters in {GovernorSettings} are protected using this modifier. * * The governance executing address may be different from the Governor's own address, for example it could be a * timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these * functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus, * for example, additional timelock proposers are not able to change governance parameters without going through the * governance protocol (since v4.6). */ modifier onlyGovernance() { _checkGovernance(); _; } /** * @dev Sets the value for {name} and {version} */ constructor(string memory name_) EIP712(name_, version()) { _name = name_; } /** * @dev Function to receive ETH that will be handled by the governor (disabled if executor is a third party contract) */ receive() external payable virtual { if (_executor() != address(this)) { revert GovernorDisabledDeposit(); } } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { return interfaceId == type(IGovernor).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IGovernor-name}. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev See {IGovernor-version}. */ function version() public view virtual returns (string memory) { return "1"; } /** * @dev See {IGovernor-hashProposal}. * * The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array * and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id * can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in * advance, before the proposal is submitted. * * Note that the chainId and the governor address are not part of the proposal id computation. Consequently, the * same proposal (with same operation and same description) will have the same id if submitted on multiple governors * across multiple networks. This also means that in order to execute the same operation twice (on the same * governor) the proposer will have to change the description in order to avoid proposal id conflicts. */ function hashProposal( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public pure virtual returns (uint256) { return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash))); } /** * @dev See {IGovernor-state}. */ function state(uint256 proposalId) public view virtual returns (ProposalState) { // We read the struct fields into the stack at once so Solidity emits a single SLOAD ProposalCore storage proposal = _proposals[proposalId]; bool proposalExecuted = proposal.executed; bool proposalCanceled = proposal.canceled; if (proposalExecuted) { return ProposalState.Executed; } if (proposalCanceled) { return ProposalState.Canceled; } uint256 snapshot = proposalSnapshot(proposalId); if (snapshot == 0) { revert GovernorNonexistentProposal(proposalId); } uint256 currentTimepoint = clock(); if (snapshot >= currentTimepoint) { return ProposalState.Pending; } uint256 deadline = proposalDeadline(proposalId); if (deadline >= currentTimepoint) { return ProposalState.Active; } else if (!_quorumReached(proposalId) || !_voteSucceeded(proposalId)) { return ProposalState.Defeated; } else if (proposalEta(proposalId) == 0) { return ProposalState.Succeeded; } else { return ProposalState.Queued; } } /** * @dev See {IGovernor-proposalThreshold}. */ function proposalThreshold() public view virtual returns (uint256) { return 0; } /** * @dev See {IGovernor-proposalSnapshot}. */ function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256) { return _proposals[proposalId].voteStart; } /** * @dev See {IGovernor-proposalDeadline}. */ function proposalDeadline(uint256 proposalId) public view virtual returns (uint256) { return _proposals[proposalId].voteStart + _proposals[proposalId].voteDuration; } /** * @dev See {IGovernor-proposalProposer}. */ function proposalProposer(uint256 proposalId) public view virtual returns (address) { return _proposals[proposalId].proposer; } /** * @dev See {IGovernor-proposalEta}. */ function proposalEta(uint256 proposalId) public view virtual returns (uint256) { return _proposals[proposalId].etaSeconds; } /** * @dev See {IGovernor-proposalNeedsQueuing}. */ function proposalNeedsQueuing(uint256) public view virtual returns (bool) { return false; } /** * @dev Reverts if the `msg.sender` is not the executor. In case the executor is not this contract * itself, the function reverts if `msg.data` is not whitelisted as a result of an {execute} * operation. See {onlyGovernance}. */ function _checkGovernance() internal virtual { if (_executor() != _msgSender()) { revert GovernorOnlyExecutor(_msgSender()); } if (_executor() != address(this)) { bytes32 msgDataHash = keccak256(_msgData()); // loop until popping the expected operation - throw if deque is empty (operation not authorized) while (_governanceCall.popFront() != msgDataHash) {} } } /** * @dev Amount of votes already cast passes the threshold limit. */ function _quorumReached(uint256 proposalId) internal view virtual returns (bool); /** * @dev Is the proposal successful or not. */ function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); /** * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`. */ function _getVotes(address account, uint256 timepoint, bytes memory params) internal view virtual returns (uint256); /** * @dev Register a vote for `proposalId` by `account` with a given `support`, voting `weight` and voting `params`. * * Note: Support is generic and can represent various things depending on the voting system used. */ function _countVote( uint256 proposalId, address account, uint8 support, uint256 totalWeight, bytes memory params ) internal virtual returns (uint256); /** * @dev Hook that should be called every time the tally for a proposal is updated. * * Note: This function must run successfully. Reverts will result in the bricking of governance */ function _tallyUpdated(uint256 proposalId) internal virtual {} /** * @dev Default additional encoded parameters used by castVote methods that don't include them * * Note: Should be overridden by specific implementations to use an appropriate value, the * meaning of the additional params, in the context of that implementation */ function _defaultParams() internal view virtual returns (bytes memory) { return ""; } /** * @dev See {IGovernor-propose}. This function has opt-in frontrunning protection, described in {_isValidDescriptionForProposer}. */ function propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description ) public virtual returns (uint256) { address proposer = _msgSender(); // check description restriction if (!_isValidDescriptionForProposer(proposer, description)) { revert GovernorRestrictedProposer(proposer); } // check proposal threshold uint256 votesThreshold = proposalThreshold(); if (votesThreshold > 0) { uint256 proposerVotes = getVotes(proposer, clock() - 1); if (proposerVotes < votesThreshold) { revert GovernorInsufficientProposerVotes(proposer, proposerVotes, votesThreshold); } } return _propose(targets, values, calldatas, description, proposer); } /** * @dev Internal propose mechanism. Can be overridden to add more logic on proposal creation. * * Emits a {IGovernor-ProposalCreated} event. */ function _propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description, address proposer ) internal virtual returns (uint256 proposalId) { proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description))); if (targets.length != values.length || targets.length != calldatas.length || targets.length == 0) { revert GovernorInvalidProposalLength(targets.length, calldatas.length, values.length); } if (_proposals[proposalId].voteStart != 0) { revert GovernorUnexpectedProposalState(proposalId, state(proposalId), bytes32(0)); } uint256 snapshot = clock() + votingDelay(); uint256 duration = votingPeriod(); ProposalCore storage proposal = _proposals[proposalId]; proposal.proposer = proposer; proposal.voteStart = SafeCast.toUint48(snapshot); proposal.voteDuration = SafeCast.toUint32(duration); emit ProposalCreated( proposalId, proposer, targets, values, new string[](targets.length), calldatas, snapshot, snapshot + duration, description ); // Using a named return variable to avoid stack too deep errors } /** * @dev See {IGovernor-queue}. */ function queue( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public virtual returns (uint256) { uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Succeeded)); uint48 etaSeconds = _queueOperations(proposalId, targets, values, calldatas, descriptionHash); if (etaSeconds != 0) { _proposals[proposalId].etaSeconds = etaSeconds; emit ProposalQueued(proposalId, etaSeconds); } else { revert GovernorQueueNotImplemented(); } return proposalId; } /** * @dev Internal queuing mechanism. Can be overridden (without a super call) to modify the way queuing is * performed (for example adding a vault/timelock). * * This is empty by default, and must be overridden to implement queuing. * * This function returns a timestamp that describes the expected ETA for execution. If the returned value is 0 * (which is the default value), the core will consider queueing did not succeed, and the public {queue} function * will revert. * * NOTE: Calling this function directly will NOT check the current state of the proposal, or emit the * `ProposalQueued` event. Queuing a proposal should be done using {queue}. */ function _queueOperations( uint256 /*proposalId*/, address[] memory /*targets*/, uint256[] memory /*values*/, bytes[] memory /*calldatas*/, bytes32 /*descriptionHash*/ ) internal virtual returns (uint48) { return 0; } /** * @dev See {IGovernor-execute}. */ function execute( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public payable virtual returns (uint256) { uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); _validateStateBitmap( proposalId, _encodeStateBitmap(ProposalState.Succeeded) | _encodeStateBitmap(ProposalState.Queued) ); // mark as executed before calls to avoid reentrancy _proposals[proposalId].executed = true; // before execute: register governance call in queue. if (_executor() != address(this)) { for (uint256 i = 0; i < targets.length; ++i) { if (targets[i] == address(this)) { _governanceCall.pushBack(keccak256(calldatas[i])); } } } _executeOperations(proposalId, targets, values, calldatas, descriptionHash); // after execute: cleanup governance call queue. if (_executor() != address(this) && !_governanceCall.empty()) { _governanceCall.clear(); } emit ProposalExecuted(proposalId); return proposalId; } /** * @dev Internal execution mechanism. Can be overridden (without a super call) to modify the way execution is * performed (for example adding a vault/timelock). * * NOTE: Calling this function directly will NOT check the current state of the proposal, set the executed flag to * true or emit the `ProposalExecuted` event. Executing a proposal should be done using {execute} or {_execute}. */ function _executeOperations( uint256 /* proposalId */, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 /*descriptionHash*/ ) internal virtual { for (uint256 i = 0; i < targets.length; ++i) { (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); Address.verifyCallResult(success, returndata); } } /** * @dev See {IGovernor-cancel}. */ function cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public virtual returns (uint256) { // The proposalId will be recomputed in the `_cancel` call further down. However we need the value before we // do the internal call, because we need to check the proposal state BEFORE the internal `_cancel` call // changes it. The `hashProposal` duplication has a cost that is limited, and that we accept. uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); // public cancel restrictions (on top of existing _cancel restrictions). _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Pending)); if (_msgSender() != proposalProposer(proposalId)) { revert GovernorOnlyProposer(_msgSender()); } return _cancel(targets, values, calldatas, descriptionHash); } /** * @dev Internal cancel mechanism with minimal restrictions. A proposal can be cancelled in any state other than * Canceled, Expired, or Executed. Once cancelled a proposal can't be re-submitted. * * Emits a {IGovernor-ProposalCanceled} event. */ function _cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal virtual returns (uint256) { uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); _validateStateBitmap( proposalId, ALL_PROPOSAL_STATES_BITMAP ^ _encodeStateBitmap(ProposalState.Canceled) ^ _encodeStateBitmap(ProposalState.Expired) ^ _encodeStateBitmap(ProposalState.Executed) ); _proposals[proposalId].canceled = true; emit ProposalCanceled(proposalId); return proposalId; } /** * @dev See {IGovernor-getVotes}. */ function getVotes(address account, uint256 timepoint) public view virtual returns (uint256) { return _getVotes(account, timepoint, _defaultParams()); } /** * @dev See {IGovernor-getVotesWithParams}. */ function getVotesWithParams( address account, uint256 timepoint, bytes memory params ) public view virtual returns (uint256) { return _getVotes(account, timepoint, params); } /** * @dev See {IGovernor-castVote}. */ function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256) { address voter = _msgSender(); return _castVote(proposalId, voter, support, ""); } /** * @dev See {IGovernor-castVoteWithReason}. */ function castVoteWithReason( uint256 proposalId, uint8 support, string calldata reason ) public virtual returns (uint256) { address voter = _msgSender(); return _castVote(proposalId, voter, support, reason); } /** * @dev See {IGovernor-castVoteWithReasonAndParams}. */ function castVoteWithReasonAndParams( uint256 proposalId, uint8 support, string calldata reason, bytes memory params ) public virtual returns (uint256) { address voter = _msgSender(); return _castVote(proposalId, voter, support, reason, params); } /** * @dev See {IGovernor-castVoteBySig}. */ function castVoteBySig( uint256 proposalId, uint8 support, address voter, bytes memory signature ) public virtual returns (uint256) { bool valid = SignatureChecker.isValidSignatureNow( voter, _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter)))), signature ); if (!valid) { revert GovernorInvalidSignature(voter); } return _castVote(proposalId, voter, support, ""); } /** * @dev See {IGovernor-castVoteWithReasonAndParamsBySig}. */ function castVoteWithReasonAndParamsBySig( uint256 proposalId, uint8 support, address voter, string calldata reason, bytes memory params, bytes memory signature ) public virtual returns (uint256) { bool valid = SignatureChecker.isValidSignatureNow( voter, _hashTypedDataV4( keccak256( abi.encode( EXTENDED_BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter), keccak256(bytes(reason)), keccak256(params) ) ) ), signature ); if (!valid) { revert GovernorInvalidSignature(voter); } return _castVote(proposalId, voter, support, reason, params); } /** * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams(). * * Emits a {IGovernor-VoteCast} event. */ function _castVote( uint256 proposalId, address account, uint8 support, string memory reason ) internal virtual returns (uint256) { return _castVote(proposalId, account, support, reason, _defaultParams()); } /** * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. * * Emits a {IGovernor-VoteCast} event. */ function _castVote( uint256 proposalId, address account, uint8 support, string memory reason, bytes memory params ) internal virtual returns (uint256) { _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Active)); uint256 totalWeight = _getVotes(account, proposalSnapshot(proposalId), params); uint256 votedWeight = _countVote(proposalId, account, support, totalWeight, params); if (params.length == 0) { emit VoteCast(account, proposalId, support, votedWeight, reason); } else { emit VoteCastWithParams(account, proposalId, support, votedWeight, reason, params); } _tallyUpdated(proposalId); return votedWeight; } /** * @dev Relays a transaction or function call to an arbitrary target. In cases where the governance executor * is some contract other than the governor itself, like when using a timelock, this function can be invoked * in a governance proposal to recover tokens or Ether that was sent to the governor contract by mistake. * Note that if the executor is simply the governor itself, use of `relay` is redundant. */ function relay(address target, uint256 value, bytes calldata data) external payable virtual onlyGovernance { (bool success, bytes memory returndata) = target.call{value: value}(data); Address.verifyCallResult(success, returndata); } /** * @dev Address through which the governor executes action. Will be overloaded by module that execute actions * through another contract such as a timelock. */ function _executor() internal view virtual returns (address) { return address(this); } /** * @dev See {IERC721Receiver-onERC721Received}. * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). */ function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { if (_executor() != address(this)) { revert GovernorDisabledDeposit(); } return this.onERC721Received.selector; } /** * @dev See {IERC1155Receiver-onERC1155Received}. * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). */ function onERC1155Received(address, address, uint256, uint256, bytes memory) public virtual returns (bytes4) { if (_executor() != address(this)) { revert GovernorDisabledDeposit(); } return this.onERC1155Received.selector; } /** * @dev See {IERC1155Receiver-onERC1155BatchReceived}. * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). */ function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual returns (bytes4) { if (_executor() != address(this)) { revert GovernorDisabledDeposit(); } return this.onERC1155BatchReceived.selector; } /** * @dev Encodes a `ProposalState` into a `bytes32` representation where each bit enabled corresponds to * the underlying position in the `ProposalState` enum. For example: * * 0x000...10000 * ^^^^^^------ ... * ^----- Succeeded * ^---- Defeated * ^--- Canceled * ^-- Active * ^- Pending */ function _encodeStateBitmap(ProposalState proposalState) internal pure returns (bytes32) { return bytes32(1 << uint8(proposalState)); } /** * @dev Check that the current state of a proposal matches the requirements described by the `allowedStates` bitmap. * This bitmap should be built using `_encodeStateBitmap`. * * If requirements are not met, reverts with a {GovernorUnexpectedProposalState} error. */ function _validateStateBitmap(uint256 proposalId, bytes32 allowedStates) internal view returns (ProposalState) { ProposalState currentState = state(proposalId); if (_encodeStateBitmap(currentState) & allowedStates == bytes32(0)) { revert GovernorUnexpectedProposalState(proposalId, currentState, allowedStates); } return currentState; } /* * @dev Check if the proposer is authorized to submit a proposal with the given description. * * If the proposal description ends with `#proposer=0x???`, where `0x???` is an address written as a hex string * (case insensitive), then the submission of this proposal will only be authorized to said address. * * This is used for frontrunning protection. By adding this pattern at the end of their proposal, one can ensure * that no other address can submit the same proposal. An attacker would have to either remove or change that part, * which would result in a different proposal id. * * If the description does not match this pattern, it is unrestricted and anyone can submit it. This includes: * - If the `0x???` part is not a valid hex string. * - If the `0x???` part is a valid hex string, but does not contain exactly 40 hex digits. * - If it ends with the expected suffix followed by newlines or other whitespace. * - If it ends with some other similar suffix, e.g. `#other=abc`. * - If it does not end with any such suffix. */ function _isValidDescriptionForProposer( address proposer, string memory description ) internal view virtual returns (bool) { unchecked { uint256 length = bytes(description).length; // Length is too short to contain a valid proposer suffix if (length < 52) { return true; } // Extract what would be the `#proposer=` marker beginning the suffix bytes10 marker = bytes10(_unsafeReadBytesOffset(bytes(description), length - 52)); // If the marker is not found, there is no proposer suffix to check if (marker != bytes10("#proposer=")) { return true; } // Check that the last 42 characters (after the marker) are a properly formatted address. (bool success, address recovered) = Strings.tryParseAddress(description, length - 42, length); return !success || recovered == proposer; } } /** * @inheritdoc IERC6372 */ function clock() public view virtual returns (uint48); /** * @inheritdoc IERC6372 */ // solhint-disable-next-line func-name-mixedcase function CLOCK_MODE() public view virtual returns (string memory); /** * @inheritdoc IGovernor */ function votingDelay() public view virtual returns (uint256); /** * @inheritdoc IGovernor */ function votingPeriod() public view virtual returns (uint256); /** * @inheritdoc IGovernor */ function quorum(uint256 timepoint) public view virtual returns (uint256); /** * @dev Reads a bytes32 from a bytes array without bounds checking. * * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the * assembly block as such would prevent some optimizations. */ function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { // This is not memory safe in the general case, but all calls to this private function are within bounds. assembly ("memory-safe") { value := mload(add(buffer, add(0x20, offset))) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (governance/extensions/GovernorCountingSimple.sol) pragma solidity ^0.8.20; import {Governor} from "../Governor.sol"; /** * @dev Extension of {Governor} for simple, 3 options, vote counting. */ abstract contract GovernorCountingSimple is Governor { /** * @dev Supported vote types. Matches Governor Bravo ordering. */ enum VoteType { Against, For, Abstain } struct ProposalVote { uint256 againstVotes; uint256 forVotes; uint256 abstainVotes; mapping(address voter => bool) hasVoted; } mapping(uint256 proposalId => ProposalVote) private _proposalVotes; /** * @dev See {IGovernor-COUNTING_MODE}. */ // solhint-disable-next-line func-name-mixedcase function COUNTING_MODE() public pure virtual override returns (string memory) { return "support=bravo&quorum=for,abstain"; } /** * @dev See {IGovernor-hasVoted}. */ function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { return _proposalVotes[proposalId].hasVoted[account]; } /** * @dev Accessor to the internal vote counts. */ function proposalVotes( uint256 proposalId ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) { ProposalVote storage proposalVote = _proposalVotes[proposalId]; return (proposalVote.againstVotes, proposalVote.forVotes, proposalVote.abstainVotes); } /** * @dev See {Governor-_quorumReached}. */ function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { ProposalVote storage proposalVote = _proposalVotes[proposalId]; return quorum(proposalSnapshot(proposalId)) <= proposalVote.forVotes + proposalVote.abstainVotes; } /** * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes. */ function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) { ProposalVote storage proposalVote = _proposalVotes[proposalId]; return proposalVote.forVotes > proposalVote.againstVotes; } /** * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo). */ function _countVote( uint256 proposalId, address account, uint8 support, uint256 totalWeight, bytes memory // params ) internal virtual override returns (uint256) { ProposalVote storage proposalVote = _proposalVotes[proposalId]; if (proposalVote.hasVoted[account]) { revert GovernorAlreadyCastVote(account); } proposalVote.hasVoted[account] = true; if (support == uint8(VoteType.Against)) { proposalVote.againstVotes += totalWeight; } else if (support == uint8(VoteType.For)) { proposalVote.forVotes += totalWeight; } else if (support == uint8(VoteType.Abstain)) { proposalVote.abstainVotes += totalWeight; } else { revert GovernorInvalidVoteType(); } return totalWeight; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorSettings.sol) pragma solidity ^0.8.20; import {Governor} from "../Governor.sol"; /** * @dev Extension of {Governor} for settings updatable through governance. */ abstract contract GovernorSettings is Governor { // amount of token uint256 private _proposalThreshold; // timepoint: limited to uint48 in core (same as clock() type) uint48 private _votingDelay; // duration: limited to uint32 in core uint32 private _votingPeriod; event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay); event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod); event ProposalThresholdSet(uint256 oldProposalThreshold, uint256 newProposalThreshold); /** * @dev Initialize the governance parameters. */ constructor(uint48 initialVotingDelay, uint32 initialVotingPeriod, uint256 initialProposalThreshold) { _setVotingDelay(initialVotingDelay); _setVotingPeriod(initialVotingPeriod); _setProposalThreshold(initialProposalThreshold); } /** * @dev See {IGovernor-votingDelay}. */ function votingDelay() public view virtual override returns (uint256) { return _votingDelay; } /** * @dev See {IGovernor-votingPeriod}. */ function votingPeriod() public view virtual override returns (uint256) { return _votingPeriod; } /** * @dev See {Governor-proposalThreshold}. */ function proposalThreshold() public view virtual override returns (uint256) { return _proposalThreshold; } /** * @dev Update the voting delay. This operation can only be performed through a governance proposal. * * Emits a {VotingDelaySet} event. */ function setVotingDelay(uint48 newVotingDelay) public virtual onlyGovernance { _setVotingDelay(newVotingDelay); } /** * @dev Update the voting period. This operation can only be performed through a governance proposal. * * Emits a {VotingPeriodSet} event. */ function setVotingPeriod(uint32 newVotingPeriod) public virtual onlyGovernance { _setVotingPeriod(newVotingPeriod); } /** * @dev Update the proposal threshold. This operation can only be performed through a governance proposal. * * Emits a {ProposalThresholdSet} event. */ function setProposalThreshold(uint256 newProposalThreshold) public virtual onlyGovernance { _setProposalThreshold(newProposalThreshold); } /** * @dev Internal setter for the voting delay. * * Emits a {VotingDelaySet} event. */ function _setVotingDelay(uint48 newVotingDelay) internal virtual { emit VotingDelaySet(_votingDelay, newVotingDelay); _votingDelay = newVotingDelay; } /** * @dev Internal setter for the voting period. * * Emits a {VotingPeriodSet} event. */ function _setVotingPeriod(uint32 newVotingPeriod) internal virtual { if (newVotingPeriod == 0) { revert GovernorInvalidVotingPeriod(0); } emit VotingPeriodSet(_votingPeriod, newVotingPeriod); _votingPeriod = newVotingPeriod; } /** * @dev Internal setter for the proposal threshold. * * Emits a {ProposalThresholdSet} event. */ function _setProposalThreshold(uint256 newProposalThreshold) internal virtual { emit ProposalThresholdSet(_proposalThreshold, newProposalThreshold); _proposalThreshold = newProposalThreshold; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (governance/extensions/GovernorVotes.sol) pragma solidity ^0.8.20; import {Governor} from "../Governor.sol"; import {IVotes} from "../utils/IVotes.sol"; import {IERC5805} from "../../interfaces/IERC5805.sol"; import {SafeCast} from "../../utils/math/SafeCast.sol"; import {Time} from "../../utils/types/Time.sol"; /** * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} * token. */ abstract contract GovernorVotes is Governor { IERC5805 private immutable _token; constructor(IVotes tokenAddress) { _token = IERC5805(address(tokenAddress)); } /** * @dev The token that voting power is sourced from. */ function token() public view virtual returns (IERC5805) { return _token; } /** * @dev Clock (as specified in ERC-6372) is set to match the token's clock. Fallback to block numbers if the token * does not implement ERC-6372. */ function clock() public view virtual override returns (uint48) { try token().clock() returns (uint48 timepoint) { return timepoint; } catch { return Time.blockNumber(); } } /** * @dev Machine-readable description of the clock as specified in ERC-6372. */ // solhint-disable-next-line func-name-mixedcase function CLOCK_MODE() public view virtual override returns (string memory) { try token().CLOCK_MODE() returns (string memory clockmode) { return clockmode; } catch { return "mode=blocknumber&from=default"; } } /** * Read the voting weight from the token's built in snapshot mechanism (see {Governor-_getVotes}). */ function _getVotes( address account, uint256 timepoint, bytes memory /*params*/ ) internal view virtual override returns (uint256) { return token().getPastVotes(account, timepoint); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorVotesQuorumFraction.sol) pragma solidity ^0.8.20; import {GovernorVotes} from "./GovernorVotes.sol"; import {SafeCast} from "../../utils/math/SafeCast.sol"; import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; /** * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a * fraction of the total supply. */ abstract contract GovernorVotesQuorumFraction is GovernorVotes { using Checkpoints for Checkpoints.Trace208; Checkpoints.Trace208 private _quorumNumeratorHistory; event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator); /** * @dev The quorum set is not a valid fraction. */ error GovernorInvalidQuorumFraction(uint256 quorumNumerator, uint256 quorumDenominator); /** * @dev Initialize quorum as a fraction of the token's total supply. * * The fraction is specified as `numerator / denominator`. By default the denominator is 100, so quorum is * specified as a percent: a numerator of 10 corresponds to quorum being 10% of total supply. The denominator can be * customized by overriding {quorumDenominator}. */ constructor(uint256 quorumNumeratorValue) { _updateQuorumNumerator(quorumNumeratorValue); } /** * @dev Returns the current quorum numerator. See {quorumDenominator}. */ function quorumNumerator() public view virtual returns (uint256) { return _quorumNumeratorHistory.latest(); } /** * @dev Returns the quorum numerator at a specific timepoint. See {quorumDenominator}. */ function quorumNumerator(uint256 timepoint) public view virtual returns (uint256) { uint256 length = _quorumNumeratorHistory._checkpoints.length; // Optimistic search, check the latest checkpoint Checkpoints.Checkpoint208 storage latest = _quorumNumeratorHistory._checkpoints[length - 1]; uint48 latestKey = latest._key; uint208 latestValue = latest._value; if (latestKey <= timepoint) { return latestValue; } // Otherwise, do the binary search return _quorumNumeratorHistory.upperLookupRecent(SafeCast.toUint48(timepoint)); } /** * @dev Returns the quorum denominator. Defaults to 100, but may be overridden. */ function quorumDenominator() public view virtual returns (uint256) { return 100; } /** * @dev Returns the quorum for a timepoint, in terms of number of votes: `supply * numerator / denominator`. */ function quorum(uint256 timepoint) public view virtual override returns (uint256) { return (token().getPastTotalSupply(timepoint) * quorumNumerator(timepoint)) / quorumDenominator(); } /** * @dev Changes the quorum numerator. * * Emits a {QuorumNumeratorUpdated} event. * * Requirements: * * - Must be called through a governance proposal. * - New numerator must be smaller or equal to the denominator. */ function updateQuorumNumerator(uint256 newQuorumNumerator) external virtual onlyGovernance { _updateQuorumNumerator(newQuorumNumerator); } /** * @dev Changes the quorum numerator. * * Emits a {QuorumNumeratorUpdated} event. * * Requirements: * * - New numerator must be smaller or equal to the denominator. */ function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual { uint256 denominator = quorumDenominator(); if (newQuorumNumerator > denominator) { revert GovernorInvalidQuorumFraction(newQuorumNumerator, denominator); } uint256 oldQuorumNumerator = quorumNumerator(); _quorumNumeratorHistory.push(clock(), SafeCast.toUint208(newQuorumNumerator)); emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol) pragma solidity ^0.8.20; /** * @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; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC-20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol) pragma solidity ^0.8.20; /** * @dev Helper library for emitting standardized panic codes. * * ```solidity * contract Example { * using Panic for uint256; * * // Use any of the declared internal constants * function foo() { Panic.GENERIC.panic(); } * * // Alternatively * function foo() { Panic.panic(Panic.GENERIC); } * } * ``` * * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. * * _Available since v5.1._ */ // slither-disable-next-line unused-state library Panic { /// @dev generic / unspecified error uint256 internal constant GENERIC = 0x00; /// @dev used by the assert() builtin uint256 internal constant ASSERT = 0x01; /// @dev arithmetic underflow or overflow uint256 internal constant UNDER_OVERFLOW = 0x11; /// @dev division or modulo by zero uint256 internal constant DIVISION_BY_ZERO = 0x12; /// @dev enum conversion error uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; /// @dev invalid encoding in storage uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; /// @dev empty array pop uint256 internal constant EMPTY_ARRAY_POP = 0x31; /// @dev array out of bounds access uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; /// @dev resource error (too large allocation or too large array) uint256 internal constant RESOURCE_ERROR = 0x41; /// @dev calling invalid internal function uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; /// @dev Reverts with a panic code. Recommended to use with /// the internal constants with predefined codes. function panic(uint256 code) internal pure { assembly ("memory-safe") { mstore(0x00, 0x4e487b71) mstore(0x20, code) revert(0x1c, 0x24) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { assembly ("memory-safe") { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC-20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC-721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC-1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @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 recovered, RecoverError err, bytes32 errArg) { 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. assembly ("memory-safe") { 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[ERC-2098 short signatures] */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { 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 recovered, RecoverError err, bytes32 errArg) { // 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); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.20; import {MessageHashUtils} from "./MessageHashUtils.sol"; import {ShortStrings, ShortString} from "../ShortStrings.sol"; import {IERC5267} from "../../interfaces/IERC5267.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. * * @custom:oz-upgrades-unsafe-allow state-variable-immutable */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @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]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, 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 ) { return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: By default this function reads _name which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Name() internal view returns (string memory) { return _name.toStringWithFallback(_nameFallback); } /** * @dev The version parameter for the EIP712 domain. * * NOTE: By default this function reads _version which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Version() internal view returns (string memory) { return _version.toStringWithFallback(_versionFallback); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (governance/utils/Votes.sol) pragma solidity ^0.8.20; import {IERC5805} from "../../interfaces/IERC5805.sol"; import {Context} from "../../utils/Context.sol"; import {Nonces} from "../../utils/Nonces.sol"; import {EIP712} from "../../utils/cryptography/EIP712.sol"; import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; import {SafeCast} from "../../utils/math/SafeCast.sol"; import {ECDSA} from "../../utils/cryptography/ECDSA.sol"; import {Time} from "../../utils/types/Time.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 Votes is Context, EIP712, Nonces, IERC5805 { using Checkpoints for Checkpoints.Trace208; bytes32 private constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); mapping(address account => address) private _delegatee; mapping(address delegatee => Checkpoints.Trace208) private _delegateCheckpoints; Checkpoints.Trace208 private _totalCheckpoints; /** * @dev The clock was incorrectly modified. */ error ERC6372InconsistentClock(); /** * @dev Lookup to future votes is not available. */ error ERC5805FutureLookup(uint256 timepoint, uint48 clock); /** * @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 ERC-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 Validate that a timepoint is in the past, and return it as a uint48. */ function _validateTimepoint(uint256 timepoint) internal view returns (uint48) { uint48 currentTimepoint = clock(); if (timepoint >= currentTimepoint) revert ERC5805FutureLookup(timepoint, currentTimepoint); return SafeCast.toUint48(timepoint); } /** * @dev Returns the current amount of votes that `account` has. */ function getVotes(address account) public view virtual returns (uint256) { 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) { return _delegateCheckpoints[account].upperLookupRecent(_validateTimepoint(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) { return _totalCheckpoints.upperLookupRecent(_validateTimepoint(timepoint)); } /** * @dev Returns the current total supply of votes. */ function _getTotalSupply() internal view virtual returns (uint256) { return _totalCheckpoints.latest(); } /** * @dev Returns the delegate that `account` has chosen. */ function delegates(address account) public view virtual returns (address) { 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 { 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 { 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) internal virtual { 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) { 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) { return _delegateCheckpoints[account].at(pos); } function _push( Checkpoints.Trace208 storage store, function(uint208, uint208) view returns (uint208) op, uint208 delta ) private returns (uint208 oldValue, uint208 newValue) { 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/Checkpoints.sol) // This file was procedurally generated from scripts/generate/templates/Checkpoints.js. pragma solidity ^0.8.20; import {Math} from "../math/Math.sol"; /** * @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 oldValue, uint224 newValue) { 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 storage 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 oldValue, uint224 newValue) { uint256 pos = self.length; if (pos > 0) { Checkpoint224 storage last = _unsafeAccess(self, pos - 1); uint32 lastKey = last._key; uint224 lastValue = last._value; // Checkpoint keys must be non-decreasing. if (lastKey > key) { revert CheckpointUnorderedInsertion(); } // Update or push new checkpoint if (lastKey == key) { last._value = value; } else { self.push(Checkpoint224({_key: key, _value: value})); } return (lastValue, value); } else { self.push(Checkpoint224({_key: key, _value: value})); return (0, value); } } /** * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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 oldValue, uint208 newValue) { 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 storage 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 oldValue, uint208 newValue) { uint256 pos = self.length; if (pos > 0) { Checkpoint208 storage last = _unsafeAccess(self, pos - 1); uint48 lastKey = last._key; uint208 lastValue = last._value; // Checkpoint keys must be non-decreasing. if (lastKey > key) { revert CheckpointUnorderedInsertion(); } // Update or push new checkpoint if (lastKey == key) { last._value = value; } else { self.push(Checkpoint208({_key: key, _value: value})); } return (lastValue, value); } else { self.push(Checkpoint208({_key: key, _value: value})); return (0, value); } } /** * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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 oldValue, uint160 newValue) { 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 storage 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 oldValue, uint160 newValue) { uint256 pos = self.length; if (pos > 0) { Checkpoint160 storage last = _unsafeAccess(self, pos - 1); uint96 lastKey = last._key; uint160 lastValue = last._value; // Checkpoint keys must be non-decreasing. if (lastKey > key) { revert CheckpointUnorderedInsertion(); } // Update or push new checkpoint if (lastKey == key) { last._value = value; } else { self.push(Checkpoint160({_key: key, _value: value})); } return (lastValue, value); } else { self.push(Checkpoint160({_key: key, _value: value})); return (0, value); } } /** * @dev Return the index of the first (oldest) checkpoint with key strictly bigger 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 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) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @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 Errors.InsufficientBalance(address(this).balance, amount); } (bool success, bytes memory returndata) = recipient.call{value: amount}(""); if (!success) { _revert(returndata); } } /** * @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 * {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value); } (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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}. */ 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 assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (governance/IGovernor.sol) pragma solidity ^0.8.20; import {IERC165} from "../interfaces/IERC165.sol"; import {IERC6372} from "../interfaces/IERC6372.sol"; /** * @dev Interface of the {Governor} core. * * NOTE: Event parameters lack the `indexed` keyword for compatibility with GovernorBravo events. * Making event parameters `indexed` affects how events are decoded, potentially breaking existing indexers. */ interface IGovernor is IERC165, IERC6372 { enum ProposalState { Pending, Active, Canceled, Defeated, Succeeded, Queued, Expired, Executed } /** * @dev Empty proposal or a mismatch between the parameters length for a proposal call. */ error GovernorInvalidProposalLength(uint256 targets, uint256 calldatas, uint256 values); /** * @dev The vote was already cast. */ error GovernorAlreadyCastVote(address voter); /** * @dev Token deposits are disabled in this contract. */ error GovernorDisabledDeposit(); /** * @dev The `account` is not a proposer. */ error GovernorOnlyProposer(address account); /** * @dev The `account` is not the governance executor. */ error GovernorOnlyExecutor(address account); /** * @dev The `proposalId` doesn't exist. */ error GovernorNonexistentProposal(uint256 proposalId); /** * @dev The current state of a proposal is not the required for performing an operation. * The `expectedStates` is a bitmap with the bits enabled for each ProposalState enum position * counting from right to left. * * NOTE: If `expectedState` is `bytes32(0)`, the proposal is expected to not be in any state (i.e. not exist). * This is the case when a proposal that is expected to be unset is already initiated (the proposal is duplicated). * * See {Governor-_encodeStateBitmap}. */ error GovernorUnexpectedProposalState(uint256 proposalId, ProposalState current, bytes32 expectedStates); /** * @dev The voting period set is not a valid period. */ error GovernorInvalidVotingPeriod(uint256 votingPeriod); /** * @dev The `proposer` does not have the required votes to create a proposal. */ error GovernorInsufficientProposerVotes(address proposer, uint256 votes, uint256 threshold); /** * @dev The `proposer` is not allowed to create a proposal. */ error GovernorRestrictedProposer(address proposer); /** * @dev The vote type used is not valid for the corresponding counting module. */ error GovernorInvalidVoteType(); /** * @dev The provided params buffer is not supported by the counting module. */ error GovernorInvalidVoteParams(); /** * @dev Queue operation is not implemented for this governor. Execute should be called directly. */ error GovernorQueueNotImplemented(); /** * @dev The proposal hasn't been queued yet. */ error GovernorNotQueuedProposal(uint256 proposalId); /** * @dev The proposal has already been queued. */ error GovernorAlreadyQueuedProposal(uint256 proposalId); /** * @dev The provided signature is not valid for the expected `voter`. * If the `voter` is a contract, the signature is not valid using {IERC1271-isValidSignature}. */ error GovernorInvalidSignature(address voter); /** * @dev Emitted when a proposal is created. */ event ProposalCreated( uint256 proposalId, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 voteStart, uint256 voteEnd, string description ); /** * @dev Emitted when a proposal is queued. */ event ProposalQueued(uint256 proposalId, uint256 etaSeconds); /** * @dev Emitted when a proposal is executed. */ event ProposalExecuted(uint256 proposalId); /** * @dev Emitted when a proposal is canceled. */ event ProposalCanceled(uint256 proposalId); /** * @dev Emitted when a vote is cast without params. * * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. */ event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason); /** * @dev Emitted when a vote is cast with params. * * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. * `params` are additional encoded parameters. Their interpretation also depends on the voting module used. */ event VoteCastWithParams( address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason, bytes params ); /** * @notice module:core * @dev Name of the governor instance (used in building the EIP-712 domain separator). */ function name() external view returns (string memory); /** * @notice module:core * @dev Version of the governor instance (used in building the EIP-712 domain separator). Default: "1" */ function version() external view returns (string memory); /** * @notice module:voting * @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to * be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of * key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`. * * There are 2 standard keys: `support` and `quorum`. * * - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`. * - `quorum=bravo` means that only For votes are counted towards quorum. * - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum. * * If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique * name that describes the behavior. For example: * * - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain. * - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote. * * NOTE: The string can be decoded by the standard * https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`] * JavaScript class. */ // solhint-disable-next-line func-name-mixedcase function COUNTING_MODE() external view returns (string memory); /** * @notice module:core * @dev Hashing function used to (re)build the proposal id from the proposal details.. */ function hashProposal( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external pure returns (uint256); /** * @notice module:core * @dev Current state of a proposal, following Compound's convention */ function state(uint256 proposalId) external view returns (ProposalState); /** * @notice module:core * @dev The number of votes required in order for a voter to become a proposer. */ function proposalThreshold() external view returns (uint256); /** * @notice module:core * @dev Timepoint used to retrieve user's votes and quorum. If using block number (as per Compound's Comp), the * snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the * following block. */ function proposalSnapshot(uint256 proposalId) external view returns (uint256); /** * @notice module:core * @dev Timepoint at which votes close. If using block number, votes close at the end of this block, so it is * possible to cast a vote during this block. */ function proposalDeadline(uint256 proposalId) external view returns (uint256); /** * @notice module:core * @dev The account that created a proposal. */ function proposalProposer(uint256 proposalId) external view returns (address); /** * @notice module:core * @dev The time when a queued proposal becomes executable ("ETA"). Unlike {proposalSnapshot} and * {proposalDeadline}, this doesn't use the governor clock, and instead relies on the executor's clock which may be * different. In most cases this will be a timestamp. */ function proposalEta(uint256 proposalId) external view returns (uint256); /** * @notice module:core * @dev Whether a proposal needs to be queued before execution. */ function proposalNeedsQueuing(uint256 proposalId) external view returns (bool); /** * @notice module:user-config * @dev Delay, between the proposal is created and the vote starts. The unit this duration is expressed in depends * on the clock (see ERC-6372) this contract uses. * * This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a * proposal starts. * * NOTE: While this interface returns a uint256, timepoints are stored as uint48 following the ERC-6372 clock type. * Consequently this value must fit in a uint48 (when added to the current clock). See {IERC6372-clock}. */ function votingDelay() external view returns (uint256); /** * @notice module:user-config * @dev Delay between the vote start and vote end. The unit this duration is expressed in depends on the clock * (see ERC-6372) this contract uses. * * NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting * duration compared to the voting delay. * * NOTE: This value is stored when the proposal is submitted so that possible changes to the value do not affect * proposals that have already been submitted. The type used to save it is a uint32. Consequently, while this * interface returns a uint256, the value it returns should fit in a uint32. */ function votingPeriod() external view returns (uint256); /** * @notice module:user-config * @dev Minimum number of cast voted required for a proposal to be successful. * * NOTE: The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows to scale the * quorum depending on values such as the totalSupply of a token at this timepoint (see {ERC20Votes}). */ function quorum(uint256 timepoint) external view returns (uint256); /** * @notice module:reputation * @dev Voting power of an `account` at a specific `timepoint`. * * Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or * multiple), {ERC20Votes} tokens. */ function getVotes(address account, uint256 timepoint) external view returns (uint256); /** * @notice module:reputation * @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters. */ function getVotesWithParams( address account, uint256 timepoint, bytes memory params ) external view returns (uint256); /** * @notice module:voting * @dev Returns whether `account` has cast a vote on `proposalId`. */ function hasVoted(uint256 proposalId, address account) external view returns (bool); /** * @dev Create a new proposal. Vote start after a delay specified by {IGovernor-votingDelay} and lasts for a * duration specified by {IGovernor-votingPeriod}. * * Emits a {ProposalCreated} event. * * NOTE: The state of the Governor and `targets` may change between the proposal creation and its execution. * This may be the result of third party actions on the targeted contracts, or other governor proposals. * For example, the balance of this contract could be updated or its access control permissions may be modified, * possibly compromising the proposal's ability to execute successfully (e.g. the governor doesn't have enough * value to cover a proposal with multiple transfers). */ function propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description ) external returns (uint256 proposalId); /** * @dev Queue a proposal. Some governors require this step to be performed before execution can happen. If queuing * is not necessary, this function may revert. * Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached. * * Emits a {ProposalQueued} event. */ function queue( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external returns (uint256 proposalId); /** * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the * deadline to be reached. Depending on the governor it might also be required that the proposal was queued and * that some delay passed. * * Emits a {ProposalExecuted} event. * * NOTE: Some modules can modify the requirements for execution, for example by adding an additional timelock. */ function execute( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external payable returns (uint256 proposalId); /** * @dev Cancel a proposal. A proposal is cancellable by the proposer, but only while it is Pending state, i.e. * before the vote starts. * * Emits a {ProposalCanceled} event. */ function cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external returns (uint256 proposalId); /** * @dev Cast a vote * * Emits a {VoteCast} event. */ function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance); /** * @dev Cast a vote with a reason * * Emits a {VoteCast} event. */ function castVoteWithReason( uint256 proposalId, uint8 support, string calldata reason ) external returns (uint256 balance); /** * @dev Cast a vote with a reason and additional encoded parameters * * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. */ function castVoteWithReasonAndParams( uint256 proposalId, uint8 support, string calldata reason, bytes memory params ) external returns (uint256 balance); /** * @dev Cast a vote using the voter's signature, including ERC-1271 signature support. * * Emits a {VoteCast} event. */ function castVoteBySig( uint256 proposalId, uint8 support, address voter, bytes memory signature ) external returns (uint256 balance); /** * @dev Cast a vote with a reason and additional encoded parameters using the voter's signature, * including ERC-1271 signature support. * * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. */ function castVoteWithReasonAndParamsBySig( uint256 proposalId, uint8 support, address voter, string calldata reason, bytes memory params, bytes memory signature ) external returns (uint256 balance); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SafeCast} from "./math/SafeCast.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { using SafeCast for *; 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 The string being parsed contains characters that are not in scope of the given base. */ error StringsInvalidChar(); /** * @dev The string being parsed is not a properly formatted address. */ error StringsInvalidAddressFormat(); /** * @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; assembly ("memory-safe") { ptr := add(buffer, add(32, length)) } while (true) { ptr--; assembly ("memory-safe") { 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 Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal * representation, according to EIP-55. */ function toChecksumHexString(address addr) internal pure returns (string memory) { bytes memory buffer = bytes(toHexString(addr)); // hash the hex part of buffer (skip length + 2 bytes, length 40) uint256 hashValue; assembly ("memory-safe") { hashValue := shr(96, keccak256(add(buffer, 0x22), 40)) } for (uint256 i = 41; i > 1; --i) { // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f) if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) { // case shift by xoring with 0x20 buffer[i] ^= 0x20; } hashValue >>= 4; } return string(buffer); } /** * @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)); } /** * @dev Parse a decimal string and returns the value as a `uint256`. * * Requirements: * - The string must be formatted as `[0-9]*` * - The result must fit into an `uint256` type */ function parseUint(string memory input) internal pure returns (uint256) { return parseUint(input, 0, bytes(input).length); } /** * @dev Variant of {parseUint} that parses a substring of `input` located between position `begin` (included) and * `end` (excluded). * * Requirements: * - The substring must be formatted as `[0-9]*` * - The result must fit into an `uint256` type */ function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) { (bool success, uint256 value) = tryParseUint(input, begin, end); if (!success) revert StringsInvalidChar(); return value; } /** * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character. * * NOTE: This function will revert if the result does not fit in a `uint256`. */ function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) { return _tryParseUintUncheckedBounds(input, 0, bytes(input).length); } /** * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid * character. * * NOTE: This function will revert if the result does not fit in a `uint256`. */ function tryParseUint( string memory input, uint256 begin, uint256 end ) internal pure returns (bool success, uint256 value) { if (end > bytes(input).length || begin > end) return (false, 0); return _tryParseUintUncheckedBounds(input, begin, end); } /** * @dev Implementation of {tryParseUint} that does not check bounds. Caller should make sure that * `begin <= end <= input.length`. Other inputs would result in undefined behavior. */ function _tryParseUintUncheckedBounds( string memory input, uint256 begin, uint256 end ) private pure returns (bool success, uint256 value) { bytes memory buffer = bytes(input); uint256 result = 0; for (uint256 i = begin; i < end; ++i) { uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i))); if (chr > 9) return (false, 0); result *= 10; result += chr; } return (true, result); } /** * @dev Parse a decimal string and returns the value as a `int256`. * * Requirements: * - The string must be formatted as `[-+]?[0-9]*` * - The result must fit in an `int256` type. */ function parseInt(string memory input) internal pure returns (int256) { return parseInt(input, 0, bytes(input).length); } /** * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and * `end` (excluded). * * Requirements: * - The substring must be formatted as `[-+]?[0-9]*` * - The result must fit in an `int256` type. */ function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) { (bool success, int256 value) = tryParseInt(input, begin, end); if (!success) revert StringsInvalidChar(); return value; } /** * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if * the result does not fit in a `int256`. * * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`. */ function tryParseInt(string memory input) internal pure returns (bool success, int256 value) { return _tryParseIntUncheckedBounds(input, 0, bytes(input).length); } uint256 private constant ABS_MIN_INT256 = 2 ** 255; /** * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid * character or if the result does not fit in a `int256`. * * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`. */ function tryParseInt( string memory input, uint256 begin, uint256 end ) internal pure returns (bool success, int256 value) { if (end > bytes(input).length || begin > end) return (false, 0); return _tryParseIntUncheckedBounds(input, begin, end); } /** * @dev Implementation of {tryParseInt} that does not check bounds. Caller should make sure that * `begin <= end <= input.length`. Other inputs would result in undefined behavior. */ function _tryParseIntUncheckedBounds( string memory input, uint256 begin, uint256 end ) private pure returns (bool success, int256 value) { bytes memory buffer = bytes(input); // Check presence of a negative sign. bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty bool positiveSign = sign == bytes1("+"); bool negativeSign = sign == bytes1("-"); uint256 offset = (positiveSign || negativeSign).toUint(); (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end); if (absSuccess && absValue < ABS_MIN_INT256) { return (true, negativeSign ? -int256(absValue) : int256(absValue)); } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) { return (true, type(int256).min); } else return (false, 0); } /** * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`. * * Requirements: * - The string must be formatted as `(0x)?[0-9a-fA-F]*` * - The result must fit in an `uint256` type. */ function parseHexUint(string memory input) internal pure returns (uint256) { return parseHexUint(input, 0, bytes(input).length); } /** * @dev Variant of {parseHexUint} that parses a substring of `input` located between position `begin` (included) and * `end` (excluded). * * Requirements: * - The substring must be formatted as `(0x)?[0-9a-fA-F]*` * - The result must fit in an `uint256` type. */ function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) { (bool success, uint256 value) = tryParseHexUint(input, begin, end); if (!success) revert StringsInvalidChar(); return value; } /** * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character. * * NOTE: This function will revert if the result does not fit in a `uint256`. */ function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) { return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length); } /** * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an * invalid character. * * NOTE: This function will revert if the result does not fit in a `uint256`. */ function tryParseHexUint( string memory input, uint256 begin, uint256 end ) internal pure returns (bool success, uint256 value) { if (end > bytes(input).length || begin > end) return (false, 0); return _tryParseHexUintUncheckedBounds(input, begin, end); } /** * @dev Implementation of {tryParseHexUint} that does not check bounds. Caller should make sure that * `begin <= end <= input.length`. Other inputs would result in undefined behavior. */ function _tryParseHexUintUncheckedBounds( string memory input, uint256 begin, uint256 end ) private pure returns (bool success, uint256 value) { bytes memory buffer = bytes(input); // skip 0x prefix if present bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty uint256 offset = hasPrefix.toUint() * 2; uint256 result = 0; for (uint256 i = begin + offset; i < end; ++i) { uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i))); if (chr > 15) return (false, 0); result *= 16; unchecked { // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check). // This guaratees that adding a value < 16 will not cause an overflow, hence the unchecked. result += chr; } } return (true, result); } /** * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`. * * Requirements: * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}` */ function parseAddress(string memory input) internal pure returns (address) { return parseAddress(input, 0, bytes(input).length); } /** * @dev Variant of {parseAddress} that parses a substring of `input` located between position `begin` (included) and * `end` (excluded). * * Requirements: * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}` */ function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) { (bool success, address value) = tryParseAddress(input, begin, end); if (!success) revert StringsInvalidAddressFormat(); return value; } /** * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly * formatted address. See {parseAddress} requirements. */ function tryParseAddress(string memory input) internal pure returns (bool success, address value) { return tryParseAddress(input, 0, bytes(input).length); } /** * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly * formatted address. See {parseAddress} requirements. */ function tryParseAddress( string memory input, uint256 begin, uint256 end ) internal pure returns (bool success, address value) { if (end > bytes(input).length || begin > end) return (false, address(0)); bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty uint256 expectedLength = 40 + hasPrefix.toUint() * 2; // check that input is the correct length if (end - begin == expectedLength) { // length guarantees that this does not overflow, and value is at most type(uint160).max (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end); return (s, address(uint160(v))); } else { return (false, address(0)); } } function _tryParseChr(bytes1 chr) private pure returns (uint8) { uint8 value = uint8(chr); // Try to parse `chr`: // - Case 1: [0-9] // - Case 2: [a-f] // - Case 3: [A-F] // - otherwise not supported unchecked { if (value > 47 && value < 58) value -= 48; else if (value > 96 && value < 103) value -= 87; else if (value > 64 && value < 71) value -= 55; else return type(uint8).max; } return value; } /** * @dev Reads a bytes32 from a bytes array without bounds checking. * * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the * assembly block as such would prevent some optimizations. */ function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { // This is not memory safe in the general case, but all calls to this private function are within bounds. assembly ("memory-safe") { value := mload(add(buffer, add(0x20, offset))) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC-721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC-721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Interface that must be implemented by smart contracts in order to receive * ERC-1155 token transfers. */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC-1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC-1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/SignatureChecker.sol) pragma solidity ^0.8.20; import {ECDSA} from "./ECDSA.sol"; import {IERC1271} from "../../interfaces/IERC1271.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC-1271 signatures from smart contract wallets like * Argent and Safe Wallet (previously Gnosis Safe). */ library SignatureChecker { /** * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the * signature is validated against that smart contract using ERC-1271, otherwise it's validated using `ECDSA.recover`. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { if (signer.code.length == 0) { (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); return err == ECDSA.RecoverError.NoError && recovered == signer; } else { return isValidERC1271SignatureNow(signer, hash, signature); } } /** * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated * against the signer smart contract using ERC-1271. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidERC1271SignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool) { (bool success, bytes memory result) = signer.staticcall( abi.encodeCall(IERC1271.isValidSignature, (hash, signature)) ); return (success && result.length >= 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/DoubleEndedQueue.sol) pragma solidity ^0.8.20; import {Panic} from "../Panic.sol"; /** * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that * the existing queue contents are left in storage. * * The struct is called `Bytes32Deque`. Other types can be cast to and from `bytes32`. This data structure can only be * used in storage, and not in memory. * ```solidity * DoubleEndedQueue.Bytes32Deque queue; * ``` */ library DoubleEndedQueue { /** * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access. * * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and * lead to unexpected behavior. * * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around. */ struct Bytes32Deque { uint128 _begin; uint128 _end; mapping(uint128 index => bytes32) _data; } /** * @dev Inserts an item at the end of the queue. * * Reverts with {Panic-RESOURCE_ERROR} if the queue is full. */ function pushBack(Bytes32Deque storage deque, bytes32 value) internal { unchecked { uint128 backIndex = deque._end; if (backIndex + 1 == deque._begin) Panic.panic(Panic.RESOURCE_ERROR); deque._data[backIndex] = value; deque._end = backIndex + 1; } } /** * @dev Removes the item at the end of the queue and returns it. * * Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty. */ function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) { unchecked { uint128 backIndex = deque._end; if (backIndex == deque._begin) Panic.panic(Panic.EMPTY_ARRAY_POP); --backIndex; value = deque._data[backIndex]; delete deque._data[backIndex]; deque._end = backIndex; } } /** * @dev Inserts an item at the beginning of the queue. * * Reverts with {Panic-RESOURCE_ERROR} if the queue is full. */ function pushFront(Bytes32Deque storage deque, bytes32 value) internal { unchecked { uint128 frontIndex = deque._begin - 1; if (frontIndex == deque._end) Panic.panic(Panic.RESOURCE_ERROR); deque._data[frontIndex] = value; deque._begin = frontIndex; } } /** * @dev Removes the item at the beginning of the queue and returns it. * * Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty. */ function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) { unchecked { uint128 frontIndex = deque._begin; if (frontIndex == deque._end) Panic.panic(Panic.EMPTY_ARRAY_POP); value = deque._data[frontIndex]; delete deque._data[frontIndex]; deque._begin = frontIndex + 1; } } /** * @dev Returns the item at the beginning of the queue. * * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty. */ function front(Bytes32Deque storage deque) internal view returns (bytes32 value) { if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); return deque._data[deque._begin]; } /** * @dev Returns the item at the end of the queue. * * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty. */ function back(Bytes32Deque storage deque) internal view returns (bytes32 value) { if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); unchecked { return deque._data[deque._end - 1]; } } /** * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at * `length(deque) - 1`. * * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the index is out of bounds. */ function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) { if (index >= length(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128 unchecked { return deque._data[deque._begin + uint128(index)]; } } /** * @dev Resets the queue back to being empty. * * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses * out on potential gas refunds. */ function clear(Bytes32Deque storage deque) internal { deque._begin = 0; deque._end = 0; } /** * @dev Returns the number of items in the queue. */ function length(Bytes32Deque storage deque) internal view returns (uint256) { unchecked { return uint256(deque._end - deque._begin); } } /** * @dev Returns true if the queue is empty. */ function empty(Bytes32Deque storage deque) internal view returns (bool) { return deque._end == deque._begin; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5805.sol) pragma solidity ^0.8.20; import {IVotes} from "../governance/utils/IVotes.sol"; import {IERC6372} from "./IERC6372.sol"; interface IERC5805 is IERC6372, IVotes {}
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/types/Time.sol) pragma solidity ^0.8.20; import {Math} from "../math/Math.sol"; import {SafeCast} from "../math/SafeCast.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 valueBefore, uint32 valueAfter, uint48 effect) { (valueBefore, valueAfter, 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 valueBefore, uint32 valueAfter, uint48 effect) { 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)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.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[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an ERC-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) { assembly ("memory-safe") { 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 ERC-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 ERC-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 (ERC-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) { assembly ("memory-safe") { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ShortStrings.sol) pragma solidity ^0.8.20; import {StorageSlot} from "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); assembly ("memory-safe") { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using * {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.20; 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 ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol) pragma solidity ^0.8.20; 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. * * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute * one branch when needed, making this function more expensive. */ function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) { unchecked { // branchless ternary works because: // b ^ (a ^ b) == a // b ^ 0 == b return b ^ ((a ^ b) * int256(SafeCast.toUint(condition))); } } /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return ternary(a > b, a, b); } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return ternary(a < b, a, b); } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson. // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift, // taking advantage of the most significant (or "sign" bit) in two's complement representation. // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result, // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative). int256 mask = n >> 255; // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it. return uint256((n + mask) ^ mask); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1271.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
{ "remappings": [ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "ds-test/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "sp1-contracts/=lib/sp1-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 100 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "prague", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"auctioneer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"bytes","name":"iproveCode","type":"bytes"},{"internalType":"bytes","name":"governorCode","type":"bytes"}],"name":"deploy","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployerOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dispenser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisStateRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxUnstakeRequests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minStakeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposalThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prove","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quorumFraction","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stakingImpl","type":"address"},{"internalType":"address","name":"_prove","type":"address"},{"internalType":"uint48","name":"_votingDelay","type":"uint48"},{"internalType":"uint32","name":"_votingPeriod","type":"uint32"},{"internalType":"uint256","name":"_proposalThreshold","type":"uint256"},{"internalType":"uint256","name":"_quorumFraction","type":"uint256"}],"name":"setParams1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vappImpl","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_auctioneer","type":"address"},{"internalType":"address","name":"_verifier","type":"address"},{"internalType":"uint256","name":"_minDepositAmount","type":"uint256"},{"internalType":"bytes32","name":"_vkey","type":"bytes32"}],"name":"setParams2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_dispenser","type":"address"},{"internalType":"uint256","name":"_minStakeAmount","type":"uint256"},{"internalType":"uint256","name":"_maxUnstakeRequests","type":"uint256"},{"internalType":"uint256","name":"_unstakePeriod","type":"uint256"},{"internalType":"uint256","name":"_slashCancellationPeriod","type":"uint256"},{"internalType":"bytes32","name":"_genesisStateRoot","type":"bytes32"}],"name":"setParams3","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"slashCancellationPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingImpl","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unstakePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vappImpl","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vkey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingDelay","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingPeriod","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6080604052348015600e575f5ffd5b50601080546001600160a01b03191633179055610e128061002e5f395ff3fe608060405234801561000f575f5ffd5b5060043610610148575f3560e01c8063a7602c7e116100bf578063e09d894d11610079578063e09d894d146102f2578063e4aa64ab14610305578063e76e84ed1461030e578063e886aeea14610321578063f18876841461032a578063f38c1af714610333575f5ffd5b8063a7602c7e146102a9578063b4113cc8146102b2578063b58131b0146102c4578063c69b0eb1146102cd578063c7dfb1d6146102d6578063e06ff5ca146102df575f5ffd5b806345152ae31161011057806345152ae3146102315780635ec2c7bf14610244578063645006ca146102575780637200acaf1461026e5780638da5cb5b14610281578063a169f52e14610294575f5ffd5b806302a251a31461014c57806319cdeff11461017d5780631c8319d2146101c35780632b7ac3f3146101ee5780633932abb114610201575b5f5ffd5b60015461016390600160d01b900463ffffffff1681565b60405163ffffffff90911681526020015b60405180910390f35b61019061018b36600461080b565b61033c565b604080516001600160a01b0395861681529385166020850152918416918301919091529091166060820152608001610174565b6004546101d6906001600160a01b031681565b6040516001600160a01b039091168152602001610174565b6007546101d6906001600160a01b031681565b60015461021a90600160a01b900465ffffffffffff1681565b60405165ffffffffffff9091168152602001610174565b6001546101d6906001600160a01b031681565b6006546101d6906001600160a01b031681565b61026060085481565b604051908152602001610174565b6010546101d6906001600160a01b031681565b6005546101d6906001600160a01b031681565b6102a76102a236600461089f565b610673565b005b610260600c5481565b5f546101d6906001600160a01b031681565b61026060025481565b61026060095481565b61026060035481565b6102a76102ed366004610901565b6106e2565b600a546101d6906001600160a01b031681565b610260600d5481565b6102a761031c366004610947565b610730565b610260600f5481565b610260600b5481565b610260600e5481565b6010545f908190819081906001600160a01b0316331461035a575f5ffd5b5f80546040518b916001600160a01b031690610375906107b9565b6001600160a01b0390911681526040602082018190525f908201526060018190604051809103905ff59050801580156103b0573d5f5f3e3d5ffd5b50600154604080516001600160a01b03928316602082015291831682820152805180830382018152606083019091529192505f919082906103f9908d908d9085906080016109a5565b60405160208183030381529060405290508c8151602083015ff59250823b61041f575f5ffd5b5050600154600254600354604080516001600160a01b0386166020820152600160a01b850465ffffffffffff1691810191909152600160d01b90930463ffffffff166060840152608083019190915260a08201525f90819060c00160405160208183030381529060405290505f8a8a836040516020016104a1939291906109a5565b60405160208183030381529060405290508d8151602083015ff59250823b6104c7575f5ffd5b5050600554600154600654600754600854600954600f546040516001600160a01b03978816602482015295871660448701528887166064870152938616608486015288861660a48601529490911660c484015260e48301526101048201929092526101248101919091525f906060906101440160408051601f198184030181529181526020820180516001600160e01b031663156c32ab60e31b17905260045490519192508f916001600160a01b03909116908390610585906107b9565b6105909291906109c8565b8190604051809103905ff59050801580156105ad573d5f5f3e3d5ffd5b50600554600154600a54600b54600c54600d54600e54604051631cc36f3560e11b81526001600160a01b0397881660048201528b88166024820152878916604482015295871660648701528b8716608487015293861660a486015260c485019290925260e484015261010483015261012482015291935086169150633986de6a90610144015f604051808303815f87803b158015610649575f5ffd5b505af115801561065b573d5f5f3e3d5ffd5b50959f929e50939c50919a5098505050505050505050565b6010546001600160a01b03163314610689575f5ffd5b600480546001600160a01b039788166001600160a01b0319918216179091556005805496881696821696909617909555600680549487169486169490941790935560078054929095169190931617909255600855600955565b6010546001600160a01b031633146106f8575f5ffd5b600a80546001600160a01b0319166001600160a01b039790971696909617909555600b93909355600c91909155600d55600e55600f55565b6010546001600160a01b03163314610746575f5ffd5b5f80546001600160a01b039788166001600160a01b03199091161790556001805463ffffffff909416600160d01b0263ffffffff60d01b1965ffffffffffff909616600160a01b026001600160d01b03199095169690971695909517929092179290921693909317909155600255600355565b6103d080610a0d83390190565b5f5f83601f8401126107d6575f5ffd5b50813567ffffffffffffffff8111156107ed575f5ffd5b602083019150836020828501011115610804575f5ffd5b9250929050565b5f5f5f5f5f6060868803121561081f575f5ffd5b85359450602086013567ffffffffffffffff81111561083c575f5ffd5b610848888289016107c6565b909550935050604086013567ffffffffffffffff811115610867575f5ffd5b610873888289016107c6565b969995985093965092949392505050565b80356001600160a01b038116811461089a575f5ffd5b919050565b5f5f5f5f5f5f60c087890312156108b4575f5ffd5b6108bd87610884565b95506108cb60208801610884565b94506108d960408801610884565b93506108e760608801610884565b9598949750929560808101359460a0909101359350915050565b5f5f5f5f5f5f60c08789031215610916575f5ffd5b61091f87610884565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b5f5f5f5f5f5f60c0878903121561095c575f5ffd5b61096587610884565b955061097360208801610884565b9450604087013565ffffffffffff8116811461098d575f5ffd5b9350606087013563ffffffff811681146108e7575f5ffd5b828482375f8382015f815283518060208601835e5f910190815295945050505050565b60018060a01b0383168152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f830116840101915050939250505056fe60806040526040516103d03803806103d08339810160408190526100229161023c565b61002c8282610033565b5050610321565b61003c82610091565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a280511561008557610080828261010c565b505050565b61008d61017f565b5050565b806001600160a01b03163b5f036100cb57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b031684604051610128919061030b565b5f60405180830381855af49150503d805f8114610160576040519150601f19603f3d011682016040523d82523d5f602084013e610165565b606091505b5090925090506101768583836101a0565b95945050505050565b341561019e5760405163b398979f60e01b815260040160405180910390fd5b565b6060826101b5576101b0826101ff565b6101f8565b81511580156101cc57506001600160a01b0384163b155b156101f557604051639996b31560e01b81526001600160a01b03851660048201526024016100c2565b50805b9392505050565b80511561020f5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b634e487b7160e01b5f52604160045260245ffd5b5f5f6040838503121561024d575f5ffd5b82516001600160a01b0381168114610263575f5ffd5b60208401519092506001600160401b0381111561027e575f5ffd5b8301601f8101851361028e575f5ffd5b80516001600160401b038111156102a7576102a7610228565b604051601f8201601f19908116603f011681016001600160401b03811182821017156102d5576102d5610228565b6040528181528282016020018710156102ec575f5ffd5b8160208401602083015e5f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b60a38061032d5f395ff3fe6080604052600a600c565b005b60186014601a565b6050565b565b5f604b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f5f375f5f365f845af43d5f5f3e8080156069573d5ff35b3d5ffdfea2646970667358221220aea4cc825fe42e4ee841f157c96189dbcabb0fd9ce7239b9d4cabcb90261b88364736f6c634300081c0033a264697066735822122027cecd8ac1171958fd89b8f085ceb3568fccca696a4c0e8be6cd6e634bfadacf64736f6c634300081c0033
Deployed Bytecode
0x608060405234801561000f575f5ffd5b5060043610610148575f3560e01c8063a7602c7e116100bf578063e09d894d11610079578063e09d894d146102f2578063e4aa64ab14610305578063e76e84ed1461030e578063e886aeea14610321578063f18876841461032a578063f38c1af714610333575f5ffd5b8063a7602c7e146102a9578063b4113cc8146102b2578063b58131b0146102c4578063c69b0eb1146102cd578063c7dfb1d6146102d6578063e06ff5ca146102df575f5ffd5b806345152ae31161011057806345152ae3146102315780635ec2c7bf14610244578063645006ca146102575780637200acaf1461026e5780638da5cb5b14610281578063a169f52e14610294575f5ffd5b806302a251a31461014c57806319cdeff11461017d5780631c8319d2146101c35780632b7ac3f3146101ee5780633932abb114610201575b5f5ffd5b60015461016390600160d01b900463ffffffff1681565b60405163ffffffff90911681526020015b60405180910390f35b61019061018b36600461080b565b61033c565b604080516001600160a01b0395861681529385166020850152918416918301919091529091166060820152608001610174565b6004546101d6906001600160a01b031681565b6040516001600160a01b039091168152602001610174565b6007546101d6906001600160a01b031681565b60015461021a90600160a01b900465ffffffffffff1681565b60405165ffffffffffff9091168152602001610174565b6001546101d6906001600160a01b031681565b6006546101d6906001600160a01b031681565b61026060085481565b604051908152602001610174565b6010546101d6906001600160a01b031681565b6005546101d6906001600160a01b031681565b6102a76102a236600461089f565b610673565b005b610260600c5481565b5f546101d6906001600160a01b031681565b61026060025481565b61026060095481565b61026060035481565b6102a76102ed366004610901565b6106e2565b600a546101d6906001600160a01b031681565b610260600d5481565b6102a761031c366004610947565b610730565b610260600f5481565b610260600b5481565b610260600e5481565b6010545f908190819081906001600160a01b0316331461035a575f5ffd5b5f80546040518b916001600160a01b031690610375906107b9565b6001600160a01b0390911681526040602082018190525f908201526060018190604051809103905ff59050801580156103b0573d5f5f3e3d5ffd5b50600154604080516001600160a01b03928316602082015291831682820152805180830382018152606083019091529192505f919082906103f9908d908d9085906080016109a5565b60405160208183030381529060405290508c8151602083015ff59250823b61041f575f5ffd5b5050600154600254600354604080516001600160a01b0386166020820152600160a01b850465ffffffffffff1691810191909152600160d01b90930463ffffffff166060840152608083019190915260a08201525f90819060c00160405160208183030381529060405290505f8a8a836040516020016104a1939291906109a5565b60405160208183030381529060405290508d8151602083015ff59250823b6104c7575f5ffd5b5050600554600154600654600754600854600954600f546040516001600160a01b03978816602482015295871660448701528887166064870152938616608486015288861660a48601529490911660c484015260e48301526101048201929092526101248101919091525f906060906101440160408051601f198184030181529181526020820180516001600160e01b031663156c32ab60e31b17905260045490519192508f916001600160a01b03909116908390610585906107b9565b6105909291906109c8565b8190604051809103905ff59050801580156105ad573d5f5f3e3d5ffd5b50600554600154600a54600b54600c54600d54600e54604051631cc36f3560e11b81526001600160a01b0397881660048201528b88166024820152878916604482015295871660648701528b8716608487015293861660a486015260c485019290925260e484015261010483015261012482015291935086169150633986de6a90610144015f604051808303815f87803b158015610649575f5ffd5b505af115801561065b573d5f5f3e3d5ffd5b50959f929e50939c50919a5098505050505050505050565b6010546001600160a01b03163314610689575f5ffd5b600480546001600160a01b039788166001600160a01b0319918216179091556005805496881696821696909617909555600680549487169486169490941790935560078054929095169190931617909255600855600955565b6010546001600160a01b031633146106f8575f5ffd5b600a80546001600160a01b0319166001600160a01b039790971696909617909555600b93909355600c91909155600d55600e55600f55565b6010546001600160a01b03163314610746575f5ffd5b5f80546001600160a01b039788166001600160a01b03199091161790556001805463ffffffff909416600160d01b0263ffffffff60d01b1965ffffffffffff909616600160a01b026001600160d01b03199095169690971695909517929092179290921693909317909155600255600355565b6103d080610a0d83390190565b5f5f83601f8401126107d6575f5ffd5b50813567ffffffffffffffff8111156107ed575f5ffd5b602083019150836020828501011115610804575f5ffd5b9250929050565b5f5f5f5f5f6060868803121561081f575f5ffd5b85359450602086013567ffffffffffffffff81111561083c575f5ffd5b610848888289016107c6565b909550935050604086013567ffffffffffffffff811115610867575f5ffd5b610873888289016107c6565b969995985093965092949392505050565b80356001600160a01b038116811461089a575f5ffd5b919050565b5f5f5f5f5f5f60c087890312156108b4575f5ffd5b6108bd87610884565b95506108cb60208801610884565b94506108d960408801610884565b93506108e760608801610884565b9598949750929560808101359460a0909101359350915050565b5f5f5f5f5f5f60c08789031215610916575f5ffd5b61091f87610884565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b5f5f5f5f5f5f60c0878903121561095c575f5ffd5b61096587610884565b955061097360208801610884565b9450604087013565ffffffffffff8116811461098d575f5ffd5b9350606087013563ffffffff811681146108e7575f5ffd5b828482375f8382015f815283518060208601835e5f910190815295945050505050565b60018060a01b0383168152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f830116840101915050939250505056fe60806040526040516103d03803806103d08339810160408190526100229161023c565b61002c8282610033565b5050610321565b61003c82610091565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a280511561008557610080828261010c565b505050565b61008d61017f565b5050565b806001600160a01b03163b5f036100cb57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b031684604051610128919061030b565b5f60405180830381855af49150503d805f8114610160576040519150601f19603f3d011682016040523d82523d5f602084013e610165565b606091505b5090925090506101768583836101a0565b95945050505050565b341561019e5760405163b398979f60e01b815260040160405180910390fd5b565b6060826101b5576101b0826101ff565b6101f8565b81511580156101cc57506001600160a01b0384163b155b156101f557604051639996b31560e01b81526001600160a01b03851660048201526024016100c2565b50805b9392505050565b80511561020f5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b634e487b7160e01b5f52604160045260245ffd5b5f5f6040838503121561024d575f5ffd5b82516001600160a01b0381168114610263575f5ffd5b60208401519092506001600160401b0381111561027e575f5ffd5b8301601f8101851361028e575f5ffd5b80516001600160401b038111156102a7576102a7610228565b604051601f8201601f19908116603f011681016001600160401b03811182821017156102d5576102d5610228565b6040528181528282016020018710156102ec575f5ffd5b8160208401602083015e5f602083830101528093505050509250929050565b5f82518060208501845e5f920191825250919050565b60a38061032d5f395ff3fe6080604052600a600c565b005b60186014601a565b6050565b565b5f604b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f5f375f5f365f845af43d5f5f3e8080156069573d5ff35b3d5ffdfea2646970667358221220aea4cc825fe42e4ee841f157c96189dbcabb0fd9ce7239b9d4cabcb90261b88364736f6c634300081c0033a264697066735822122027cecd8ac1171958fd89b8f085ceb3568fccca696a4c0e8be6cd6e634bfadacf64736f6c634300081c0033
Loading...
Loading
Loading...
Loading

Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.