Overview
ETH Balance
0.0002 ETH
ETH Value
$0.67 (@ $3,344.44/ETH)More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 6 from a total of 6 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw | 13492755 | 18 days ago | IN | 0 ETH | 0.00000004 | ||||
Initialize | 13492734 | 18 days ago | IN | 0 ETH | 0.00000004 | ||||
Deposit | 5115898 | 212 days ago | IN | 0.0001 ETH | 0.00001955 | ||||
Deposit | 5115454 | 212 days ago | IN | 0.0001 ETH | 0.00000652 | ||||
Transfer | 4481341 | 227 days ago | IN | 0 ETH | 0.00000072 | ||||
Transfer | 4359874 | 229 days ago | IN | 0 ETH | 0.00000031 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
2182863 | 280 days ago | 0.0001 ETH |
Loading...
Loading
Contract Name:
WETHRebasing
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd. pragma solidity 0.8.15; import { FixedPointMathLib } from "solmate/utils/FixedPointMathLib.sol"; import { Blast, YieldMode } from "src/L2/Blast.sol"; import { GasMode } from "src/L2/Gas.sol"; import { ERC20Rebasing } from "src/L2/ERC20Rebasing.sol"; import { SharesBase } from "src/L2/Shares.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { Semver } from "src/universal/Semver.sol"; /// @custom:proxied /// @custom:predeploy 0x4300000000000000000000000000000000000004 /// @title WETHRebasing /// @notice Rebasing ERC20 token that serves as WETH on Blast L2. /// Although the WETH token builds on top of the already rebasing native ether, /// it has its own configuration and shares accounting. However, it’s the only token /// that does not receive a yield report. /// /// An additional complexity with WETH is that since it holds native ether, /// its own balance is rebasing. Therefore, we could just base the WETH share price on the ether price, /// however, users and contracts are able to opt-out of receiving yield, while their funds are still /// gaining yield for the WETH contract. Using the native ether share price would leave yields /// in the WETH contract that are unallocated due to the VOID balances. To resolve this, WETH has /// its own share price that’s computed based on its current balance and removing void funds /// so the yields are only divided amongst the active funds. contract WETHRebasing is ERC20Rebasing, Semver { /// @notice Emitted whenever tokens are deposited to an account. /// @param account Address of the account tokens are being deposited to. /// @param amount Amount of tokens deposited. event Deposit(address indexed account, uint amount); /// @notice Emitted whenever tokens are withdrawn from an account. /// @param account Address of the account tokens are being withdrawn from. /// @param amount Amount of tokens withdrawn. event Withdrawal(address indexed account, uint amount); error ETHTransferFailed(); /// @custom:semver 1.0.0 constructor() ERC20Rebasing(Predeploys.SHARES, 18) Semver(1, 0, 0) { _disableInitializers(); } /// @notice Initializer. function initialize() external initializer { __ERC20Rebasing_init( "Wrapped Ether", "WETH", SharesBase(Predeploys.SHARES).price() ); Blast(Predeploys.BLAST).configureContract( address(this), YieldMode.AUTOMATIC, GasMode.VOID, address(0xdead) /// don't set a governor ); } /// @notice Allows a user to send ETH directly and have /// their balance updated. receive() external payable { deposit(); } /// @notice Deposit ETH and increase the wrapped balance. function deposit() public payable { address account = msg.sender; _deposit(account, msg.value); emit Deposit(account, msg.value); } /// @notice Withdraw ETH and decrease the wrapped balance. /// @param wad Amount to withdraw. function withdraw(uint256 wad) public { address account = msg.sender; _withdraw(account, wad); (bool success,) = account.call{value: wad}(""); if (!success) revert ETHTransferFailed(); emit Withdrawal(account, wad); } /// @notice Update the share price based on the rebased contract balance. function _addValue(uint256) internal override { if (msg.sender != REPORTER) { revert InvalidReporter(); } uint256 yieldBearingEth = price * _totalShares; uint256 pending = address(this).balance - yieldBearingEth - _totalVoidAndRemainders; if (pending < _totalShares || _totalShares == 0) { return; } price += (pending / _totalShares); } /** * @dev The version parameter for the EIP712 domain. */ function _EIP712Version() internal override view returns (string memory) { return version(); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } function powWad(int256 x, int256 y) internal pure returns (int256) { // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y) return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0. } function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is < 0.5 we return zero. This happens when // x <= floor(log(0.5e18) * 1e18) ~ -42e18 if (x <= -42139678854452767551) return 0; // When the result is > (2**255 - 1) / 1e18 we can not represent it as an // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. if (x >= 135305999368893231589) revert("EXP_OVERFLOW"); // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5**18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96; x = x - k * 54916777467707473351141471128; // k is in the range [-61, 195]. // Evaluate using a (6, 7)-term rational approximation. // p is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already 2**96 too large. r := sdiv(p, q) } // r should be in the range (0.09, 0.25) * 2**96. // We now need to multiply r by: // * the scale factor s = ~6.031367120. // * the 2**k factor from the range reduction. // * the 1e18 / 2**96 factor for base conversion. // We do this all at once, with an intermediate result in 2**213 // basis, so the final right shift is always by a positive amount. r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)); } } function lnWad(int256 x) internal pure returns (int256 r) { unchecked { require(x > 0, "UNDEFINED"); // We want to convert x from 10**18 fixed point to 2**96 fixed point. // We do this by multiplying by 2**96 / 10**18. But since // ln(x * C) = ln(x) + ln(C), we can simply do nothing here // and add ln(2**96 / 10**18) at the end. // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) int256 k = int256(log2(uint256(x))) - 96; x <<= uint256(159 - k); x = int256(uint256(x) >> 159); // Evaluate using a (8, 8)-term rational approximation. // p is made monic, we will multiply by a scale factor later. int256 p = x + 3273285459638523848632254066296; p = ((p * x) >> 96) + 24828157081833163892658089445524; p = ((p * x) >> 96) + 43456485725739037958740375743393; p = ((p * x) >> 96) - 11111509109440967052023855526967; p = ((p * x) >> 96) - 45023709667254063763336534515857; p = ((p * x) >> 96) - 14706773417378608786704636184526; p = p * x - (795164235651350426258249787498 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. // q is monic by convention. int256 q = x + 5573035233440673466300451813936; q = ((q * x) >> 96) + 71694874799317883764090561454958; q = ((q * x) >> 96) + 283447036172924575727196451306956; q = ((q * x) >> 96) + 401686690394027663651624208769553; q = ((q * x) >> 96) + 204048457590392012362485061816622; q = ((q * x) >> 96) + 31853899698501571402653359427138; q = ((q * x) >> 96) + 909429971244387300277376558375; assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already 2**96 too large. r := sdiv(p, q) } // r is in the range (0, 0.125) * 2**96 // Finalization, we need to: // * multiply by the scale factor s = 5.549… // * add ln(2**96 / 10**18) // * add k * ln(2) // * multiply by 10**18 / 2**96 = 5**18 >> 78 // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 r *= 1677202110996718588342820967067443963516166; // add ln(2) * k * 5e18 * 2**192 r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; // add ln(2**96 / 10**18) * 5e18 * 2**192 r += 600920179829731861736702779321621459595472258049074101567377883020018308; // base conversion: mul 2**18 / 2**192 r >>= 174; } } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // Divide z by the denominator. z := div(z, denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // First, divide z - 1 by the denominator and add 1. // We allow z - 1 to underflow if z is 0, because we multiply the // end result by 0 if z is zero, ensuring we return 0 if z is zero. z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function log2(uint256 x) internal pure returns (uint256 r) { require(x > 0, "UNDEFINED"); assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) r := or(r, shl(2, lt(0xf, shr(r, x)))) r := or(r, shl(1, lt(0x3, shr(r, x)))) r := or(r, lt(0x1, shr(r, x))) } } }
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd. pragma solidity 0.8.15; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { Semver } from "src/universal/Semver.sol"; import { GasMode, IGas } from "src/L2/Gas.sol"; enum YieldMode { AUTOMATIC, VOID, CLAIMABLE } interface IYield { function configure(address contractAddress, uint8 flags) external returns (uint256); function claim(address contractAddress, address recipientOfYield, uint256 desiredAmount) external returns (uint256); function getClaimableAmount(address contractAddress) external view returns (uint256); function getConfiguration(address contractAddress) external view returns (uint8); } interface IBlast{ // configure function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external; function configure(YieldMode _yield, GasMode gasMode, address governor) external; // base configuration options function configureClaimableYield() external; function configureClaimableYieldOnBehalf(address contractAddress) external; function configureAutomaticYield() external; function configureAutomaticYieldOnBehalf(address contractAddress) external; function configureVoidYield() external; function configureVoidYieldOnBehalf(address contractAddress) external; function configureClaimableGas() external; function configureClaimableGasOnBehalf(address contractAddress) external; function configureVoidGas() external; function configureVoidGasOnBehalf(address contractAddress) external; function configureGovernor(address _governor) external; function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external; // claim yield function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256); function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256); // claim gas function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256); // NOTE: can be off by 1 bip function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256); function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256); // read functions function readClaimableYield(address contractAddress) external view returns (uint256); function readYieldConfiguration(address contractAddress) external view returns (uint8); function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode); } /// @custom:predeploy 0x4300000000000000000000000000000000000002 /// @title Blast contract Blast is IBlast, Initializable, Semver { address public immutable YIELD_CONTRACT; address public immutable GAS_CONTRACT; mapping(address => address) public governorMap; constructor(address _gasContract, address _yieldContract) Semver(1, 0, 0) { GAS_CONTRACT = _gasContract; YIELD_CONTRACT = _yieldContract; _disableInitializers(); } function initialize() public initializer {} /** * @notice Checks if the caller is the governor of the contract * @param contractAddress The address of the contract * @return A boolean indicating if the caller is the governor */ function isGovernor(address contractAddress) public view returns (bool) { return msg.sender == governorMap[contractAddress]; } /** * @notice Checks if the governor is not set for the contract * @param contractAddress The address of the contract * @return boolean indicating if the governor is not set */ function governorNotSet(address contractAddress) internal view returns (bool) { return governorMap[contractAddress] == address(0); } /** * @notice Checks if the caller is authorized * @param contractAddress The address of the contract * @return A boolean indicating if the caller is authorized */ function isAuthorized(address contractAddress) public view returns (bool) { return isGovernor(contractAddress) || (governorNotSet(contractAddress) && msg.sender == contractAddress); } /** * @notice contract configures its yield and gas modes and sets the governor. called by contract * @param _yieldMode The yield mode to be set * @param _gasMode The gas mode to be set * @param governor The address of the governor to be set */ function configure(YieldMode _yieldMode, GasMode _gasMode, address governor) external { // requires that no governor is set for contract require(isAuthorized(msg.sender), "not authorized to configure contract"); // set governor governorMap[msg.sender] = governor; // set gas mode IGas(GAS_CONTRACT).setGasMode(msg.sender, _gasMode); // set yield mode IYield(YIELD_CONTRACT).configure(msg.sender, uint8(_yieldMode)); } /** * @notice Configures the yield and gas modes and sets the governor for a specific contract. called by authorized user * @param contractAddress The address of the contract to be configured * @param _yieldMode The yield mode to be set * @param _gasMode The gas mode to be set * @param _newGovernor The address of the new governor to be set */ function configureContract(address contractAddress, YieldMode _yieldMode, GasMode _gasMode, address _newGovernor) external { // only allow governor, or if no governor is set, the contract itself to configure require(isAuthorized(contractAddress), "not authorized to configure contract"); // set governor governorMap[contractAddress] = _newGovernor; // set gas mode IGas(GAS_CONTRACT).setGasMode(contractAddress, _gasMode); // set yield mode IYield(YIELD_CONTRACT).configure(contractAddress, uint8(_yieldMode)); } /** * @notice Configures the yield mode to CLAIMABLE for the contract that calls this function */ function configureClaimableYield() external { require(isAuthorized(msg.sender), "not authorized to configure contract"); IYield(YIELD_CONTRACT).configure(msg.sender, uint8(YieldMode.CLAIMABLE)); } /** * @notice Configures the yield mode to CLAIMABLE for a specific contract. Called by an authorized user * @param contractAddress The address of the contract to be configured */ function configureClaimableYieldOnBehalf(address contractAddress) external { require(isAuthorized(contractAddress), "not authorized to configure contract"); IYield(YIELD_CONTRACT).configure(contractAddress, uint8(YieldMode.CLAIMABLE)); } /** * @notice Configures the yield mode to AUTOMATIC for the contract that calls this function */ function configureAutomaticYield() external { require(isAuthorized(msg.sender), "not authorized to configure contract"); IYield(YIELD_CONTRACT).configure(msg.sender, uint8(YieldMode.AUTOMATIC)); } /** * @notice Configures the yield mode to AUTOMATIC for a specific contract. Called by an authorized user * @param contractAddress The address of the contract to be configured */ function configureAutomaticYieldOnBehalf(address contractAddress) external { require(isAuthorized(contractAddress), "not authorized to configure contract"); IYield(YIELD_CONTRACT).configure(contractAddress, uint8(YieldMode.AUTOMATIC)); } /** * @notice Configures the yield mode to VOID for the contract that calls this function */ function configureVoidYield() external { require(isAuthorized(msg.sender), "not authorized to configure contract"); IYield(YIELD_CONTRACT).configure(msg.sender, uint8(YieldMode.VOID)); } /** * @notice Configures the yield mode to VOID for a specific contract. Called by an authorized user * @param contractAddress The address of the contract to be configured */ function configureVoidYieldOnBehalf(address contractAddress) external { require(isAuthorized(contractAddress), "not authorized to configure contract"); IYield(YIELD_CONTRACT).configure(contractAddress, uint8(YieldMode.VOID)); } /** * @notice Configures the gas mode to CLAIMABLE for the contract that calls this function */ function configureClaimableGas() external { require(isAuthorized(msg.sender), "not authorized to configure contract"); IGas(GAS_CONTRACT).setGasMode(msg.sender, GasMode.CLAIMABLE); } /** * @notice Configures the gas mode to CLAIMABLE for a specific contract. Called by an authorized user * @param contractAddress The address of the contract to be configured */ function configureClaimableGasOnBehalf(address contractAddress) external { require(isAuthorized(contractAddress), "not authorized to configure contract"); IGas(GAS_CONTRACT).setGasMode(contractAddress, GasMode.CLAIMABLE); } /** * @notice Configures the gas mode to VOID for the contract that calls this function */ function configureVoidGas() external { require(isAuthorized(msg.sender), "not authorized to configure contract"); IGas(GAS_CONTRACT).setGasMode(msg.sender, GasMode.VOID); } /** * @notice Configures the gas mode to void for a specific contract. Called by an authorized user * @param contractAddress The address of the contract to be configured */ function configureVoidGasOnBehalf(address contractAddress) external { require(isAuthorized(contractAddress), "not authorized to configure contract"); IGas(GAS_CONTRACT).setGasMode(contractAddress, GasMode.VOID); } /** * @notice Configures the governor for the contract that calls this function */ function configureGovernor(address _governor) external { require(isAuthorized(msg.sender), "not authorized to configure contract"); governorMap[msg.sender] = _governor; } /** * @notice Configures the governor for a specific contract. Called by an authorized user * @param contractAddress The address of the contract to be configured */ function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external { require(isAuthorized(contractAddress), "not authorized to configure contract"); governorMap[contractAddress] = _newGovernor; } // claim methods /** * @notice Claims yield for a specific contract. Called by an authorized user * @param contractAddress The address of the contract for which yield is to be claimed * @param recipientOfYield The address of the recipient of the yield * @param amount The amount of yield to be claimed * @return The amount of yield that was claimed */ function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256) { require(isAuthorized(contractAddress), "Not authorized to claim yield"); return IYield(YIELD_CONTRACT).claim(contractAddress, recipientOfYield, amount); } /** * @notice Claims all yield for a specific contract. Called by an authorized user * @param contractAddress The address of the contract for which all yield is to be claimed * @param recipientOfYield The address of the recipient of the yield * @return The amount of yield that was claimed */ function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256) { require(isAuthorized(contractAddress), "Not authorized to claim yield"); uint256 amount = IYield(YIELD_CONTRACT).getClaimableAmount(contractAddress); return IYield(YIELD_CONTRACT).claim(contractAddress, recipientOfYield, amount); } /** * @notice Claims all gas for a specific contract. Called by an authorized user * @param contractAddress The address of the contract for which all gas is to be claimed * @param recipientOfGas The address of the recipient of the gas * @return The amount of gas that was claimed */ function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256) { require(isAuthorized(contractAddress), "Not allowed to claim all gas"); return IGas(GAS_CONTRACT).claimAll(contractAddress, recipientOfGas); } /** * @notice Claims gas at a minimum claim rate for a specific contract, with error rate '1'. Called by an authorized user * @param contractAddress The address of the contract for which gas is to be claimed * @param recipientOfGas The address of the recipient of the gas * @param minClaimRateBips The minimum claim rate in basis points * @return The amount of gas that was claimed */ function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256) { require(isAuthorized(contractAddress), "Not allowed to claim gas at min claim rate"); return IGas(GAS_CONTRACT).claimGasAtMinClaimRate(contractAddress, recipientOfGas, minClaimRateBips); } /** * @notice Claims gas available to be claimed at max claim rate for a specific contract. Called by an authorized user * @param contractAddress The address of the contract for which maximum gas is to be claimed * @param recipientOfGas The address of the recipient of the gas * @return The amount of gas that was claimed */ function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256) { require(isAuthorized(contractAddress), "Not allowed to claim max gas"); return IGas(GAS_CONTRACT).claimMax(contractAddress, recipientOfGas); } /** * @notice Claims a specific amount of gas for a specific contract. claim rate governed by integral of gas over time * @param contractAddress The address of the contract for which gas is to be claimed * @param recipientOfGas The address of the recipient of the gas * @param gasToClaim The amount of gas to be claimed * @param gasSecondsToConsume The amount of gas seconds to consume * @return The amount of gas that was claimed */ function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256) { require(isAuthorized(contractAddress), "Not allowed to claim gas"); return IGas(GAS_CONTRACT).claim(contractAddress, recipientOfGas, gasToClaim, gasSecondsToConsume); } /** * @notice Reads the claimable yield for a specific contract * @param contractAddress The address of the contract for which the claimable yield is to be read * @return claimable yield */ function readClaimableYield(address contractAddress) public view returns (uint256) { return IYield(YIELD_CONTRACT).getClaimableAmount(contractAddress); } /** * @notice Reads the yield configuration for a specific contract * @param contractAddress The address of the contract for which the yield configuration is to be read * @return uint8 representing yield enum */ function readYieldConfiguration(address contractAddress) public view returns (uint8) { return IYield(YIELD_CONTRACT).getConfiguration(contractAddress); } /** * @notice Reads the gas parameters for a specific contract * @param contractAddress The address of the contract for which the gas parameters are to be read * @return uint256 representing the accumulated ether seconds * @return uint256 representing ether balance * @return uint256 representing last update timestamp * @return GasMode representing the gas mode (VOID, CLAIMABLE) */ function readGasParams(address contractAddress) public view returns (uint256, uint256, uint256, GasMode) { return IGas(GAS_CONTRACT).readGasParams(contractAddress); } }
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd. pragma solidity 0.8.15; import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { Semver } from "src/universal/Semver.sol"; enum GasMode { VOID, CLAIMABLE } interface IGas { function readGasParams(address contractAddress) external view returns (uint256, uint256, uint256, GasMode); function setGasMode(address contractAddress, GasMode mode) external; function claimGasAtMinClaimRate(address contractAddress, address recipient, uint256 minClaimRateBips) external returns (uint256); function claimAll(address contractAddress, address recipient) external returns (uint256); function claimMax(address contractAddress, address recipient) external returns (uint256); function claim(address contractAddress, address recipient, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256); } /// @custom:predeploy 0x4300000000000000000000000000000000000001 /// @title Gas contract Gas is IGas, Initializable, Semver { address public immutable admin; // Blast.sol --> controls all dAPP accesses to Gas.sol address public immutable blastConfigurationContract; // BaseFeeVault.sol -> fees from gas claims directed here address public immutable blastFeeVault; // zero claim rate in bps -> percent of gas user is able to claim // without consuming any gas seconds uint256 public zeroClaimRate; // bps // base claim rate in bps -> percent of gas user is able to claim // by consuming base gas seconds uint256 public baseGasSeconds; uint256 public baseClaimRate; // bps // ceil claim rate in bps -> percent of gas user is able to claim // by consuming ceil gas seconds or more uint256 public ceilGasSeconds; uint256 public ceilClaimRate; // bps /** * @notice Constructs the blast gas contract. * @param _admin The address of the admin. * @param _blastConfigurationContract The address of the Blast configuration contract. * @param _blastFeeVault The address of the Blast fee vault. */ constructor ( address _admin, address _blastConfigurationContract, address _blastFeeVault ) Semver(1, 0, 0) { admin = _admin; blastConfigurationContract = _blastConfigurationContract; blastFeeVault = _blastFeeVault; _disableInitializers(); } /** * @notice Initializer. * @param _zeroClaimRate The zero claim rate. * @param _baseGasSeconds The base gas seconds. * @param _baseClaimRate The base claim rate. * @param _ceilGasSeconds The ceiling gas seconds. * @param _ceilClaimRate The ceiling claim rate. */ function initialize( uint256 _zeroClaimRate, uint256 _baseGasSeconds, uint256 _baseClaimRate, uint256 _ceilGasSeconds, uint256 _ceilClaimRate ) public initializer { require(_zeroClaimRate < _baseClaimRate, "zero claim rate must be < base claim rate"); require(_baseClaimRate < _ceilClaimRate, "base claim rate must be < ceil claim rate"); require(_baseGasSeconds < _ceilGasSeconds, "base gas seconds must be < ceil gas seconds"); require(_baseGasSeconds > 0, "base gas seconds must be > 0"); require(_ceilClaimRate <= 10000, "ceil claim rate must be less than or equal to 10_000 bips"); // admin vars zeroClaimRate = _zeroClaimRate; baseGasSeconds = _baseGasSeconds; baseClaimRate = _baseClaimRate; ceilGasSeconds = _ceilGasSeconds; ceilClaimRate = _ceilClaimRate; } /** * @notice Allows only the admin to call a function */ modifier onlyAdmin() { require(msg.sender == admin, "Caller is not the admin"); _; } /** * @notice Allows only the Blast Configuration Contract to call a function */ modifier onlyBlastConfigurationContract() { require(msg.sender == blastConfigurationContract, "Caller must be blast configuration contract"); _; } /** * @notice Allows the admin to update the parameters * @param _zeroClaimRate The new zero claim rate * @param _baseGasSeconds The new base gas seconds * @param _baseClaimRate The new base claim rate * @param _ceilGasSeconds The new ceiling gas seconds * @param _ceilClaimRate The new ceiling claim rate */ function updateAdminParameters( uint256 _zeroClaimRate, uint256 _baseGasSeconds, uint256 _baseClaimRate, uint256 _ceilGasSeconds, uint256 _ceilClaimRate ) external onlyAdmin { require(_zeroClaimRate < _baseClaimRate, "zero claim rate must be < base claim rate"); require(_baseClaimRate < _ceilClaimRate, "base claim rate must be < ceil claim rate"); require(_baseGasSeconds < _ceilGasSeconds, "base gas seconds must be < ceil gas seconds"); require(_baseGasSeconds > 0, "base gas seconds must be > 0"); require(_ceilClaimRate <= 10000, "ceil claim rate must be less than or equal to 10_000 bips"); zeroClaimRate = _zeroClaimRate; baseGasSeconds = _baseGasSeconds; baseClaimRate = _baseClaimRate; ceilGasSeconds = _ceilGasSeconds; ceilClaimRate = _ceilClaimRate; } /** * @notice Allows the admin to claim the gas of any address * @param contractAddress The address of the contract * @return The amount of ether balance claimed */ function adminClaimGas(address contractAddress) external onlyAdmin returns (uint256) { (, uint256 etherBalance,,) = readGasParams(contractAddress); _updateGasParams(contractAddress, 0, 0, GasMode.VOID); SafeTransferLib.safeTransferETH(blastFeeVault, etherBalance); return etherBalance; } /** * @notice Allows an authorized user to set the gas mode for a contract via the BlastConfigurationContract * @param contractAddress The address of the contract * @param mode The new gas mode for the contract */ function setGasMode(address contractAddress, GasMode mode) external onlyBlastConfigurationContract { // retrieve gas params (uint256 etherSeconds, uint256 etherBalance,,) = readGasParams(contractAddress); _updateGasParams(contractAddress, etherSeconds, etherBalance, mode); } /** * @notice Allows a user to claim gas at a minimum claim rate (error = 1 bip) * @param contractAddress The address of the contract * @param recipientOfGas The address of the recipient of the gas * @param minClaimRateBips The minimum claim rate in basis points * @return The amount of gas claimed */ function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) public returns (uint256) { require(minClaimRateBips <= ceilClaimRate, "desired claim rate exceeds maximum"); (uint256 etherSeconds, uint256 etherBalance,,) = readGasParams(contractAddress); if (minClaimRateBips <= zeroClaimRate) { return claimAll(contractAddress, recipientOfGas); } // set minClaimRate to baseClaimRate in this case if (minClaimRateBips < baseClaimRate) { minClaimRateBips = baseClaimRate; } uint256 bipsDiff = minClaimRateBips - baseClaimRate; uint256 secondsDiff = ceilGasSeconds - baseGasSeconds; uint256 rateDiff = ceilClaimRate - baseClaimRate; uint256 minSecondsStaked = baseGasSeconds + Math.ceilDiv(bipsDiff * secondsDiff, rateDiff); uint256 maxEtherClaimable = etherSeconds / minSecondsStaked; if (maxEtherClaimable > etherBalance) { maxEtherClaimable = etherBalance; } uint256 secondsToConsume = maxEtherClaimable * minSecondsStaked; return claim(contractAddress, recipientOfGas, maxEtherClaimable, secondsToConsume); } /** * @notice Allows a contract to claim all gas * @param contractAddress The address of the contract * @param recipientOfGas The address of the recipient of the gas * @return The amount of gas claimed */ function claimAll(address contractAddress, address recipientOfGas) public returns (uint256) { (uint256 etherSeconds, uint256 etherBalance,,) = readGasParams(contractAddress); return claim(contractAddress, recipientOfGas, etherBalance, etherSeconds); } /** * @notice Allows a contract to claim all gas at the highest possible claim rate * @param contractAddress The address of the contract * @param recipientOfGas The address of the recipient of the gas * @return The amount of gas claimed */ function claimMax(address contractAddress, address recipientOfGas) public returns (uint256) { return claimGasAtMinClaimRate(contractAddress, recipientOfGas, ceilClaimRate); } /** * @notice Allows a contract to claim a specified amount of gas, at a claim rate set by the number of gas seconds * @param contractAddress The address of the contract * @param recipientOfGas The address of the recipient of the gas * @param gasToClaim The amount of gas to claim * @param gasSecondsToConsume The amount of gas seconds to consume * @return The amount of gas claimed (gasToClaim - penalty) */ function claim(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) public onlyBlastConfigurationContract() returns (uint256) { // retrieve gas params (uint256 etherSeconds, uint256 etherBalance,, GasMode mode) = readGasParams(contractAddress); // check validity requirements require(gasToClaim > 0, "must withdraw non-zero amount"); require(gasToClaim <= etherBalance, "too much to withdraw"); require(gasSecondsToConsume <= etherSeconds, "not enough gas seconds"); // get claim rate (uint256 claimRate, uint256 gasSecondsToConsumeNormalized) = getClaimRateBps(gasSecondsToConsume, gasToClaim); // calculate tax uint256 userEther = gasToClaim * claimRate / 10_000; uint256 penalty = gasToClaim - userEther; _updateGasParams(contractAddress, etherSeconds - gasSecondsToConsumeNormalized, etherBalance - gasToClaim, mode); SafeTransferLib.safeTransferETH(recipientOfGas, userEther); if (penalty > 0) { SafeTransferLib.safeTransferETH(blastFeeVault, penalty); } return userEther; } /** * @notice Calculates the claim rate in basis points based on gasSeconds, gasToClaim * @param gasSecondsToConsume The amount of gas seconds to consume * @param gasToClaim The amount of gas to claim * @return claimRate The calculated claim rate in basis points * @return gasSecondsToConsume The normalized gas seconds to consume (<= gasSecondsToConsume) */ function getClaimRateBps(uint256 gasSecondsToConsume, uint256 gasToClaim) public view returns (uint256, uint256) { uint256 secondsStaked = gasSecondsToConsume / gasToClaim; if (secondsStaked < baseGasSeconds) { return (zeroClaimRate, 0); } if (secondsStaked >= ceilGasSeconds) { uint256 gasToConsumeNormalized = gasToClaim * ceilGasSeconds; return (ceilClaimRate, gasToConsumeNormalized); } uint256 rateDiff = ceilClaimRate - baseClaimRate; uint256 secondsDiff = ceilGasSeconds - baseGasSeconds; uint256 secondsStakedDiff = secondsStaked - baseGasSeconds; uint256 additionalClaimRate = rateDiff * secondsStakedDiff / secondsDiff; uint256 claimRate = baseClaimRate + additionalClaimRate; return (claimRate, gasSecondsToConsume); } /** * @notice Reads the gas parameters for a given user * @param user The address of the user * @return etherSeconds The integral of ether over time (ether * seconds vested) * @return etherBalance The total ether balance for the user * @return lastUpdated The last updated timestamp for the user's gas parameters * @return mode The current gas mode for the user */ function readGasParams(address user) public view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode mode) { bytes32 paramsHash = keccak256(abi.encodePacked(user, "parameters")); bytes32 packedParams; // read params assembly { packedParams := sload(paramsHash) } // unpack params // - The first byte (most significant byte) represents the mode // - The next 12 bytes represent the etherBalance // - The following 15 bytes represent the etherSeconds // - The last 4 bytes (least significant bytes) represent the lastUpdated timestamp mode = GasMode(uint8(packedParams[0])); etherBalance = uint256((packedParams << (1 * 8)) >> ((32 - 12) * 8)); etherSeconds = uint256((packedParams << ((1 + 12) * 8)) >> ((32 - 15) * 8)); lastUpdated = uint256((packedParams << ((1 + 12 + 15) * 8)) >> ((32 - 4) * 8)); // update ether seconds etherSeconds = etherSeconds + etherBalance * (block.timestamp - lastUpdated); } /** * @notice Updates the gas parameters for a given contract address * @param contractAddress The address of the contract * @param etherSeconds The integral of ether over time (ether * seconds vested) * @param etherBalance The total ether balance for the contract */ function _updateGasParams(address contractAddress, uint256 etherSeconds, uint256 etherBalance, GasMode mode) internal { if ( etherBalance >= 1 << (12 * 8) || etherSeconds >= 1 << (15 * 8) ) { revert("Unexpected packing issue due to overflow"); } uint256 updatedTimestamp = block.timestamp; // Known to fit in 4 bytes bytes32 paramsHash = keccak256(abi.encodePacked(contractAddress, "parameters")); bytes32 packedParams; packedParams = ( (bytes32(uint256(mode)) << ((12 + 15 + 4) * 8)) | // Shift mode to the most significant byte (bytes32(etherBalance) << ((15 + 4) * 8)) | // Shift etherBalance to start after 1 byte of mode (bytes32(etherSeconds) << (4 * 8)) | // Shift etherSeconds to start after mode and etherBalance bytes32(updatedTimestamp) // Keep updatedTimestamp in the least significant bytes ); assembly { sstore(paramsHash, packedParams) } } }
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd. pragma solidity 0.8.15; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; import { SharesBase } from "src/L2/Shares.sol"; import { YieldMode } from "src/L2/Blast.sol"; import { ERC20PermitUpgradeable } from "src/L2/ERC20PermitUpgradeable.sol"; /// @custom:upgradeable /// @title ERC20Rebasing /// @notice ERC20 implementation with rebasing token balances. There are 3 yield /// modes with different rebasing behaviors. /// /// AUTOMATIC dynamically updates the balance as the share price increases. /// /// VOID fixes the balance and exempts the account from receiving yields. /// /// CLAIMABLE fixes the balance and allows the account to claim yields to /// another account. /// /// The child implementation is responsible for deciding how the share price is set. abstract contract ERC20Rebasing is ERC20PermitUpgradeable, SharesBase, IERC20 { /// @notice Number of decimals. uint8 public immutable decimals; /// @notice Name of the token. string public name; /// @notice Symbol of the token. string public symbol; /// @notice Mapping that stores the number of shares for each account. mapping(address => uint256) private _shares; /// @notice Total number of shares distributed. uint256 internal _totalShares; /// @notice Mapping that stores the number of remainder tokens for each account. mapping(address => uint256) private _remainders; /// @notice Mapping that stores the number of fixed tokens for each account. mapping(address => uint256) private _fixed; /// @notice Total number of non-rebasing tokens. uint256 internal _totalVoidAndRemainders; /// @notice Mapping that stores the configured yield mode for each account. mapping(address => YieldMode) private _yieldMode; /// @notice Mapping that stores the allowance for a given spender and operator pair. mapping(address => mapping(address => uint256)) private _allowances; /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades. /// A gap size of 41 was chosen here, so that the first slot used in a child contract /// would be a multiple of 50. uint256[41] private __gap; /// @notice Emitted when an account configures their yield mode. /// @param account Address of the account. /// @param yieldMode Yield mode that was configured. event Configure(address indexed account, YieldMode yieldMode); /// @notice Emitted when a CLAIMABLE account claims their yield. /// @param account Address of the account. /// @param recipient Address of the recipient. /// @param amount Amount of yield claimed. event Claim(address indexed account, address indexed recipient, uint256 amount); error InsufficientBalance(); error InsufficientAllowance(); error TransferFromZeroAddress(); error TransferToZeroAddress(); error ApproveFromZeroAddress(); error ApproveToZeroAddress(); error ClaimToZeroAddress(); error NotClaimableAccount(); /// @param _decimals Number of decimals. constructor(address _reporter, uint8 _decimals) SharesBase(_reporter) { decimals = _decimals; } /// @param _name Token name. /// @param _symbol Token symbol. /// @param _price Initial share price. function __ERC20Rebasing_init(string memory _name, string memory _symbol, uint256 _price) internal onlyInitializing { __ERC20Permit_init(_name); __SharesBase_init({ _price: _price }); name = _name; symbol = _symbol; } /// @inheritdoc SharesBase function count() public view override returns (uint256) { return _totalShares; } /// @notice --- ERC20 Interface --- /// @inheritdoc IERC20 function totalSupply() external view returns (uint256) { return price * _totalShares + _totalVoidAndRemainders; } /// @inheritdoc IERC20 function balanceOf(address account) public view virtual returns (uint256 value) { YieldMode yieldMode = _yieldMode[account]; if (yieldMode == YieldMode.AUTOMATIC) { value = _computeShareValue(_shares[account], _remainders[account]); } else { value = _fixed[account]; } } /// @inheritdoc IERC20 function allowance(address owner, address spender) public view virtual returns (uint256) { return _allowances[owner][spender]; } /// @inheritdoc IERC20 function transfer(address to, uint256 amount) public virtual returns (bool) { _transfer(msg.sender, to, amount); return true; } /// @inheritdoc IERC20 function approve(address spender, uint256 amount) public virtual returns (bool) { address owner = msg.sender; _approve(owner, spender, amount); return true; } /// @inheritdoc IERC20 function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { _spendAllowance(from, msg.sender, amount); _transfer(from, to, amount); return true; } /// @notice --- Blast Interface --- /// @notice Query an account's configured yield mode. /// @param account Address to query the configuration. /// @return Configured yield mode. function getConfiguration(address account) public view returns (YieldMode) { return _yieldMode[account]; } /// @notice Query an CLAIMABLE account's claimable yield. /// @param account Address to query the claimable amount. /// @return amount Claimable amount. function getClaimableAmount(address account) public view returns (uint256) { if (getConfiguration(account) != YieldMode.CLAIMABLE) { revert NotClaimableAccount(); } uint256 shareValue = _computeShareValue(_shares[account], _remainders[account]); return shareValue - _fixed[account]; } /// @notice Claim yield from a CLAIMABLE account and send to /// a recipient. /// @param recipient Address to receive the claimed balance. /// @param amount Amount to claim. /// @return Amount claimed. function claim(address recipient, uint256 amount) external returns (uint256) { address account = msg.sender; if (recipient == address(0)) { revert ClaimToZeroAddress(); } if (getConfiguration(account) != YieldMode.CLAIMABLE) { revert NotClaimableAccount(); } uint256 shareValue = _computeShareValue(_shares[account], _remainders[account]); uint256 claimableAmount = shareValue - _fixed[account]; if (amount > claimableAmount) { revert InsufficientBalance(); } (uint256 newShares, uint256 newRemainder) = _computeSharesAndRemainder(shareValue - amount); _updateBalance(account, newShares, newRemainder, _fixed[account]); _deposit(recipient, amount); emit Claim(msg.sender, recipient, amount); return amount; } /// @notice Change the yield mode of the caller and update the /// balance to reflect the configuration. /// @param yieldMode Yield mode to configure /// @return Current user balance function configure(YieldMode yieldMode) external returns (uint256) { _configure(msg.sender, yieldMode); emit Configure(msg.sender, yieldMode); return balanceOf(msg.sender); } /// @notice Moves `amount` of tokens from `from` to `to`. /// @param from Address of the sender. /// @param to Address of the recipient. /// @param amount Amount of tokens to send. function _transfer( address from, address to, uint256 amount ) internal virtual { if (from == address(0)) revert TransferFromZeroAddress(); if (to == address(0)) revert TransferToZeroAddress(); _withdraw(from, amount); _deposit(to, amount); emit Transfer(from, to, amount); } /// @notice Sets `amount` as the allowance of `spender` over the `owner` s tokens. /// @param owner Address of the owner. /// @param spender Address of the spender. /// @param amount Amount of tokens to approve. function _approve( address owner, address spender, uint256 amount ) internal override { if (owner == address(0)) revert ApproveFromZeroAddress(); if (spender == address(0)) revert ApproveToZeroAddress(); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /// @notice Updates `owner` s allowance for `spender` based on spent `amount`. /// @param owner Address of the owner. /// @param spender Address of the spender. /// @param amount Amount of tokens to spender. function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { if (amount > currentAllowance) revert InsufficientAllowance(); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /// @notice Deposit to an account. /// @param account Address of the account to deposit to. /// @param amount Amount to deposit to the account. function _deposit(address account, uint256 amount) internal { uint256 balanceAfter = balanceOf(account) + amount; _setBalance(account, balanceAfter, false); /// If the user is configured as VOID, then the amount /// is added to the total voided funds. YieldMode yieldMode = getConfiguration(account); if (yieldMode == YieldMode.VOID) { _totalVoidAndRemainders += amount; } } /// @notice Withdraw from an account. /// @param account Address of the account to withdraw from. /// @param amount Amount to withdraw to the account. function _withdraw(address account, uint256 amount) internal { uint256 balance = balanceOf(account); if (amount > balance) { revert InsufficientBalance(); } unchecked { _setBalance(account, balance - amount, false); } /// If the user is configured as VOID, then the amount /// is deducted from the total voided funds. YieldMode yieldMode = getConfiguration(account); if (yieldMode == YieldMode.VOID) { _totalVoidAndRemainders -= amount; } } /// @notice Configures a new yield mode for an account and updates /// the balance storage to reflect the change. /// @param account Address of the account to configure. /// @param newYieldMode New yield mode to configure. function _configure(address account, YieldMode newYieldMode) internal { YieldMode prevYieldMode = getConfiguration(account); uint256 balance; if (prevYieldMode == YieldMode.CLAIMABLE) { /// If the balance is claimable, we need to use their share balance so they /// don't lose their claimable yield. balance = _computeShareValue(_shares[account], _remainders[account]); } else { balance = balanceOf(account); } _yieldMode[account] = newYieldMode; uint256 prevFixed = _fixed[account]; _setBalance(account, balance, true); /// If the previous yield mode was VOID, then the amount /// is deducted from the total voided funds. if (prevYieldMode == YieldMode.VOID) { _totalVoidAndRemainders -= prevFixed; } /// If the new yield mode is VOID, then the amount /// is added to the total voided funds. if (newYieldMode == YieldMode.VOID) { _totalVoidAndRemainders += balance; } } /// @notice Sets the balance of an account according to its yield mode /// configuration. /// @param account Address of the account to set the balance of. /// @param amount Balance to set for the account. /// @param resetClaimable If the account is CLAIMABLE, true if the share /// balance should be set to the amount. Should only be true when /// configuring the account. function _setBalance(address account, uint256 amount, bool resetClaimable) internal { uint256 newShares; uint256 newRemainder; uint256 newFixed; YieldMode yieldMode = getConfiguration(account); if (yieldMode == YieldMode.AUTOMATIC) { (newShares, newRemainder) = _computeSharesAndRemainder(amount); } else if (yieldMode == YieldMode.VOID) { newFixed = amount; } else if (yieldMode == YieldMode.CLAIMABLE) { newFixed = amount; uint256 shareValue = amount; if (!resetClaimable) { /// In order to not reset the claimable balance, we have to compute /// the user's current share balance and add or subtract the change in /// fixed balance before computing the new shares balance parameters. shareValue = _computeShareValue(_shares[account], _remainders[account]); shareValue = shareValue + amount - _fixed[account]; } (newShares, newRemainder) = _computeSharesAndRemainder(shareValue); } _updateBalance(account, newShares, newRemainder, newFixed); } /// @notice Update the balance parameters of an account and appropriately refresh the global sums /// to reflect the change of allocation. /// @param account Address of account to update. /// @param newShares New shares value for account. /// @param newRemainder New remainder value for account. /// @param newFixed New fixed value for account. function _updateBalance(address account, uint256 newShares, uint256 newRemainder, uint256 newFixed) internal { _totalShares = _totalShares + newShares - _shares[account]; _totalVoidAndRemainders = _totalVoidAndRemainders + newRemainder - _remainders[account]; _shares[account] = newShares; _remainders[account] = newRemainder; _fixed[account] = newFixed; } /// @notice Convert nominal value to number of shares with remainder. /// @param value Amount to convert to shares (wad). /// @return shares Number of shares (wad), remainder Remainder (wad). function _computeSharesAndRemainder(uint256 value) internal view returns (uint256 shares, uint256 remainder) { if (price == 0) { remainder = value; } else { shares = value / price; remainder = value % price; } } /// @notice Compute nominal value from number of shares. /// @param shares Number of shares (wad). /// @param remainders Amount of remainder (wad). /// @return value (wad). function _computeShareValue(uint256 shares, uint256 remainders) internal view returns (uint256) { return price * shares + remainders; } /** * @dev The name parameter for the EIP712 domain. */ function _EIP712Name() internal override view returns (string memory) { return name; } }
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd. pragma solidity 0.8.15; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { Semver } from "src/universal/Semver.sol"; import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { Blast, YieldMode, GasMode } from "src/L2/Blast.sol"; /// @custom:predeploy 0x4300000000000000000000000000000000000000 /// @title SharesBase /// @notice Base contract to track share rebasing and yield reporting. abstract contract SharesBase is Initializable { /// @notice Approved yield reporter. address public immutable REPORTER; /// @notice Share price. This value can only increase. uint256 public price; /// @notice Accumulated yield that has not been distributed /// to the share price. uint256 public pending; /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades. /// A gap size of 48 was chosen here, so that the first slot used in a child contract /// would be a multiple of 50. uint256[48] private __gap; /// @notice Emitted when a new share price is set after a yield event. event NewPrice(uint256 price); error InvalidReporter(); error DistributeFailed(uint256 count, uint256 pending); error PriceIsInitialized(); /// @param _reporter Address of the approved yield reporter. constructor(address _reporter) { REPORTER = _reporter; } /// @notice Initializer. /// @param _price Initial share price. // solhint-disable-next-line func-name-mixedcase function __SharesBase_init(uint256 _price) internal onlyInitializing { if (price != 0) { revert PriceIsInitialized(); } price = _price; } /// @notice Get the total number of shares. Needs to be /// overridden by the child contract. /// @return Total number of shares. function count() public view virtual returns (uint256); /// @notice Report a yield event and update the share price. /// @param value Amount of new yield function addValue(uint256 value) external { _addValue(value); } function _addValue(uint256 value) internal virtual { if (AddressAliasHelper.undoL1ToL2Alias(msg.sender) != REPORTER) { revert InvalidReporter(); } if (value > 0) { pending += value; } _tryDistributePending(); } /// @notice Attempt to distribute pending yields if there /// are sufficient pending yields to increase the /// share price. /// @return True if there were sufficient pending yields to /// increase the share price. function _tryDistributePending() internal returns (bool) { if (pending < count() || count() == 0) { return false; } price += pending / count(); pending = pending % count(); emit NewPrice(price); return true; } } /// @custom:predeploy 0x4300000000000000000000000000000000000000 /// @title Shares /// @notice Integrated EVM contract to manage native ether share /// rebasing from yield reports. contract Shares is SharesBase, Semver { /// @notice Total number of shares. This value is modified directly /// by the sequencer EVM. uint256 private _count; /// @notice _reporter Address of approved yield reporter. constructor(address _reporter) SharesBase(_reporter) Semver(1, 0, 0) { _disableInitializers(); } /// @notice Initializer. function initialize(uint256 _price) public initializer { __SharesBase_init({ _price: _price }); Blast(Predeploys.BLAST).configureContract( address(this), YieldMode.VOID, GasMode.VOID, address(0xdead) /// don't set a governor ); } /// @inheritdoc SharesBase function count() public view override returns (uint256) { return _count; } function _addValue(uint256 value) internal override { super._addValue(value); SharesBase(Predeploys.WETH_REBASING).addValue(value); } }
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd. pragma solidity ^0.8.0; /// @title Predeploys /// @notice Contains constant addresses for contracts that are pre-deployed to the L2 system. library Predeploys { /// @notice Address of the L2ToL1MessagePasser predeploy. address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000016; /// @notice Address of the L2CrossDomainMessenger predeploy. address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007; /// @notice Address of the L2StandardBridge predeploy. address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010; /// @notice Address of the L2ERC721Bridge predeploy. address internal constant L2_ERC721_BRIDGE = 0x4200000000000000000000000000000000000014; //// @notice Address of the SequencerFeeWallet predeploy. address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011; /// @notice Address of the OptimismMintableERC20Factory predeploy. address internal constant OPTIMISM_MINTABLE_ERC20_FACTORY = 0x4200000000000000000000000000000000000012; /// @notice Address of the OptimismMintableERC721Factory predeploy. address internal constant OPTIMISM_MINTABLE_ERC721_FACTORY = 0x4200000000000000000000000000000000000017; /// @notice Address of the L1Block predeploy. address internal constant L1_BLOCK_ATTRIBUTES = 0x4200000000000000000000000000000000000015; /// @notice Address of the GasPriceOracle predeploy. Includes fee information /// and helpers for computing the L1 portion of the transaction fee. address internal constant GAS_PRICE_ORACLE = 0x420000000000000000000000000000000000000F; /// @custom:legacy /// @notice Address of the L1MessageSender predeploy. Deprecated. Use L2CrossDomainMessenger /// or access tx.origin (or msg.sender) in a L1 to L2 transaction instead. address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001; /// @custom:legacy /// @notice Address of the DeployerWhitelist predeploy. No longer active. address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002; /// @custom:legacy /// @notice Address of the LegacyERC20ETH predeploy. Deprecated. Balances are migrated to the /// state trie as of the Bedrock upgrade. Contract has been locked and write functions /// can no longer be accessed. address internal constant LEGACY_ERC20_ETH = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000; /// @custom:legacy /// @notice Address of the L1BlockNumber predeploy. Deprecated. Use the L1Block predeploy /// instead, which exposes more information about the L1 state. address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013; /// @custom:legacy /// @notice Address of the LegacyMessagePasser predeploy. Deprecate. Use the updated /// L2ToL1MessagePasser contract instead. address internal constant LEGACY_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000; /// @notice Address of the ProxyAdmin predeploy. address internal constant PROXY_ADMIN = 0x4200000000000000000000000000000000000018; /// @notice Address of the BaseFeeVault predeploy. address internal constant BASE_FEE_VAULT = 0x4200000000000000000000000000000000000019; /// @notice Address of the L1FeeVault predeploy. address internal constant L1_FEE_VAULT = 0x420000000000000000000000000000000000001A; /// @notice Address of the GovernanceToken predeploy. address internal constant GOVERNANCE_TOKEN = 0x4200000000000000000000000000000000000042; /// @notice Address of the SchemaRegistry predeploy. address internal constant SCHEMA_REGISTRY = 0x4200000000000000000000000000000000000020; /// @notice Address of the EAS predeploy. address internal constant EAS = 0x4200000000000000000000000000000000000021; /// @notice Address of the Shares predeploy. address internal constant SHARES = 0x4300000000000000000000000000000000000000; /// @notice Address of the Gas predeploy. address internal constant GAS = 0x4300000000000000000000000000000000000001; /// @notice Address of the Blast predeploy. address internal constant BLAST = 0x4300000000000000000000000000000000000002; /// @notice Address of the USDB predeploy. address internal constant USDB = 0x4300000000000000000000000000000000000003; /// @notice Address of the WETH predeploy. address internal constant WETH_REBASING = 0x4300000000000000000000000000000000000004; /// @notice Address of the L2BlastBridge predeploy. address internal constant L2_BLAST_BRIDGE = 0x4300000000000000000000000000000000000005; }
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd. pragma solidity ^0.8.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; /// @title Semver /// @notice Semver is a simple contract for managing contract versions. contract Semver { /// @notice Contract version number (major). uint256 private immutable MAJOR_VERSION; /// @notice Contract version number (minor). uint256 private immutable MINOR_VERSION; /// @notice Contract version number (patch). uint256 private immutable PATCH_VERSION; /// @param _major Version number (major). /// @param _minor Version number (minor). /// @param _patch Version number (patch). constructor(uint256 _major, uint256 _minor, uint256 _patch) { MAJOR_VERSION = _major; MINOR_VERSION = _minor; PATCH_VERSION = _patch; } /// @notice Returns the full semver contract version. /// @return Semver contract version as a string. function version() public view returns (string memory) { return string( abi.encodePacked( Strings.toString(MAJOR_VERSION), ".", Strings.toString(MINOR_VERSION), ".", Strings.toString(PATCH_VERSION) ) ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _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 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _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() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @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 { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; assembly { // We'll write our calldata to this slot below, but restore it later. let memPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(4, from) // Append the "from" argument. mstore(36, to) // Append the "to" argument. mstore(68, amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because that's the total length of our calldata (4 + 32 * 3) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. call(gas(), token, 0, 0, 100, 0, 32) ) mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, memPointer) // Restore the memPointer. } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // We'll write our calldata to this slot below, but restore it later. let memPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(0, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(4, to) // Append the "to" argument. mstore(36, amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because that's the total length of our calldata (4 + 32 * 2) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. call(gas(), token, 0, 0, 68, 0, 32) ) mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, memPointer) // Restore the memPointer. } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // We'll write our calldata to this slot below, but restore it later. let memPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(0, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(4, to) // Append the "to" argument. mstore(36, amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because that's the total length of our calldata (4 + 32 * 2) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. call(gas(), token, 0, 0, 68, 0, 32) ) mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, memPointer) // Restore the memPointer. } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 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. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`. // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`. // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a // good first aproximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1; uint256 x = a; if (x >> 128 > 0) { x >>= 128; result <<= 64; } if (x >> 64 > 0) { x >>= 64; result <<= 32; } if (x >> 32 > 0) { x >>= 32; result <<= 16; } if (x >> 16 > 0) { x >>= 16; result <<= 8; } if (x >> 8 > 0) { x >>= 8; result <<= 4; } if (x >> 4 > 0) { x >>= 4; result <<= 2; } if (x >> 2 > 0) { result <<= 1; } // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { uint256 result = sqrt(a); if (rounding == Rounding.Up && result * result < a) { result += 1; } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: BSL 1.1 - Copyright 2024 MetaLayer Labs Ltd. // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC20Permit.sol) pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ * * @custom:storage-size 51 */ abstract contract ERC20PermitUpgradeable is Initializable, IERC20PermitUpgradeable, EIP712Upgradeable { using CountersUpgradeable for CountersUpgradeable.Counter; mapping(address => CountersUpgradeable.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`. * However, to ensure consistency with the upgradeable transpiler, we will continue * to reserve a slot. * @custom:oz-renamed-from _PERMIT_TYPEHASH */ // solhint-disable-next-line var-name-mixedcase bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT; /** * @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 ERC20 token name. */ function __ERC20Permit_init(string memory name) internal onlyInitializing { __EIP712_init_unchained(name, "1"); } function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {} /** * @dev See {IERC20Permit-permit}. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSAUpgradeable.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { CountersUpgradeable.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } /** * @dev See {ERC20-_approve}. */ function _approve( address owner, address spender, uint256 amount ) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: Apache-2.0 /* * Copyright 2019-2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ pragma solidity ^0.8.0; library AddressAliasHelper { uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); /// @notice Utility function that converts the address in the L1 that submitted a tx to /// the inbox to the msg.sender viewed in the L2 /// @param l1Address the address in the L1 that triggered the tx to L2 /// @return l2Address L2 address as viewed in msg.sender function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { unchecked { l2Address = address(uint160(l1Address) + offset); } } /// @notice Utility function that converts the msg.sender viewed in the L2 to the /// address in the L1 that submitted a tx to the inbox /// @param l2Address L2 address as viewed in msg.sender /// @return l1Address the address in the L1 that triggered the tx to L2 function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) { unchecked { l1Address = address(uint160(l2Address) - offset); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 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_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); 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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @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, it is bubbled up by this * function (like regular Solidity function calls). * * 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. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @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`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` 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 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @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]. */ 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 v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../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}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => 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. */ 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 { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override 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 override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override 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 `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` 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 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `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. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` 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. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../StringsUpgradeable.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSAUpgradeable { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode 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 {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] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode 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 {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); 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. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // 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); } // 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); } return (signer, RecoverError.NoError); } /** * @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) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "./ECDSAUpgradeable.sol"; import "../../interfaces/IERC5267Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic 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 their contracts 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. * * _Available since v3.4._ * * @custom:storage-size 52 */ abstract contract EIP712Upgradeable is Initializable, IERC5267Upgradeable { bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// @custom:oz-renamed-from _HASHED_NAME bytes32 private _hashedName; /// @custom:oz-renamed-from _HASHED_VERSION bytes32 private _hashedVersion; string private _name; string private _version; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP712_init(string memory name, string memory version) internal onlyInitializing { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { _name = name; _version = version; // Reset prior values in storage if upgrading _hashedName = 0; _hashedVersion = 0; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(); } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized // and the EIP712 domain is not reliable, as it will be missing name and version. require(_hashedName == 0 && _hashedVersion == 0, "EIP712: Uninitialized"); return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Name() internal virtual view returns (string memory) { return _name; } /** * @dev The version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Version() internal virtual view returns (string memory) { return _version; } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. */ function _EIP712NameHash() internal view returns (bytes32) { string memory name = _EIP712Name(); if (bytes(name).length > 0) { return keccak256(bytes(name)); } else { // If the name is empty, the contract may have been upgraded without initializing the new storage. // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. bytes32 hashedName = _hashedName; if (hashedName != 0) { return hashedName; } else { return keccak256(""); } } } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. */ function _EIP712VersionHash() internal view returns (bytes32) { string memory version = _EIP712Version(); if (bytes(version).length > 0) { return keccak256(bytes(version)); } else { // If the version is empty, the contract may have been upgraded without initializing the new storage. // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. bytes32 hashedVersion = _hashedVersion; if (hashedVersion != 0) { return hashedVersion; } else { return keccak256(""); } } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[48] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library CountersUpgradeable { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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 amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` 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 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @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 v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../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; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; import "./math/SignedMathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.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, MathUpgradeable.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) { 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] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267Upgradeable { /** * @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 v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv 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. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMathUpgradeable { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
{ "remappings": [ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@rari-capital/solmate/=lib/solmate/", "@cwia/=lib/clones-with-immutable-args/src/", "forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "safe-contracts/=lib/safe-contracts/contracts/", "clones-with-immutable-args/=lib/clones-with-immutable-args/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApproveFromZeroAddress","type":"error"},{"inputs":[],"name":"ApproveToZeroAddress","type":"error"},{"inputs":[],"name":"ClaimToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"uint256","name":"pending","type":"uint256"}],"name":"DistributeFailed","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidReporter","type":"error"},{"inputs":[],"name":"NotClaimableAccount","type":"error"},{"inputs":[],"name":"PriceIsInitialized","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"enum YieldMode","name":"yieldMode","type":"uint8"}],"name":"Configure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"NewPrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"addValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum YieldMode","name":"yieldMode","type":"uint8"}],"name":"configure","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getClaimableAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getConfiguration","outputs":[{"internalType":"enum YieldMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pending","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
61012060405234801561001157600080fd5b50604360981b608052601260a052600160c052600060e08190526101005261003761003c565b6100fb565b600054610100900460ff16156100a85760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146100f9576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60805160a05160c05160e05161010051612271620001476000396000610827015260006107fe015260006107d5015260006102e5015260008181610395015261148001526122716000f3fe6080604052600436106101a05760003560e01c80637ae556b5116100ec578063aad3ec961161008a578063d505accf11610064578063d505accf146104cc578063dd62ed3e146104ec578063e12f3a6114610532578063e20ccec31461055257600080fd5b8063aad3ec9614610477578063c44b11f714610497578063d0e30db0146104c457600080fd5b806384b0196e116100c657806384b0196e1461040457806395d89b411461042c578063a035b1fe14610441578063a9059cbb1461045757600080fd5b80637ae556b5146103835780637ecebe00146103cf5780638129fc1c146103ef57600080fd5b80632e1a7d4d116101595780633644e515116101335780633644e5151461031957806354fd4d501461032e5780635b9af12b1461034357806370a082311461036357600080fd5b80632e1a7d4d1461027f57806330adf81f1461029f578063313ce567146102d357600080fd5b806306661abd146101b457806306fdde03146101d8578063095ea7b3146101fa57806318160ddd1461022a5780631a33757d1461023f57806323b872dd1461025f57600080fd5b366101af576101ad610568565b005b600080fd5b3480156101c057600080fd5b50609d545b6040519081526020015b60405180910390f35b3480156101e457600080fd5b506101ed6105b9565b6040516101cf9190611cd7565b34801561020657600080fd5b5061021a610215366004611d06565b610647565b60405190151581526020016101cf565b34801561023657600080fd5b506101c5610661565b34801561024b57600080fd5b506101c561025a366004611d30565b610685565b34801561026b57600080fd5b5061021a61027a366004611d51565b6106db565b34801561028b57600080fd5b506101ad61029a366004611d8d565b6106fd565b3480156102ab57600080fd5b506101c57f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b3480156102df57600080fd5b506103077f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016101cf565b34801561032557600080fd5b506101c56107c4565b34801561033a57600080fd5b506101ed6107ce565b34801561034f57600080fd5b506101ad61035e366004611d8d565b610871565b34801561036f57600080fd5b506101c561037e366004611da6565b61087d565b34801561038f57600080fd5b506103b77f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101cf565b3480156103db57600080fd5b506101c56103ea366004611da6565b610909565b3480156103fb57600080fd5b506101ad610927565b34801561041057600080fd5b50610419610b4a565b6040516101cf9796959493929190611dc1565b34801561043857600080fd5b506101ed610be8565b34801561044d57600080fd5b506101c560685481565b34801561046357600080fd5b5061021a610472366004611d06565b610bf5565b34801561048357600080fd5b506101c5610492366004611d06565b610c0b565b3480156104a357600080fd5b506104b76104b2366004611da6565b610d87565b6040516101cf9190611e81565b6101ad610568565b3480156104d857600080fd5b506101ad6104e7366004611e8f565b610da5565b3480156104f857600080fd5b506101c5610507366004611f02565b6001600160a01b03918216600090815260a26020908152604080832093909416825291909152205490565b34801561053e57600080fd5b506101c561054d366004611da6565b610f09565b34801561055e57600080fd5b506101c560695481565b336105738134610fa0565b806001600160a01b03167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040516105ae91815260200190565b60405180910390a250565b609a80546105c690611f35565b80601f01602080910402602001604051908101604052809291908181526020018280546105f290611f35565b801561063f5780601f106106145761010080835404028352916020019161063f565b820191906000526020600020905b81548152906001019060200180831161062257829003601f168201915b505050505081565b600033610655818585611008565b60019150505b92915050565b600060a054609d546068546106769190611f7f565b6106809190611f9e565b905090565b600061069133836110b8565b336001600160a01b03167fcaa97ab28bae75adcb5a02786c64b44d0d3139aa521bf831cdfbe280ef246e36836040516106ca9190611e81565b60405180910390a261065b3361087d565b60006106e88433846111ea565b6106f3848484611247565b5060019392505050565b3361070881836112ee565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114610755576040519150601f19603f3d011682016040523d82523d6000602084013e61075a565b606091505b505090508061077c5760405163b12d13eb60e01b815260040160405180910390fd5b816001600160a01b03167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65846040516107b791815260200190565b60405180910390a2505050565b6000610680611362565b60606107f97f000000000000000000000000000000000000000000000000000000000000000061136c565b6108227f000000000000000000000000000000000000000000000000000000000000000061136c565b61084b7f000000000000000000000000000000000000000000000000000000000000000061136c565b60405160200161085d93929190611fb6565b604051602081830303815290604052905090565b61087a81611475565b50565b6001600160a01b038116600090815260a1602052604081205460ff16818160028111156108ac576108ac611e57565b036108e7576001600160a01b0383166000908152609c6020908152604080832054609e909252909120546108e09190611531565b9150610903565b6001600160a01b0383166000908152609f602052604090205491505b50919050565b6001600160a01b03811660009081526035602052604081205461065b565b600054610100900460ff16158080156109475750600054600160ff909116105b806109615750303b158015610961575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b610a9d6040518060400160405280600d81526020016c2bb930b83832b21022ba3432b960991b815250604051806040016040528060048152602001630ae8aa8960e31b815250604360981b6001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a989190612010565b61154c565b60405163099005e760e31b81526002604360981b0190634c802f3890610ad0903090600090819061dead90600401612029565b600060405180830381600087803b158015610aea57600080fd5b505af1158015610afe573d6000803e3d6000fd5b50505050801561087a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6000606080600080600060606001546000801b148015610b6a5750600254155b610bae5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064016109c0565b610bb661159e565b610bbe611630565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b609b80546105c690611f35565b6000610c02338484611247565b50600192915050565b6000336001600160a01b038416610c355760405163088d6c0d60e31b815260040160405180910390fd5b6002610c4082610d87565b6002811115610c5157610c51611e57565b14610c6f5760405163ebf953c760e01b815260040160405180910390fd5b6001600160a01b0381166000908152609c6020908152604080832054609e909252822054610c9d9190611531565b6001600160a01b0383166000908152609f602052604081205491925090610cc49083612086565b905080851115610ce757604051631e9acf1760e31b815260040160405180910390fd5b600080610cfc610cf78886612086565b61163a565b91509150610d31858383609f60008a6001600160a01b03166001600160a01b031681526020019081526020016000205461166f565b610d3b8888610fa0565b6040518781526001600160a01b0389169033907f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd9870689060200160405180910390a350949695505050505050565b6001600160a01b0316600090815260a1602052604090205460ff1690565b83421115610df55760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016109c0565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e248c61170b565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610e7f82611731565b90506000610e8f8287878761175e565b9050896001600160a01b0316816001600160a01b031614610ef25760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016109c0565b610efd8a8a8a611008565b50505050505050505050565b60006002610f1683610d87565b6002811115610f2757610f27611e57565b14610f455760405163ebf953c760e01b815260040160405180910390fd5b6001600160a01b0382166000908152609c6020908152604080832054609e909252822054610f739190611531565b6001600160a01b0384166000908152609f6020526040902054909150610f999082612086565b9392505050565b600081610fac8461087d565b610fb69190611f9e565b9050610fc483826000611786565b6000610fcf84610d87565b90506001816002811115610fe557610fe5611e57565b03611002578260a06000828254610ffc9190611f9e565b90915550505b50505050565b6001600160a01b03831661102f5760405163eb3b083560e01b815260040160405180910390fd5b6001600160a01b0382166110565760405163076e33c360e31b815260040160405180910390fd5b6001600160a01b03838116600081815260a2602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006110c383610d87565b9050600060028260028111156110db576110db611e57565b03611116576001600160a01b0384166000908152609c6020908152604080832054609e9092529091205461110f9190611531565b9050611122565b61111f8461087d565b90505b6001600160a01b038416600090815260a160205260409020805484919060ff1916600183600281111561115757611157611e57565b02179055506001600160a01b0384166000908152609f602052604090205461118185836001611786565b600183600281111561119557611195611e57565b036111b2578060a060008282546111ac9190612086565b90915550505b60018460028111156111c6576111c6611e57565b036111e3578160a060008282546111dd9190611f9e565b90915550505b5050505050565b6001600160a01b03838116600090815260a260209081526040808320938616835292905220546000198114611002578082111561123a576040516313be252b60e01b815260040160405180910390fd5b6110028484848403611008565b6001600160a01b03831661126e57604051630b07e54560e11b815260040160405180910390fd5b6001600160a01b03821661129557604051633a954ecd60e21b815260040160405180910390fd5b61129f83826112ee565b6112a98282610fa0565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516110ab91815260200190565b60006112f98361087d565b90508082111561131c57604051631e9acf1760e31b815260040160405180910390fd5b61132a838383036000611786565b600061133584610d87565b9050600181600281111561134b5761134b611e57565b03611002578260a06000828254610ffc9190612086565b600061068061188d565b6060816000036113935750506040805180820190915260018152600360fc1b602082015290565b8160005b81156113bd57806113a78161209d565b91506113b69050600a836120cc565b9150611397565b60008167ffffffffffffffff8111156113d8576113d8612070565b6040519080825280601f01601f191660200182016040528015611402576020820181803683370190505b5090505b841561146d57611417600183612086565b9150611424600a866120e0565b61142f906030611f9e565b60f81b818381518110611444576114446120f4565b60200101906001600160f81b031916908160001a905350611466600a866120cc565b9450611406565b949350505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146114be57604051631d73770560e11b815260040160405180910390fd5b6000609d546068546114d09190611f7f565b9050600060a05482476114e39190612086565b6114ed9190612086565b9050609d548110806114ff5750609d54155b1561150957505050565b609d5461151690826120cc565b606860008282546115279190611f9e565b9091555050505050565b600081836068546115429190611f7f565b610f999190611f9e565b600054610100900460ff166115735760405162461bcd60e51b81526004016109c09061210a565b61157c83611901565b6115858161194b565b609a61159184826121a4565b50609b61100283826121a4565b6060609a80546115ad90611f35565b80601f01602080910402602001604051908101604052809291908181526020018280546115d990611f35565b80156116265780601f106115fb57610100808354040283529160200191611626565b820191906000526020600020905b81548152906001019060200180831161160957829003601f168201915b5050505050905090565b60606106806107ce565b60008060685460000361164b575091565b60685461165890846120cc565b91506068548361166891906120e0565b9050915091565b6001600160a01b0384166000908152609c6020526040902054609d54611696908590611f9e565b6116a09190612086565b609d556001600160a01b0384166000908152609e602052604090205460a0546116ca908490611f9e565b6116d49190612086565b60a0556001600160a01b039093166000908152609c6020908152604080832094909455609e815283822092909255609f9091522055565b6001600160a01b0381166000908152603560205260409020805460018101825590610903565b600061065b61173e611362565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600061176f87878787611998565b9150915061177c81611a5c565b5095945050505050565b60008060008061179587610d87565b905060008160028111156117ab576117ab611e57565b036117c3576117b98661163a565b9094509250611878565b60018160028111156117d7576117d7611e57565b036117e457859150611878565b60028160028111156117f8576117f8611e57565b03611878578591508185611868576001600160a01b0388166000908152609c6020908152604080832054609e909252909120546118359190611531565b6001600160a01b0389166000908152609f602052604090205490915061185b8883611f9e565b6118659190612086565b90505b6118718161163a565b9095509350505b6118848785858561166f565b50505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6118b8611ba6565b6118c0611bff565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600054610100900460ff166119285760405162461bcd60e51b81526004016109c09061210a565b61087a81604051806040016040528060018152602001603160f81b815250611c30565b600054610100900460ff166119725760405162461bcd60e51b81526004016109c09061210a565b606854156119935760405163131cb46d60e21b815260040160405180910390fd5b606855565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156119cf5750600090506003611a53565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611a23573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611a4c57600060019250925050611a53565b9150600090505b94509492505050565b6000816004811115611a7057611a70611e57565b03611a785750565b6001816004811115611a8c57611a8c611e57565b03611ad95760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016109c0565b6002816004811115611aed57611aed611e57565b03611b3a5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016109c0565b6003816004811115611b4e57611b4e611e57565b0361087a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016109c0565b600080611bb161159e565b805190915015611bc8578051602090910120919050565b6001548015611bd75792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b600080611c0a611630565b805190915015611c21578051602090910120919050565b6002548015611bd75792915050565b600054610100900460ff16611c575760405162461bcd60e51b81526004016109c09061210a565b6003611c6383826121a4565b506004611c7082826121a4565b50506000600181905560025550565b60005b83811015611c9a578181015183820152602001611c82565b838111156110025750506000910152565b60008151808452611cc3816020860160208601611c7f565b601f01601f19169290920160200192915050565b602081526000610f996020830184611cab565b80356001600160a01b0381168114611d0157600080fd5b919050565b60008060408385031215611d1957600080fd5b611d2283611cea565b946020939093013593505050565b600060208284031215611d4257600080fd5b813560038110610f9957600080fd5b600080600060608486031215611d6657600080fd5b611d6f84611cea565b9250611d7d60208501611cea565b9150604084013590509250925092565b600060208284031215611d9f57600080fd5b5035919050565b600060208284031215611db857600080fd5b610f9982611cea565b60ff60f81b881681526000602060e081840152611de160e084018a611cab565b8381036040850152611df3818a611cab565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015611e4557835183529284019291840191600101611e29565b50909c9b505050505050505050505050565b634e487b7160e01b600052602160045260246000fd5b60038110611e7d57611e7d611e57565b9052565b6020810161065b8284611e6d565b600080600080600080600060e0888a031215611eaa57600080fd5b611eb388611cea565b9650611ec160208901611cea565b95506040880135945060608801359350608088013560ff81168114611ee557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611f1557600080fd5b611f1e83611cea565b9150611f2c60208401611cea565b90509250929050565b600181811c90821680611f4957607f821691505b60208210810361090357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615611f9957611f99611f69565b500290565b60008219821115611fb157611fb1611f69565b500190565b60008451611fc8818460208901611c7f565b8083019050601760f91b8082528551611fe8816001850160208a01611c7f565b60019201918201528351612003816002840160208801611c7f565b0160020195945050505050565b60006020828403121561202257600080fd5b5051919050565b6001600160a01b03858116825260808201906120486020840187611e6d565b6002851061205857612058611e57565b84604084015280841660608401525095945050505050565b634e487b7160e01b600052604160045260246000fd5b60008282101561209857612098611f69565b500390565b6000600182016120af576120af611f69565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826120db576120db6120b6565b500490565b6000826120ef576120ef6120b6565b500690565b634e487b7160e01b600052603260045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b601f82111561219f57600081815260208120601f850160051c8101602086101561217c5750805b601f850160051c820191505b8181101561219b57828155600101612188565b5050505b505050565b815167ffffffffffffffff8111156121be576121be612070565b6121d2816121cc8454611f35565b84612155565b602080601f83116001811461220757600084156121ef5750858301515b600019600386901b1c1916600185901b17855561219b565b600085815260208120601f198616915b8281101561223657888601518255948401946001909101908401612217565b50858210156122545787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c634300080f000a
Deployed Bytecode
0x6080604052600436106101a05760003560e01c80637ae556b5116100ec578063aad3ec961161008a578063d505accf11610064578063d505accf146104cc578063dd62ed3e146104ec578063e12f3a6114610532578063e20ccec31461055257600080fd5b8063aad3ec9614610477578063c44b11f714610497578063d0e30db0146104c457600080fd5b806384b0196e116100c657806384b0196e1461040457806395d89b411461042c578063a035b1fe14610441578063a9059cbb1461045757600080fd5b80637ae556b5146103835780637ecebe00146103cf5780638129fc1c146103ef57600080fd5b80632e1a7d4d116101595780633644e515116101335780633644e5151461031957806354fd4d501461032e5780635b9af12b1461034357806370a082311461036357600080fd5b80632e1a7d4d1461027f57806330adf81f1461029f578063313ce567146102d357600080fd5b806306661abd146101b457806306fdde03146101d8578063095ea7b3146101fa57806318160ddd1461022a5780631a33757d1461023f57806323b872dd1461025f57600080fd5b366101af576101ad610568565b005b600080fd5b3480156101c057600080fd5b50609d545b6040519081526020015b60405180910390f35b3480156101e457600080fd5b506101ed6105b9565b6040516101cf9190611cd7565b34801561020657600080fd5b5061021a610215366004611d06565b610647565b60405190151581526020016101cf565b34801561023657600080fd5b506101c5610661565b34801561024b57600080fd5b506101c561025a366004611d30565b610685565b34801561026b57600080fd5b5061021a61027a366004611d51565b6106db565b34801561028b57600080fd5b506101ad61029a366004611d8d565b6106fd565b3480156102ab57600080fd5b506101c57f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b3480156102df57600080fd5b506103077f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff90911681526020016101cf565b34801561032557600080fd5b506101c56107c4565b34801561033a57600080fd5b506101ed6107ce565b34801561034f57600080fd5b506101ad61035e366004611d8d565b610871565b34801561036f57600080fd5b506101c561037e366004611da6565b61087d565b34801561038f57600080fd5b506103b77f000000000000000000000000430000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101cf565b3480156103db57600080fd5b506101c56103ea366004611da6565b610909565b3480156103fb57600080fd5b506101ad610927565b34801561041057600080fd5b50610419610b4a565b6040516101cf9796959493929190611dc1565b34801561043857600080fd5b506101ed610be8565b34801561044d57600080fd5b506101c560685481565b34801561046357600080fd5b5061021a610472366004611d06565b610bf5565b34801561048357600080fd5b506101c5610492366004611d06565b610c0b565b3480156104a357600080fd5b506104b76104b2366004611da6565b610d87565b6040516101cf9190611e81565b6101ad610568565b3480156104d857600080fd5b506101ad6104e7366004611e8f565b610da5565b3480156104f857600080fd5b506101c5610507366004611f02565b6001600160a01b03918216600090815260a26020908152604080832093909416825291909152205490565b34801561053e57600080fd5b506101c561054d366004611da6565b610f09565b34801561055e57600080fd5b506101c560695481565b336105738134610fa0565b806001600160a01b03167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040516105ae91815260200190565b60405180910390a250565b609a80546105c690611f35565b80601f01602080910402602001604051908101604052809291908181526020018280546105f290611f35565b801561063f5780601f106106145761010080835404028352916020019161063f565b820191906000526020600020905b81548152906001019060200180831161062257829003601f168201915b505050505081565b600033610655818585611008565b60019150505b92915050565b600060a054609d546068546106769190611f7f565b6106809190611f9e565b905090565b600061069133836110b8565b336001600160a01b03167fcaa97ab28bae75adcb5a02786c64b44d0d3139aa521bf831cdfbe280ef246e36836040516106ca9190611e81565b60405180910390a261065b3361087d565b60006106e88433846111ea565b6106f3848484611247565b5060019392505050565b3361070881836112ee565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114610755576040519150601f19603f3d011682016040523d82523d6000602084013e61075a565b606091505b505090508061077c5760405163b12d13eb60e01b815260040160405180910390fd5b816001600160a01b03167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65846040516107b791815260200190565b60405180910390a2505050565b6000610680611362565b60606107f97f000000000000000000000000000000000000000000000000000000000000000161136c565b6108227f000000000000000000000000000000000000000000000000000000000000000061136c565b61084b7f000000000000000000000000000000000000000000000000000000000000000061136c565b60405160200161085d93929190611fb6565b604051602081830303815290604052905090565b61087a81611475565b50565b6001600160a01b038116600090815260a1602052604081205460ff16818160028111156108ac576108ac611e57565b036108e7576001600160a01b0383166000908152609c6020908152604080832054609e909252909120546108e09190611531565b9150610903565b6001600160a01b0383166000908152609f602052604090205491505b50919050565b6001600160a01b03811660009081526035602052604081205461065b565b600054610100900460ff16158080156109475750600054600160ff909116105b806109615750303b158015610961575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b610a9d6040518060400160405280600d81526020016c2bb930b83832b21022ba3432b960991b815250604051806040016040528060048152602001630ae8aa8960e31b815250604360981b6001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a989190612010565b61154c565b60405163099005e760e31b81526002604360981b0190634c802f3890610ad0903090600090819061dead90600401612029565b600060405180830381600087803b158015610aea57600080fd5b505af1158015610afe573d6000803e3d6000fd5b50505050801561087a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6000606080600080600060606001546000801b148015610b6a5750600254155b610bae5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064016109c0565b610bb661159e565b610bbe611630565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b609b80546105c690611f35565b6000610c02338484611247565b50600192915050565b6000336001600160a01b038416610c355760405163088d6c0d60e31b815260040160405180910390fd5b6002610c4082610d87565b6002811115610c5157610c51611e57565b14610c6f5760405163ebf953c760e01b815260040160405180910390fd5b6001600160a01b0381166000908152609c6020908152604080832054609e909252822054610c9d9190611531565b6001600160a01b0383166000908152609f602052604081205491925090610cc49083612086565b905080851115610ce757604051631e9acf1760e31b815260040160405180910390fd5b600080610cfc610cf78886612086565b61163a565b91509150610d31858383609f60008a6001600160a01b03166001600160a01b031681526020019081526020016000205461166f565b610d3b8888610fa0565b6040518781526001600160a01b0389169033907f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd9870689060200160405180910390a350949695505050505050565b6001600160a01b0316600090815260a1602052604090205460ff1690565b83421115610df55760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016109c0565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e248c61170b565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610e7f82611731565b90506000610e8f8287878761175e565b9050896001600160a01b0316816001600160a01b031614610ef25760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016109c0565b610efd8a8a8a611008565b50505050505050505050565b60006002610f1683610d87565b6002811115610f2757610f27611e57565b14610f455760405163ebf953c760e01b815260040160405180910390fd5b6001600160a01b0382166000908152609c6020908152604080832054609e909252822054610f739190611531565b6001600160a01b0384166000908152609f6020526040902054909150610f999082612086565b9392505050565b600081610fac8461087d565b610fb69190611f9e565b9050610fc483826000611786565b6000610fcf84610d87565b90506001816002811115610fe557610fe5611e57565b03611002578260a06000828254610ffc9190611f9e565b90915550505b50505050565b6001600160a01b03831661102f5760405163eb3b083560e01b815260040160405180910390fd5b6001600160a01b0382166110565760405163076e33c360e31b815260040160405180910390fd5b6001600160a01b03838116600081815260a2602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006110c383610d87565b9050600060028260028111156110db576110db611e57565b03611116576001600160a01b0384166000908152609c6020908152604080832054609e9092529091205461110f9190611531565b9050611122565b61111f8461087d565b90505b6001600160a01b038416600090815260a160205260409020805484919060ff1916600183600281111561115757611157611e57565b02179055506001600160a01b0384166000908152609f602052604090205461118185836001611786565b600183600281111561119557611195611e57565b036111b2578060a060008282546111ac9190612086565b90915550505b60018460028111156111c6576111c6611e57565b036111e3578160a060008282546111dd9190611f9e565b90915550505b5050505050565b6001600160a01b03838116600090815260a260209081526040808320938616835292905220546000198114611002578082111561123a576040516313be252b60e01b815260040160405180910390fd5b6110028484848403611008565b6001600160a01b03831661126e57604051630b07e54560e11b815260040160405180910390fd5b6001600160a01b03821661129557604051633a954ecd60e21b815260040160405180910390fd5b61129f83826112ee565b6112a98282610fa0565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516110ab91815260200190565b60006112f98361087d565b90508082111561131c57604051631e9acf1760e31b815260040160405180910390fd5b61132a838383036000611786565b600061133584610d87565b9050600181600281111561134b5761134b611e57565b03611002578260a06000828254610ffc9190612086565b600061068061188d565b6060816000036113935750506040805180820190915260018152600360fc1b602082015290565b8160005b81156113bd57806113a78161209d565b91506113b69050600a836120cc565b9150611397565b60008167ffffffffffffffff8111156113d8576113d8612070565b6040519080825280601f01601f191660200182016040528015611402576020820181803683370190505b5090505b841561146d57611417600183612086565b9150611424600a866120e0565b61142f906030611f9e565b60f81b818381518110611444576114446120f4565b60200101906001600160f81b031916908160001a905350611466600a866120cc565b9450611406565b949350505050565b336001600160a01b037f000000000000000000000000430000000000000000000000000000000000000016146114be57604051631d73770560e11b815260040160405180910390fd5b6000609d546068546114d09190611f7f565b9050600060a05482476114e39190612086565b6114ed9190612086565b9050609d548110806114ff5750609d54155b1561150957505050565b609d5461151690826120cc565b606860008282546115279190611f9e565b9091555050505050565b600081836068546115429190611f7f565b610f999190611f9e565b600054610100900460ff166115735760405162461bcd60e51b81526004016109c09061210a565b61157c83611901565b6115858161194b565b609a61159184826121a4565b50609b61100283826121a4565b6060609a80546115ad90611f35565b80601f01602080910402602001604051908101604052809291908181526020018280546115d990611f35565b80156116265780601f106115fb57610100808354040283529160200191611626565b820191906000526020600020905b81548152906001019060200180831161160957829003601f168201915b5050505050905090565b60606106806107ce565b60008060685460000361164b575091565b60685461165890846120cc565b91506068548361166891906120e0565b9050915091565b6001600160a01b0384166000908152609c6020526040902054609d54611696908590611f9e565b6116a09190612086565b609d556001600160a01b0384166000908152609e602052604090205460a0546116ca908490611f9e565b6116d49190612086565b60a0556001600160a01b039093166000908152609c6020908152604080832094909455609e815283822092909255609f9091522055565b6001600160a01b0381166000908152603560205260409020805460018101825590610903565b600061065b61173e611362565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600061176f87878787611998565b9150915061177c81611a5c565b5095945050505050565b60008060008061179587610d87565b905060008160028111156117ab576117ab611e57565b036117c3576117b98661163a565b9094509250611878565b60018160028111156117d7576117d7611e57565b036117e457859150611878565b60028160028111156117f8576117f8611e57565b03611878578591508185611868576001600160a01b0388166000908152609c6020908152604080832054609e909252909120546118359190611531565b6001600160a01b0389166000908152609f602052604090205490915061185b8883611f9e565b6118659190612086565b90505b6118718161163a565b9095509350505b6118848785858561166f565b50505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6118b8611ba6565b6118c0611bff565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600054610100900460ff166119285760405162461bcd60e51b81526004016109c09061210a565b61087a81604051806040016040528060018152602001603160f81b815250611c30565b600054610100900460ff166119725760405162461bcd60e51b81526004016109c09061210a565b606854156119935760405163131cb46d60e21b815260040160405180910390fd5b606855565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156119cf5750600090506003611a53565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611a23573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611a4c57600060019250925050611a53565b9150600090505b94509492505050565b6000816004811115611a7057611a70611e57565b03611a785750565b6001816004811115611a8c57611a8c611e57565b03611ad95760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016109c0565b6002816004811115611aed57611aed611e57565b03611b3a5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016109c0565b6003816004811115611b4e57611b4e611e57565b0361087a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016109c0565b600080611bb161159e565b805190915015611bc8578051602090910120919050565b6001548015611bd75792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b600080611c0a611630565b805190915015611c21578051602090910120919050565b6002548015611bd75792915050565b600054610100900460ff16611c575760405162461bcd60e51b81526004016109c09061210a565b6003611c6383826121a4565b506004611c7082826121a4565b50506000600181905560025550565b60005b83811015611c9a578181015183820152602001611c82565b838111156110025750506000910152565b60008151808452611cc3816020860160208601611c7f565b601f01601f19169290920160200192915050565b602081526000610f996020830184611cab565b80356001600160a01b0381168114611d0157600080fd5b919050565b60008060408385031215611d1957600080fd5b611d2283611cea565b946020939093013593505050565b600060208284031215611d4257600080fd5b813560038110610f9957600080fd5b600080600060608486031215611d6657600080fd5b611d6f84611cea565b9250611d7d60208501611cea565b9150604084013590509250925092565b600060208284031215611d9f57600080fd5b5035919050565b600060208284031215611db857600080fd5b610f9982611cea565b60ff60f81b881681526000602060e081840152611de160e084018a611cab565b8381036040850152611df3818a611cab565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015611e4557835183529284019291840191600101611e29565b50909c9b505050505050505050505050565b634e487b7160e01b600052602160045260246000fd5b60038110611e7d57611e7d611e57565b9052565b6020810161065b8284611e6d565b600080600080600080600060e0888a031215611eaa57600080fd5b611eb388611cea565b9650611ec160208901611cea565b95506040880135945060608801359350608088013560ff81168114611ee557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611f1557600080fd5b611f1e83611cea565b9150611f2c60208401611cea565b90509250929050565b600181811c90821680611f4957607f821691505b60208210810361090357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615611f9957611f99611f69565b500290565b60008219821115611fb157611fb1611f69565b500190565b60008451611fc8818460208901611c7f565b8083019050601760f91b8082528551611fe8816001850160208a01611c7f565b60019201918201528351612003816002840160208801611c7f565b0160020195945050505050565b60006020828403121561202257600080fd5b5051919050565b6001600160a01b03858116825260808201906120486020840187611e6d565b6002851061205857612058611e57565b84604084015280841660608401525095945050505050565b634e487b7160e01b600052604160045260246000fd5b60008282101561209857612098611f69565b500390565b6000600182016120af576120af611f69565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826120db576120db6120b6565b500490565b6000826120ef576120ef6120b6565b500690565b634e487b7160e01b600052603260045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b601f82111561219f57600081815260208120601f850160051c8101602086101561217c5750805b601f850160051c820191505b8181101561219b57828155600101612188565b5050505b505050565b815167ffffffffffffffff8111156121be576121be612070565b6121d2816121cc8454611f35565b84612155565b602080601f83116001811461220757600084156121ef5750858301515b600019600386901b1c1916600185901b17855561219b565b600085815260208120601f198616915b8281101561223657888601518255948401946001909101908401612217565b50858210156122545787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c634300080f000a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BLAST | Ether (ETH) | 100.00% | $3,346.4 | 0.0002 | $0.669281 |
[ 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.