Source Code
Latest 16 from a total of 16 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Swap Eth For Tok... | 7468649 | 550 days ago | IN | 0.0001 FRAX | 0.00000073 | ||||
| Launch Token | 7295667 | 554 days ago | IN | 0 FRAX | 0.00000349 | ||||
| Swap Eth For Tok... | 6718227 | 567 days ago | IN | 0.001 FRAX | 0.00000041 | ||||
| Swap Eth For Tok... | 6718146 | 567 days ago | IN | 0.0005 FRAX | 0.00000037 | ||||
| Swap Tokens For ... | 6694890 | 568 days ago | IN | 0 FRAX | 0.00000078 | ||||
| Swap Eth For Tok... | 6694857 | 568 days ago | IN | 0.0001 FRAX | 0.00000076 | ||||
| Launch Token | 6694828 | 568 days ago | IN | 0 FRAX | 0.00000192 | ||||
| Set Init Virtual... | 6694635 | 568 days ago | IN | 0 FRAX | 0.00000061 | ||||
| Set Init Virtual... | 6694519 | 568 days ago | IN | 0 FRAX | 0.00000062 | ||||
| Launch Token | 6694351 | 568 days ago | IN | 0 FRAX | 0.00000237 | ||||
| Set Init Virtual... | 6693984 | 568 days ago | IN | 0 FRAX | 0.00000068 | ||||
| Swap Eth For Tok... | 6271648 | 578 days ago | IN | 0.0003 FRAX | 0.00000047 | ||||
| Swap Tokens For ... | 6271648 | 578 days ago | IN | 0 FRAX | 0.00000045 | ||||
| Swap Eth For Tok... | 6271648 | 578 days ago | IN | 0.0001 FRAX | 0.00000047 | ||||
| Launch Token | 6271648 | 578 days ago | IN | 0 FRAX | 0.00000101 | ||||
| Set Creation Fee | 6271648 | 578 days ago | IN | 0 FRAX | 0.0000003 |
Latest 19 internal transactions
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 26468898 | 110 days ago | 0.00000001 FRAX | ||||
| 26404876 | 111 days ago | 0.00000001 FRAX | ||||
| 19575701 | 270 days ago | 1.22555069 FRAX | ||||
| 7468649 | 550 days ago | 0.000001 FRAX | ||||
| 7295667 | 554 days ago | Contract Creation | 0 FRAX | |||
| 6718227 | 567 days ago | 0.00001 FRAX | ||||
| 6718146 | 567 days ago | 0.000005 FRAX | ||||
| 6694890 | 568 days ago | 0.00004844 FRAX | ||||
| 6694890 | 568 days ago | 0.00000048 FRAX | ||||
| 6694857 | 568 days ago | 0.000001 FRAX | ||||
| 6694828 | 568 days ago | Contract Creation | 0 FRAX | |||
| 6694351 | 568 days ago | Contract Creation | 0 FRAX | |||
| 6271648 | 578 days ago | 0.0003136 FRAX | ||||
| 6271648 | 578 days ago | 0.0000165 FRAX | ||||
| 6271648 | 578 days ago | 0.000003 FRAX | ||||
| 6271648 | 578 days ago | 0.00006523 FRAX | ||||
| 6271648 | 578 days ago | 0.00000065 FRAX | ||||
| 6271648 | 578 days ago | 0.000001 FRAX | ||||
| 6271648 | 578 days ago | Contract Creation | 0 FRAX |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RampBondingCurveAMM
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;
import { RampToken } from "./Token.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { FixedPointMathLib } from "@solmate/utils/FixedPointMathLib.sol";
import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol";
import { ERC20 } from "@solmate/tokens/ERC20.sol";
error NotPermitted();
error Paused();
error InsufficientPayment();
error InvalidAmountIn();
error InsufficientOutput();
error DeadlineExceeded();
error InvalidToken();
error FeeTooHigh();
struct TokenLaunchParam {
string name;
string symbol;
string description;
string image;
string twitterLink;
string telegramLink;
string website;
}
struct Pool {
RampToken token;
uint256 tokenReserve;
uint256 virtualTokenReserve;
uint256 ethReserve;
uint256 virtualEthReserve;
uint256 lastPrice;
uint256 lastMcapInEth;
uint256 lastTimestamp;
uint256 lastBlock;
address creator;
bool migrated;
}
contract RampBondingCurveAMM is ReentrancyGuard {
using FixedPointMathLib for uint256;
uint256 public constant FEE_DENOMINATOR = 100_00;
uint256 public constant MAX_FEE = 10_00; // 10%
uint256 public constant INIT_VIRTUAL_TOKEN_RESERVE = 1073000000 ether;
uint256 public constant INIT_REAL_TOKEN_RESERVE = 793100000 ether;
uint256 public constant TOTAL_SUPPLY = 1_000_000_000 ether;
IUniswapV2Router02 public immutable swapRouter;
IUniswapV2Factory public immutable uniswapV2Factory;
uint256 public initVirtualEthReserve;
uint256 public migrationThreshold;
uint256 public CURVE_CONSTANT;
uint256 public creationFee;
uint256 public tradingFeeRate;
uint256 public migrationFeeRate;
address public admin;
address payable public protocolFeeRecipient;
bool public paused;
mapping(address => Pool) public tokenPool;
event TokenLaunch(
address indexed creator,
address token,
string name,
string symbol,
string description,
string image,
string twitterLink,
string telegramLink,
string website,
uint256 timestamp
);
event PriceUpdate(
address indexed token,
address indexed trader,
uint256 price,
uint256 mcapEth,
uint256 timestamp
);
event Trade(
address indexed trader,
address indexed token,
uint256 amountIn,
uint256 amountOut,
uint256 fee,
uint256 timestamp,
bool isBuy
);
event MigrateLiquidity(
address indexed token,
address indexed pair,
uint256 ethAmount,
uint256 tokenAmount,
uint256 fee,
uint256 timestamp
);
modifier onlyAdmin() {
if (msg.sender != admin) revert NotPermitted();
_;
}
modifier onlyUnPaused() {
if (paused) revert Paused();
_;
}
modifier checkDeadline(uint256 deadline) {
if (block.timestamp > deadline) revert DeadlineExceeded();
_;
}
constructor(
uint256 _tradingFeeRate,
uint256 _migrationFeeRate,
uint256 _creationFee,
uint256 _initVirtualEthReserve,
address feeRecipient,
address router,
address factory
) {
admin = msg.sender;
tradingFeeRate = _tradingFeeRate;
migrationFeeRate = _migrationFeeRate;
creationFee = _creationFee;
swapRouter = IUniswapV2Router02(router);
uniswapV2Factory = IUniswapV2Factory(factory);
paused = false;
protocolFeeRecipient = payable(feeRecipient);
initVirtualEthReserve = _initVirtualEthReserve;
CURVE_CONSTANT = initVirtualEthReserve * INIT_VIRTUAL_TOKEN_RESERVE;
migrationThreshold = CURVE_CONSTANT / (INIT_VIRTUAL_TOKEN_RESERVE - INIT_REAL_TOKEN_RESERVE) - initVirtualEthReserve;
}
function launchToken(TokenLaunchParam memory param) external payable onlyUnPaused returns (address) {
if (msg.value < creationFee) revert InsufficientPayment();
if (creationFee > 0) SafeTransferLib.safeTransferETH(protocolFeeRecipient, creationFee);
RampToken token = new RampToken(param.name, param.symbol, address(this), msg.sender, TOTAL_SUPPLY);
Pool storage pool = tokenPool[address(token)];
pool.token = token;
pool.tokenReserve = INIT_REAL_TOKEN_RESERVE;
pool.virtualTokenReserve = INIT_VIRTUAL_TOKEN_RESERVE;
pool.ethReserve = 0;
pool.virtualEthReserve = initVirtualEthReserve;
pool.lastPrice = initVirtualEthReserve.divWadDown(INIT_VIRTUAL_TOKEN_RESERVE);
pool.lastMcapInEth = TOTAL_SUPPLY.mulWadUp(pool.lastPrice);
pool.lastTimestamp = block.timestamp;
pool.lastBlock = block.number;
pool.creator = msg.sender;
pool.migrated = false;
emit TokenLaunch(
msg.sender,
address(token),
param.name,
param.symbol,
param.description,
param.image,
param.twitterLink,
param.telegramLink,
param.website,
block.timestamp
);
emit PriceUpdate(
address(token),
msg.sender,
pool.lastPrice,
pool.lastMcapInEth,
block.timestamp
);
return address(token);
}
function swapEthForTokens(address token, uint256 amountIn, uint256 amountOutMin, uint256 deadline)
external
payable
nonReentrant
onlyUnPaused
checkDeadline(deadline)
returns (uint256 amountOut)
{
if (msg.value < amountIn) revert InsufficientPayment();
if (amountIn == 0) revert InvalidAmountIn();
uint256 fee = 0;
if (tokenPool[token].migrated) {
( amountOut, fee ) = _swapETHForTokenOnRouter(token, amountIn, amountOutMin, msg.sender);
} else {
fee = amountIn * tradingFeeRate / FEE_DENOMINATOR;
amountIn -= fee;
SafeTransferLib.safeTransferETH(protocolFeeRecipient, fee);
if (tokenPool[token].creator == address(0)) revert InvalidToken();
uint256 newVirtualEthReserve = tokenPool[token].virtualEthReserve + amountIn;
uint256 newVirtualTokenReserve = CURVE_CONSTANT / newVirtualEthReserve;
amountOut = tokenPool[token].virtualTokenReserve - newVirtualTokenReserve;
if (amountOut > tokenPool[token].tokenReserve) {
amountOut = tokenPool[token].tokenReserve;
}
if (amountOut < amountOutMin) revert InsufficientOutput();
tokenPool[token].virtualEthReserve = newVirtualEthReserve;
tokenPool[token].virtualTokenReserve = newVirtualTokenReserve;
tokenPool[token].lastPrice = newVirtualEthReserve.divWadDown(newVirtualTokenReserve);
tokenPool[token].lastMcapInEth = TOTAL_SUPPLY.mulWadUp(tokenPool[token].lastPrice);
tokenPool[token].lastTimestamp = block.timestamp;
tokenPool[token].lastBlock = block.number;
tokenPool[token].ethReserve += amountIn;
tokenPool[token].tokenReserve -= amountOut;
SafeTransferLib.safeTransfer(ERC20(token), msg.sender, amountOut);
emit PriceUpdate(token, msg.sender, tokenPool[token].lastPrice, tokenPool[token].lastMcapInEth, block.timestamp);
if (tokenPool[token].ethReserve >= migrationThreshold) {
_migrateLiquidity(token);
}
}
emit Trade(msg.sender, token, amountIn + fee, amountOut, fee, block.timestamp, true);
}
function swapTokensForEth(address token, uint256 amountIn, uint256 amountOutMin, uint256 deadline)
external
nonReentrant
onlyUnPaused
checkDeadline(deadline)
returns (uint256 amountOut)
{
uint256 fee = 0;
if (amountIn == 0) revert InvalidAmountIn();
SafeTransferLib.safeTransferFrom(ERC20(token), msg.sender, address(this), amountIn);
if (tokenPool[token].migrated) {
( amountOut, fee ) = _swapTokenForETHOnRouter(token, amountIn, amountOutMin, msg.sender);
} else {
if (tokenPool[token].creator == address(0)) revert InvalidToken();
uint256 newVirtualTokenReserve = tokenPool[token].virtualTokenReserve + amountIn;
uint256 newVirtualEthReserve = CURVE_CONSTANT / newVirtualTokenReserve;
amountOut = tokenPool[token].virtualEthReserve - newVirtualEthReserve;
tokenPool[token].virtualTokenReserve = newVirtualTokenReserve;
tokenPool[token].virtualEthReserve = newVirtualEthReserve;
tokenPool[token].lastPrice = newVirtualEthReserve.divWadDown(newVirtualTokenReserve);
tokenPool[token].lastMcapInEth = TOTAL_SUPPLY.mulWadUp(tokenPool[token].lastPrice);
tokenPool[token].lastTimestamp = block.timestamp;
tokenPool[token].lastBlock = block.number;
tokenPool[token].tokenReserve += amountIn;
tokenPool[token].ethReserve -= amountOut;
fee = amountOut * tradingFeeRate / FEE_DENOMINATOR;
amountOut -= fee;
if (amountOut < amountOutMin) revert InsufficientOutput();
SafeTransferLib.safeTransferETH(protocolFeeRecipient, fee);
SafeTransferLib.safeTransferETH(msg.sender, amountOut);
emit PriceUpdate(token, msg.sender, tokenPool[token].lastPrice, tokenPool[token].lastMcapInEth, block.timestamp);
}
emit Trade(msg.sender, token, amountIn, amountOut, fee, block.timestamp, false);
}
function _migrateLiquidity(address token) private {
if (tokenPool[token].creator == address(0)) revert InvalidToken();
tokenPool[token].lastTimestamp = block.timestamp;
tokenPool[token].lastBlock = block.number;
uint256 fee = tokenPool[token].ethReserve * migrationFeeRate / FEE_DENOMINATOR;
SafeTransferLib.safeTransferETH(protocolFeeRecipient, fee);
uint256 ethAmount = tokenPool[token].ethReserve - fee;
uint256 tokenAmount = TOTAL_SUPPLY - INIT_REAL_TOKEN_RESERVE;
RampToken(token).setIsApprovable(true);
bool success = RampToken(token).approve(address(swapRouter), tokenAmount);
require(success, "token approval failed");
address pair = uniswapV2Factory.createPair(token, swapRouter.WETH());
swapRouter.addLiquidityETH{ value: ethAmount }(
token,
tokenAmount,
tokenAmount,
ethAmount,
address(0), // permanently lock the liquidity
block.timestamp + 1 minutes
);
tokenPool[token].migrated = true;
tokenPool[token].virtualEthReserve = 0;
tokenPool[token].virtualTokenReserve = 0;
tokenPool[token].ethReserve = 0;
tokenPool[token].tokenReserve = 0;
emit MigrateLiquidity(token, pair, ethAmount, tokenAmount, fee, block.timestamp);
}
function calcAmountOutFromToken(address token, uint256 amountIn) external view returns (uint256 amountOut) {
if (amountIn == 0) revert InvalidAmountIn();
uint256 newVirtualTokenReserve = tokenPool[token].virtualTokenReserve + amountIn;
uint256 newVirtualEthReserve = CURVE_CONSTANT / newVirtualTokenReserve;
amountOut = tokenPool[token].virtualEthReserve - newVirtualEthReserve;
uint256 fee = amountOut * tradingFeeRate / FEE_DENOMINATOR;
amountOut -= fee;
}
function calcAmountOutFromEth(address token, uint256 amountIn) external view returns (uint256 amountOut) {
if (amountIn == 0) revert InvalidAmountIn();
uint256 fee = amountIn * tradingFeeRate / FEE_DENOMINATOR;
amountIn -= fee;
uint256 newVirtualEthReserve = tokenPool[token].virtualEthReserve + amountIn;
uint256 newVirtualTokenReserve = CURVE_CONSTANT / newVirtualEthReserve;
amountOut = tokenPool[token].virtualTokenReserve - newVirtualTokenReserve;
if (amountOut > tokenPool[token].tokenReserve) {
amountOut = tokenPool[token].tokenReserve;
}
}
function _swapETHForTokenOnRouter(address token, uint256 amountIn, uint256 amountOutMin, address to) private returns (uint256, uint256) {
if (msg.value < amountIn) revert InsufficientPayment();
uint256 fee = (amountIn * tradingFeeRate) / FEE_DENOMINATOR;
address[] memory path = new address[](2);
path[0] = swapRouter.WETH();
path[1] = token;
uint[] memory amounts = swapRouter.swapExactETHForTokens{value: amountIn - fee}(
amountOutMin,
path,
to,
block.timestamp + 1 minutes
);
uint amountOut = amounts[amounts.length - 1];
SafeTransferLib.safeTransferETH(protocolFeeRecipient, fee);
return (amountOut, fee);
}
function _swapTokenForETHOnRouter(address token, uint256 amountIn, uint256 amountOutMin, address to) private returns (uint256, uint256) {
address[] memory path = new address[](2);
path[0] = token;
path[1] = swapRouter.WETH();
RampToken(token).approve(address(swapRouter), amountIn);
uint[] memory amounts = swapRouter.swapExactTokensForETH(
amountIn,
amountOutMin,
path,
address(this),
block.timestamp + 1 minutes
);
uint amountOut = amounts[amounts.length - 1];
uint256 fee = (amountOut * tradingFeeRate) / FEE_DENOMINATOR;
SafeTransferLib.safeTransferETH(protocolFeeRecipient, fee);
SafeTransferLib.safeTransferETH(to, amountOut - fee);
return (amountOut - fee, fee);
}
function setInitVirtualEthReserve(uint256 value) external onlyAdmin {
initVirtualEthReserve = value;
CURVE_CONSTANT = initVirtualEthReserve * INIT_VIRTUAL_TOKEN_RESERVE;
migrationThreshold = CURVE_CONSTANT / (INIT_VIRTUAL_TOKEN_RESERVE - INIT_REAL_TOKEN_RESERVE) - initVirtualEthReserve;
}
function setProtocolFeeRecipient(address recpt) external onlyAdmin {
protocolFeeRecipient = payable(recpt);
}
function setCreationFee(uint256 value) external onlyAdmin {
creationFee = value;
}
function setMigrationFeeRate(uint256 value) external onlyAdmin {
if (value > MAX_FEE) revert FeeTooHigh();
migrationFeeRate = value;
}
function setTradingFeeRate(uint256 value) external onlyAdmin {
if (value > MAX_FEE) revert FeeTooHigh();
tradingFeeRate = value;
}
function setAdmin(address newAdmin) external onlyAdmin {
admin = newAdmin;
}
function setPaused(bool _val) external onlyAdmin {
paused = _val;
}
receive() external payable {}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;
import { ERC20Permit, ERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
error NotApprovable();
error NotRampBondingCurve();
contract RampToken is ERC20Permit {
address public immutable curve;
address public immutable creator;
/// @notice Prevent trading on AMMs until liquidity migration
bool public isApprovable = false;
constructor(
string memory name,
string memory symbol,
address _curve,
address _creator,
uint256 _supply
) ERC20(name, symbol) ERC20Permit(name) {
curve = _curve;
creator = _creator;
_mint(msg.sender, _supply);
}
function approve(address spender, uint256 amount) public override returns (bool) {
if (spender == curve || isApprovable) return super.approve(spender, amount);
revert NotApprovable();
}
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public override {
if (!isApprovable) revert NotApprovable();
super.permit(owner, spender, value, deadline, v, r, s);
}
function setIsApprovable(bool _val) public {
if (msg.sender != curve) revert NotRampBondingCurve();
isApprovable = _val;
}
}pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
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.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
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) {
/// @solidity memory-safe-assembly
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 unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
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/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
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;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
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 the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
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 the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
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 the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/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 v5.0.0) (token/ERC20/extensions/ERC20Permit.sol)
pragma solidity ^0.8.20;
import {IERC20Permit} from "./IERC20Permit.sol";
import {ERC20} from "../ERC20.sol";
import {ECDSA} from "../../../utils/cryptography/ECDSA.sol";
import {EIP712} from "../../../utils/cryptography/EIP712.sol";
import {Nonces} from "../../../utils/Nonces.sol";
/**
* @dev Implementation of the 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.
*/
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces {
bytes32 private constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
/**
* @dev Permit deadline has expired.
*/
error ERC2612ExpiredSignature(uint256 deadline);
/**
* @dev Mismatched signature.
*/
error ERC2612InvalidSigner(address signer, address owner);
/**
* @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
*
* It's a good idea to use the same `name` that is defined as the ERC20 token name.
*/
constructor(string memory name) EIP712(name, "1") {}
/**
* @inheritdoc IERC20Permit
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
if (block.timestamp > deadline) {
revert ERC2612ExpiredSignature(deadline);
}
bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
if (signer != owner) {
revert ERC2612InvalidSigner(signer, owner);
}
_approve(owner, spender, value);
}
/**
* @inheritdoc IERC20Permit
*/
function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) {
return super.nonces(owner);
}
/**
* @inheritdoc IERC20Permit
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
return _domainSeparatorV4();
}
}pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.20;
import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
* encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
* does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
* produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {IERC-5267}.
*/
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
/**
* @dev The name parameter for the EIP712 domain.
*
* NOTE: By default this function reads _name which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Name() internal view returns (string memory) {
return _name.toStringWithFallback(_nameFallback);
}
/**
* @dev The version parameter for the EIP712 domain.
*
* NOTE: By default this function reads _version which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Version() internal view returns (string memory) {
return _version.toStringWithFallback(_versionFallback);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides tracking nonces for addresses. Nonces will only increment.
*/
abstract contract Nonces {
/**
* @dev The nonce used for an `account` is not the expected current nonce.
*/
error InvalidAccountNonce(address account, uint256 currentNonce);
mapping(address account => uint256) private _nonces;
/**
* @dev Returns the next unused nonce for an address.
*/
function nonces(address owner) public view virtual returns (uint256) {
return _nonces[owner];
}
/**
* @dev Consumes a nonce.
*
* Returns the current value and increments nonce.
*/
function _useNonce(address owner) internal virtual returns (uint256) {
// For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
// decremented or reset. This guarantees that the nonce never overflows.
unchecked {
// It is important to do x++ and not ++x here.
return _nonces[owner]++;
}
}
/**
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
*/
function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
uint256 current = _useNonce(owner);
if (nonce != current) {
revert InvalidAccountNonce(owner, current);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using
* {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@uniswap/v2-periphery/=lib/v2-periphery/",
"@uniswap/v2-core/=lib/v2-core/",
"@solmate/=lib/solmate/src/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solmate/=lib/solmate/src/",
"v2-core/=lib/v2-core/contracts/",
"v2-periphery/=lib/v2-periphery/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"_tradingFeeRate","type":"uint256"},{"internalType":"uint256","name":"_migrationFeeRate","type":"uint256"},{"internalType":"uint256","name":"_creationFee","type":"uint256"},{"internalType":"uint256","name":"_initVirtualEthReserve","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"factory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"FeeTooHigh","type":"error"},{"inputs":[],"name":"InsufficientOutput","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"InvalidAmountIn","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"NotPermitted","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MigrateLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mcapEth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"PriceUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"string","name":"description","type":"string"},{"indexed":false,"internalType":"string","name":"image","type":"string"},{"indexed":false,"internalType":"string","name":"twitterLink","type":"string"},{"indexed":false,"internalType":"string","name":"telegramLink","type":"string"},{"indexed":false,"internalType":"string","name":"website","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"TokenLaunch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBuy","type":"bool"}],"name":"Trade","type":"event"},{"inputs":[],"name":"CURVE_CONSTANT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INIT_REAL_TOKEN_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INIT_VIRTUAL_TOKEN_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"calcAmountOutFromEth","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"calcAmountOutFromToken","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creationFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initVirtualEthReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"image","type":"string"},{"internalType":"string","name":"twitterLink","type":"string"},{"internalType":"string","name":"telegramLink","type":"string"},{"internalType":"string","name":"website","type":"string"}],"internalType":"struct TokenLaunchParam","name":"param","type":"tuple"}],"name":"launchToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"migrationFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrationThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRecipient","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setCreationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setInitVirtualEthReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setMigrationFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_val","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recpt","type":"address"}],"name":"setProtocolFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setTradingFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapEthForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForEth","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenPool","outputs":[{"internalType":"contract RampToken","name":"token","type":"address"},{"internalType":"uint256","name":"tokenReserve","type":"uint256"},{"internalType":"uint256","name":"virtualTokenReserve","type":"uint256"},{"internalType":"uint256","name":"ethReserve","type":"uint256"},{"internalType":"uint256","name":"virtualEthReserve","type":"uint256"},{"internalType":"uint256","name":"lastPrice","type":"uint256"},{"internalType":"uint256","name":"lastMcapInEth","type":"uint256"},{"internalType":"uint256","name":"lastTimestamp","type":"uint256"},{"internalType":"uint256","name":"lastBlock","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"bool","name":"migrated","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapV2Factory","outputs":[{"internalType":"contract IUniswapV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60c03461015e57601f61375b38819003918201601f19168301916001600160401b038311848410176101635780849260e09460405283398101031261015e57805160208201519060408301519260608101519361005e60808301610179565b9361007760c061007060a08601610179565b9401610179565b9360016000553360018060a01b0319600754161760075560055560065560045560018060a01b0391828092166080521660a05260085491169060018060a81b03191617600855806001556b037790968dc8efffd100000080820290828204148215171561014857806ae787216768429d218000009160035504908103908111610148576002556040516135cd908161018e82396080518181816106bb0152818161088c01528181610d7701528181610de801528181610ef001526112dd015260a051818181610e55015261182e0152f35b634e487b7160e01b600052601160045260246000fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b038216820361015e5756fe608080604052600436101561001d575b50361561001b57600080fd5b005b600090813560e01c908163045b8d78146119ac575080631091f67c1461197557806316c38b3c1461192057806329b53cee146118a2578063320a0060146118845780634b103bfa1461185d57806359d0f713146118185780635c975abb146117f257806364df049e146117c95780636577327e1461174d578063704b6c02146117085780638238e9da146116555780638365546714611204578063902d55a5146111dd57806390bc1e85146111bf578063a134ddf714611198578063a4c821e61461114f578063b242483e146107ee578063b7d86225146107c1578063bc063e1a146107a4578063c1edd5bc146106ea578063c31c9c07146106a5578063d73792a914610688578063dce0b4e41461066a578063e01df1a81461064c578063e05f024e1461062e578063e521cb92146105d6578063f851a440146105aa5763fa1c492e0361000f57602060031981813601126105a6576004359067ffffffffffffffff908183116105a25760e090833603011261059e5760405160e0810181811083821117610588576040528260040135828111610584576101c59060043691860101611a4f565b81526024830135828111610584576101e39060043691860101611a4f565b8482019081526044840135838111610580576102059060043691870101611a4f565b60408301908152606485013584811161057c576102289060043691880101611a4f565b936060840194855260848601358181116105785761024c9060043691890101611a4f565b956080850196875260a4810135828111610574576102709060043691840101611a4f565b9060a0860191825260c4810135908382116105705760046102949236920101611a4f565b9160c0860192835260085460ff8160a01c1661055e5760045480341061054c5780610533575b5050855185516040519261183e808501939184118585101761051f576103118d8695946103046b033b2e3c9fd0803ce800000095608095611d5a8a3960a0885260a0880190611b09565b9186830390870152611b09565b92306040820152336060820152015203908af080156105145760018060a01b031696878a526009895260408a2096886001600160601b0360a01b8954161788556b029009752660ad62af80000060018901556b037790968dc8efffd10000008060028a01558b60038a01556001548060048b0155670de0b6b3a7640000907812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218111820215830215610510578b9c9d509a999a0204968760058b01556103ce88611b6c565b998a6006820155426007820155436008820155600901805460ff60a01b193316906affffffffffffffffffffff60a81b161790555195519451905191519251935194604051968c61012080918c8b528a0152880161042b91611b09565b878103604089015261043c91611b09565b868103606088015261044d91611b09565b858103608087015261045e91611b09565b84810360a086015261046f91611b09565b83810360c085015261048091611b09565b82810360e084015261049191611b09565b9042610100820152803392037f4c3449617a987f0d9b9e9b06cc25e185a3bf4ee8d294d61d2e310a9a0ec498b091a26040518091339442906104e492846040919493926060820195825260208201520152565b037feadf1668b2f8926f6538c3b24fceb72251daa320b74c8c36da738cce051c48c091a3604051908152f35b8d80fd5b6040513d8b823e3d90fd5b634e487b7160e01b8e52604160045260248efd5b610545916001600160a01b0316611ba2565b38806102ba565b60405163cd1c886760e01b8152600490fd5b6040516313d0ff5960e31b8152600490fd5b8a80fd5b8980fd5b8880fd5b8780fd5b8680fd5b8580fd5b634e487b7160e01b600052604160045260246000fd5b8380fd5b8480fd5b8280fd5b50346105d357806003193601126105d3576007546040516001600160a01b039091168152602090f35b80fd5b50346105d35760203660031901126105d3576105f06119c8565b6007546001600160a01b0391908216330361061c57166001600160601b0360a01b600854161760085580f35b6040516339218f3b60e01b8152600490fd5b50346105d357806003193601126105d3576020600654604051908152f35b50346105d357806003193601126105d3576020600554604051908152f35b50346105d357806003193601126105d3576020600454604051908152f35b50346105d357806003193601126105d35760206040516127108152f35b50346105d357806003193601126105d3576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105d35760403660031901126105d3576107046119c8565b60243591821561079257604060019161076f61075c61075461073860209861271061073160055483611aa6565b0490611acf565b96868060a01b0316968785526009895260048686200154611afc565b600354611adc565b8583526009875260028484200154611acf565b9381526009855220015480821161078a575b50604051908152f35b905038610781565b6040516365719fe160e11b8152600490fd5b50346105d357806003193601126105d35760206040516103e88152f35b50346105d35760203660031901126105d3576007546001600160a01b0316330361061c5760043560045580f35b506107f8366119e3565b61080493919293611b49565b6008549060ff8260a01c1661055e57421161113d578380341061054c578015610792576001600160a01b03831686526009602081905260408720015460a01c60ff1615610a7a57505082341061054c5761271061086360055485611aa6565b049160405161087181611a11565b6002815260403660208301376040516315ab88c960e31b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169190602081600481865afa908115610a6f578891610a40575b506108d782611bed565b6001600160a01b03918216905284166108ef82611c10565b526108fa8587611acf565b603c420193844211610a2c57918893916109389360405196879586948593637ff36ab560e01b85526004850152608060248501526084840190611ce7565b90336044840152606483015203925af1908115610a215785916109ff575b5080516000198101919082116109eb579161099761097a6001959360209895611c20565b519261098f81878060a01b0360085416611ba2565b809396611afc565b9160405192835285878401526040830152426060830152836080830152838060a01b0316907f3893b12ea2017f00ca6b320ece400190bef0f01352a842b563729af4b14e8f3660a03392a355604051908152f35b634e487b7160e01b86526011600452602486fd5b610a1b91503d8087833e610a138183611a2d565b810190611c6b565b38610956565b6040513d87823e3d90fd5b634e487b7160e01b89526011600452602489fd5b610a62915060203d602011610a68575b610a5a8183611a2d565b810190611c34565b386108cd565b503d610a50565b6040513d8a823e3d90fd5b610a9e939450610aad6127109182610a9460055483611aa6565b0495868092611acf565b936001600160a01b0316611ba2565b6001600160a01b0383811687526009602081905260408820015416156110da576001600160a01b038316865260096020526040862060040154610af1908390611afc565b610afd81600354611adc565b9060018060a01b03851688526009602052610b1f82600260408b200154611acf565b6001600160a01b038616895260096020526040892060010154909790808911611135575b50871061112357610b84610b7960039360018060a01b0388168b52600960205260408b2093806004860155816002860155611d24565b806005840155611b6c565b600682015542600782015543600882015501610ba1838254611afc565b90556001600160a01b03831686526009602052604086206001018054610bc8908790611acf565b905560405163a9059cbb60e01b8152336004820152602481018690526020908790604490826001600160a01b0388165af13d15601f3d116001895114161716156110ec576001600160a01b038316808752600960209081526040808920600581015460069091015482519182529281019290925242908201523391907feadf1668b2f8926f6538c3b24fceb72251daa320b74c8c36da738cce051c48c090606090a36001600160a01b038316865260096020526040862060038101546002541115610ca1575b5050916020949161099782600195611afc565b600901546001600160a01b0316156110da576001600160a01b038316865260096020526040862042600782015543600882015560030154600654610ce491611aa6565b04610cf98160018060a01b0360085416611ba2565b6001600160a01b038316865260096020526040862060030154610d1d908290611acf565b906001600160a01b0384163b156105805760405163538a035b60e11b8152600160048201528781602481836001600160a01b038a165af18015610a6f576110aa575b5060405163095ea7b360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526aab24c7796fd2da388000006024830152602090829060449082908c908a165af1908115610a6f57889161107b575b501561103e576040516315ab88c960e31b8152906020826004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa918215610a6f57889261101d575b506040516364e329cb60e11b81526001600160a01b038681166004830152928316602482015291602090839060449082908c907f0000000000000000000000000000000000000000000000000000000000000000165af1918215610a6f578892610ffc575b50603c4201804211610a2c576040519063f305d71960e01b825260018060a01b03871660048301526aab24c7796fd2da3880000060248301526aab24c7796fd2da38800000604483015284606483015289608483015260a482015260608160c4818760018060a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1801561051457610fd1575b506001600160a01b03808616808a52600960208181526040808d20928301805460ff60a01b1916600160a01b179055600483018d9055600283018d9055600383018d905560019283018d905580519788526aab24c7796fd2da388000008883015287019490945242606087015292999297929692959294610997948794931691907f975531bb29dbf7996fcd8e163f4189c89f5aa16ef8c6c1178c8c3e59a67b7e0190608090a39350945081939650610c8e565b606090813d8311610ff5575b610fe78183611a2d565b8101031261057c5738610f1d565b503d610fdd565b61101691925060203d602011610a6857610a5a8183611a2d565b9038610e85565b61103791925060203d602011610a6857610a5a8183611a2d565b9038610e20565b60405162461bcd60e51b81526020600482015260156024820152741d1bdad95b88185c1c1c9bdd985b0819985a5b1959605a1b6044820152606490fd5b61109d915060203d6020116110a3575b6110958183611a2d565b810190611c53565b38610dcc565b503d61108b565b67ffffffffffffffff81989298116110c6576040529538610d5f565b634e487b7160e01b82526041600452602482fd5b60405163c1ab6dc160e01b8152600490fd5b60405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606490fd5b60405163bb2875c360e01b8152600490fd5b975038610b43565b60405163559895a360e01b8152600490fd5b50346105d35760203660031901126105d357600754600435906001600160a01b0316330361061c576103e881116111865760065580f35b60405163cd4e616760e01b8152600490fd5b50346105d357806003193601126105d35760206040516b037790968dc8efffd10000008152f35b50346105d357806003193601126105d3576020600254604051908152f35b50346105d357806003193601126105d35760206040516b033b2e3c9fd0803ce80000008152f35b50346105d357611213366119e3565b611221949394929192611b49565b60ff60085460a01c1661055e57421161113d578015610792576040516323b872dd60e01b815233600482015230602480830191909152604482018390526020956001600160a01b039081169490928790879060649082895af13d15601f3d1160018951141617161561161a5784865260098088528060408820015460ff8160a01c166000146114e15750506040516112b881611a11565b6002815260403689830137856112cd82611bed565b526040516315ab88c960e31b81527f0000000000000000000000000000000000000000000000000000000000000000851691908981600481865afa9081156105145789916114c4575b508561132183611c10565b9116905260405163095ea7b360e01b8152826004820152868582015289816044818c8c5af18015610514576114a7575b50603c420192834211611494579161139591898094604051968795869485936318cbafe560e01b85528d60048601528b85015260a0604485015260a4840190611ce7565b90306064840152608483015203925af190811561148957869161146f575b50805160001981019290831161145d5750600194926113da6113f897959361141093611c20565b516127106113ea60055483611aa6565b049788809360085416611ba2565b61140b6114058383611acf565b33611ba2565b611acf565b945b604051918252858783015260408201524260608201528260808201527f3893b12ea2017f00ca6b320ece400190bef0f01352a842b563729af4b14e8f3660a03392a355604051908152f35b634e487b7160e01b8752601160045286fd5b61148391503d8088833e610a138183611a2d565b386113b3565b6040513d88823e3d90fd5b634e487b7160e01b895260116004528489fd5b6114bd908a3d8c116110a3576110958183611a2d565b5038611351565b6114db91508a3d8c11610a6857610a5a8183611a2d565b38611316565b84969491929795935016156110da57828452808752611507826002604087200154611afc565b90600161151683600354611adc565b858752828a52611550610b7961153383600460408c200154611acf565b95888a52858d5260408a2093816002860155806004860155611d24565b60068201554260078201554360088201550161156d848254611afc565b905583855280885260036040862001611587838254611acf565b90556115a361271061159b60055485611aa6565b048093611acf565b968710611123576115ba8260019760085416611ba2565b6115c48733611ba2565b838552875260408085206005810154600690910154825191825260208201524291810191909152339084907feadf1668b2f8926f6538c3b24fceb72251daa320b74c8c36da738cce051c48c090606090a3611412565b60405162461bcd60e51b815260048101889052601481840152731514905394d1915497d19493d357d1905253115160621b6044820152606490fd5b50346105d35760203660031901126105d357610160906001600160a01b039060ff90604090836116836119c8565b168152600960205220828154169260018201549160028101546003820154600483015460058401549060068501549260078601549460096008880154970154986040519b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152811661012084015260a01c161515610140820152f35b50346105d35760203660031901126105d3576117226119c8565b600754906001600160a01b0390818316330361061c5716906001600160601b0360a01b161760075580f35b50346105d35760403660031901126105d3576117676119c8565b9060243591821561079257602092600460406117c1946117a36107546117b29660018060a01b03169586845260098a5260028585200154611afc565b93815260098752200154611acf565b61271061073160055483611aa6565b604051908152f35b50346105d357806003193601126105d3576008546040516001600160a01b039091168152602090f35b50346105d357806003193601126105d357602060ff60085460a01c166040519015158152f35b50346105d357806003193601126105d3576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105d357806003193601126105d35760206040516b029009752660ad62af8000008152f35b50346105d357806003193601126105d3576020600154604051908152f35b50346105d35760203660031901126105d357600754600435906001600160a01b0316330361061c57806001556b037790968dc8efffd100000080820290828204148215171561190c57906ae787216768429d21800000826119069360035504611acf565b60025580f35b634e487b7160e01b83526011600452602483fd5b50346105d35760203660031901126105d357600435801515809103611971576007546001600160a01b0316330361061c576008805460ff60a01b191660a09290921b60ff60a01b1691909117905580f35b5080fd5b50346105d35760203660031901126105d357600754600435906001600160a01b0316330361061c576103e881116111865760055580f35b9050346119715781600319360112611971576020906003548152f35b600435906001600160a01b03821682036119de57565b600080fd5b60809060031901126119de576004356001600160a01b03811681036119de5790602435906044359060643590565b6060810190811067ffffffffffffffff82111761058857604052565b90601f8019910116810190811067ffffffffffffffff82111761058857604052565b81601f820112156119de5780359067ffffffffffffffff82116105885760405192611a84601f8401601f191660200185611a2d565b828452602083830101116119de57816000926020809301838601378301015290565b81810292918115918404141715611ab957565b634e487b7160e01b600052601160045260246000fd5b91908203918211611ab957565b8115611ae6570490565b634e487b7160e01b600052601260045260246000fd5b91908201809211611ab957565b919082519283825260005b848110611b35575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201611b14565b600260005414611b5a576002600055565b604051633ee5aeb560e01b8152600490fd5b670de0b6b3a7640000906b033b2e3c9fd0803ce800000060001982900481118202158302156119de570290808204910615150190565b600080809381935af115611bb257565b60405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606490fd5b805115611bfa5760200190565b634e487b7160e01b600052603260045260246000fd5b805160011015611bfa5760400190565b8051821015611bfa5760209160051b010190565b908160209103126119de57516001600160a01b03811681036119de5790565b908160209103126119de575180151581036119de5790565b9060209081838203126119de57825167ffffffffffffffff938482116119de570181601f820112156119de578051938411610588578360051b9060405194611cb585840187611a2d565b855283808601928201019283116119de578301905b828210611cd8575050505090565b81518152908301908301611cca565b90815180825260208080930193019160005b828110611d07575050505090565b83516001600160a01b031685529381019392810192600101611cf9565b670de0b6b3a7640000907812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f2181118202158302156119de5702049056fe6101a0604090808252346104bd5761183e803803809161001f82856104c2565b833981019060a0818303126104bd5780516001600160401b0392908381116104bd578161004d918401610508565b60209182840151908582116104bd57610067918501610508565b9461007381850161055c565b9260806100826060870161055c565b95015190825197838901898110898211176103d4578452600197888a52828a0198603160f81b8a5286518281116103d45760038054918383811c931680156104b3575b8784101461049d57601f92838111610457575b5080878482116001146103f5576000916103ea575b5060001982841b1c191690841b1781555b8451918483116103d45760049586548581811c911680156103ca575b898210146103b55782811161036f575b5087918411600114610309579383949184926000956102fe575b50501b92600019911b1c19161782555b61015d86610570565b98610120998a5261016d8b610701565b966101409788528481519101209a8b60e0525190206101009a818c524660a052865191858301917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83528884015260608301524660808301523060a083015260a0825260c0820192828410908411176102e957828752815190206080523060c05260ff196008541660085561016097885261018098895233156102d2575050600254908382018092116102bd57506000917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9160025533835282815284832084815401905584519384523393a35193610ff79586610847873960805186610b63015260a05186610c2f015260c05186610b2d015260e05186610bb201525185610bd80152518461045f01525183610489015251828181610301015281816105b401526109f1015251816108b50152f35b601190634e487b7160e01b6000525260246000fd5b63ec442f0560e01b8252600060c490910152602490fd5b604184634e487b7160e01b6000525260246000fd5b015193503880610144565b9190601f198416928760005284896000209460005b8b89838310610358575050501061033e575b50505050811b018255610154565b01519060f884600019921b161c1916905538808080610330565b86860151895590970196948501948893500161031e565b87600052886000208380870160051c8201928b88106103ac575b0160051c019086905b8281106103a057505061012a565b60008155018690610392565b92508192610389565b602288634e487b7160e01b6000525260246000fd5b90607f169061011a565b634e487b7160e01b600052604160045260246000fd5b90508a0151386100ed565b60008481528981208794509190601f198416908b8f5b838310610440575050508311610428575b5050811b0181556100fe565b8c015160001983861b60f8161c19169055388061041c565b840151855589969094019392830192018b8f61040b565b82600052876000208480840160051c8201928a8510610494575b0160051c019085905b8281106104885750506100d8565b6000815501859061047a565b92508192610471565b634e487b7160e01b600052602260045260246000fd5b92607f16926100c5565b600080fd5b601f909101601f19168101906001600160401b038211908210176103d457604052565b60005b8381106104f85750506000910152565b81810151838201526020016104e8565b81601f820112156104bd5780516001600160401b0381116103d4576040519261053b601f8301601f1916602001856104c2565b818452602082840101116104bd5761055991602080850191016104e5565b90565b51906001600160a01b03821682036104bd57565b805160209190828110156105eb575090601f8251116105ab578082519201519080831061059c57501790565b82600019910360031b1b161790565b6044906105dd9260405193849263305a27a960e01b8452806004850152825192839182602487015286860191016104e5565b601f01601f19168101030190fd5b6001600160401b0381116103d4576005928354926001938481811c911680156106f7575b8382101461049d57601f81116106c3575b5081601f841160011461065d5750928293918392600094610652575b50501b916000199060031b1c191617905560ff90565b01519250388061063c565b919083601f1981168760005284600020946000905b888383106106a95750505010610690575b505050811b01905560ff90565b015160001960f88460031b161c19169055388080610683565b858701518855909601959485019487935090810190610672565b8560005284601f846000209201871c820191601f8601881c015b8281106106eb575050610620565b600081550185906106dd565b90607f169061060f565b80516020908181101561072b5750601f8251116105ab578082519201519080831061059c57501790565b906001600160401b0382116103d457600654926001938481811c9116801561083c575b8382101461049d57601f8111610805575b5081601f841160011461079d5750928293918392600094610792575b50501b916000199060031b1c19161760065560ff90565b01519250388061077b565b919083601f198116600660005284600020946000905b888383106107eb57505050106107d2575b505050811b0160065560ff90565b015160001960f88460031b161c191690553880806107c4565b8587015188559096019594850194879350908101906107b3565b600660005284601f84600020920160051c820191601f860160051c015b82811061083057505061075f565b60008155018590610822565b90607f169061074e56fe608060408181526004918236101561001657600080fd5b600092833560e01c91826302d05d3f146108a15750816306fdde03146107c6578163095ea7b31461079457816318160ddd1461077557816323b872dd1461067e578163313ce5671461066257816331a18ea11461063e5781633644e5151461061a57816370a08231146105e35781637165485d1461059f5781637ecebe001461056757816384b0196e1461044757816395d89b4114610357578163a71406b6146102df578163a9059cbb146102ae578163d505accf1461012b575063dd62ed3e146100e057600080fd5b34610127578060031936011261012757806020926100fc610924565b61010461093f565b6001600160a01b0391821683526001865283832091168252845220549051908152f35b5080fd5b839150346101275760e036600319011261012757610147610924565b61014f61093f565b906044359260643560843560ff811681036102aa5760ff600854161561029a578142116102835760018060a01b0390818516928389526007602052898920908154916001830190558a519060208201927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98452868d840152858a1660608401528a608084015260a083015260c082015260c0815260e0810181811067ffffffffffffffff821117610270578b5251902061023e916102359161020f610b2a565b908c519161190160f01b83526002830152602282015260c43591604260a4359220610eac565b90929192610f3c565b168181036102555786610252878787610c55565b80f35b87516325c0072360e11b815292830152602482015260449150fd5b634e487b7160e01b8b526041875260248bfd5b875163313c898160e11b8152808401839052602490fd5b875163ad8c648b60e01b81528390fd5b8680fd5b5050346101275780600319360112610127576020906102d86102ce610924565b6024359033610a4c565b5160018152f35b9050346103535760203660031901126103535780359182151580930361034f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361034257505060ff80196008541691161760085580f35b516363f46cb560e01b8152fd5b8380fd5b8280fd5b91905034610353578260031936011261035357805183819490845461037b81610955565b918285526020966001928860018216918260001461041d5750506001146103c2575b85886103be896103af848a03856109c1565b519282849384528301906108e4565b0390f35b815286935091907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b82841061040557505050820101816103af6103be3861039d565b8054848a0186015288955087949093019281016103eb565b60ff19168882015294151560051b870190940194508593506103af92506103be915038905061039d565b919050346103535782600319360112610353576104837f0000000000000000000000000000000000000000000000000000000000000000610ce8565b926104ad7f0000000000000000000000000000000000000000000000000000000000000000610dec565b90825192602092602085019585871067ffffffffffffffff881117610554575092602061050a8388966104fd998b9996528686528151998a99600f60f81b8b5260e0868c015260e08b01906108e4565b91898303908a01526108e4565b924660608801523060808801528460a088015286840360c088015251928381520193925b82811061053d57505050500390f35b83518552869550938101939281019260010161052e565b634e487b7160e01b845260419052602483fd5b5050346101275760203660031901126101275760209181906001600160a01b0361058f610924565b1681526007845220549051908152f35b505034610127578160031936011261012757517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5050346101275760203660031901126101275760209181906001600160a01b0361060b610924565b16815280845220549051908152f35b505034610127578160031936011261012757602090610637610b2a565b9051908152f35b50503461012757816003193601126101275760209060ff6008541690519015158152f35b5050346101275781600319360112610127576020905160128152f35b905082346107725760603660031901126107725761069a610924565b6106a261093f565b916044359360018060a01b0383168083526001602052868320338452602052868320549160001983036106de575b6020886102d8898989610a4c565b86831061074657811561072f573315610718575082526001602090815286832033845281529186902090859003905582906102d8876106d0565b8751634a1406b160e11b8152908101849052602490fd5b875163e602df0560e01b8152908101849052602490fd5b8751637dc7a0d960e11b8152339181019182526020820193909352604081018790528291506060010390fd5b80fd5b5050346101275781600319360112610127576020906002549051908152f35b5050346101275780600319360112610127576020906107bd6107b4610924565b602435906109e3565b90519015158152f35b82843461077257806003193601126107725781519182826003546107e981610955565b908184526020956001918760018216918260001461087a57505060011461081e575b5050506103be92916103af9103856109c1565b9190869350600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061086257505050820101816103af6103be61080b565b8054848a018601528895508794909301928101610849565b60ff19168782015293151560051b860190930193508492506103af91506103be905061080b565b8490346101275781600319360112610127577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b919082519283825260005b848110610910575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016108ef565b600435906001600160a01b038216820361093a57565b600080fd5b602435906001600160a01b038216820361093a57565b90600182811c92168015610985575b602083101461096f57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610964565b6040810190811067ffffffffffffffff8211176109ab57604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176109ab57604052565b906001600160a01b038083167f0000000000000000000000000000000000000000000000000000000000000000909116148015610a40575b610a315760405163ad8c648b60e01b8152600490fd5b610a3b9133610c55565b600190565b5060ff60085416610a1b565b916001600160a01b03808416928315610b115716928315610af85760009083825281602052604082205490838210610ac6575091604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b60405163ec442f0560e01b815260006004820152602490fd5b604051634b637e8f60e11b815260006004820152602490fd5b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480610c2c575b15610b85577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a0815260c0810181811067ffffffffffffffff8211176109ab5760405251902090565b507f00000000000000000000000000000000000000000000000000000000000000004614610b5c565b6001600160a01b03908116918215610ccf5716918215610cb65760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260018252604060002085600052825280604060002055604051908152a3565b604051634a1406b160e11b815260006004820152602490fd5b60405163e602df0560e01b815260006004820152602490fd5b60ff8114610d265760ff811690601f8211610d145760405191610d0a8361098f565b8252602082015290565b604051632cd44ac360e21b8152600490fd5b50604051600554816000610d3983610955565b80835292602090600190818116908115610dc85750600114610d67575b5050610d64925003826109c1565b90565b91509260056000527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0936000925b828410610db05750610d649450505081016020013880610d56565b85548785018301529485019486945092810192610d95565b91505060209250610d6494915060ff191682840152151560051b8201013880610d56565b60ff8114610e0e5760ff811690601f8211610d145760405191610d0a8361098f565b50604051600654816000610e2183610955565b80835292602090600190818116908115610dc85750600114610e4b575050610d64925003826109c1565b91509260066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f936000925b828410610e945750610d649450505081016020013880610d56565b85548785018301529485019486945092810192610e79565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411610f3057926020929160ff608095604051948552168484015260408301526060820152600092839182805260015afa15610f245780516001600160a01b03811615610f1b57918190565b50809160019190565b604051903d90823e3d90fd5b50505060009160039190565b6004811015610fab5780610f4e575050565b60018103610f685760405163f645eedf60e01b8152600490fd5b60028103610f895760405163fce698f760e01b815260048101839052602490fd5b600314610f935750565b602490604051906335e2f38360e21b82526004820152fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220f7cc8e66c14588fcaaa301e0efc5838bc7d5a238db77c59c60d1c4e13142fbda64736f6c63430008190033a264697066735822122090635580932afa136f3509fe1a6f5fd80cd7acbf795fb711604fe34c84f690a264736f6c63430008190033000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000038d7ea4c6800000000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000f65330dc75e32b20be62f503a337cd1a072f898f00000000000000000000000039cd4db6460d8b5961f73e997e86ddbb7ca4d5f6000000000000000000000000e30521fe7f3beb6ad556887b50739d6c7ca667e6
Deployed Bytecode
0x608080604052600436101561001d575b50361561001b57600080fd5b005b600090813560e01c908163045b8d78146119ac575080631091f67c1461197557806316c38b3c1461192057806329b53cee146118a2578063320a0060146118845780634b103bfa1461185d57806359d0f713146118185780635c975abb146117f257806364df049e146117c95780636577327e1461174d578063704b6c02146117085780638238e9da146116555780638365546714611204578063902d55a5146111dd57806390bc1e85146111bf578063a134ddf714611198578063a4c821e61461114f578063b242483e146107ee578063b7d86225146107c1578063bc063e1a146107a4578063c1edd5bc146106ea578063c31c9c07146106a5578063d73792a914610688578063dce0b4e41461066a578063e01df1a81461064c578063e05f024e1461062e578063e521cb92146105d6578063f851a440146105aa5763fa1c492e0361000f57602060031981813601126105a6576004359067ffffffffffffffff908183116105a25760e090833603011261059e5760405160e0810181811083821117610588576040528260040135828111610584576101c59060043691860101611a4f565b81526024830135828111610584576101e39060043691860101611a4f565b8482019081526044840135838111610580576102059060043691870101611a4f565b60408301908152606485013584811161057c576102289060043691880101611a4f565b936060840194855260848601358181116105785761024c9060043691890101611a4f565b956080850196875260a4810135828111610574576102709060043691840101611a4f565b9060a0860191825260c4810135908382116105705760046102949236920101611a4f565b9160c0860192835260085460ff8160a01c1661055e5760045480341061054c5780610533575b5050855185516040519261183e808501939184118585101761051f576103118d8695946103046b033b2e3c9fd0803ce800000095608095611d5a8a3960a0885260a0880190611b09565b9186830390870152611b09565b92306040820152336060820152015203908af080156105145760018060a01b031696878a526009895260408a2096886001600160601b0360a01b8954161788556b029009752660ad62af80000060018901556b037790968dc8efffd10000008060028a01558b60038a01556001548060048b0155670de0b6b3a7640000907812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f218111820215830215610510578b9c9d509a999a0204968760058b01556103ce88611b6c565b998a6006820155426007820155436008820155600901805460ff60a01b193316906affffffffffffffffffffff60a81b161790555195519451905191519251935194604051968c61012080918c8b528a0152880161042b91611b09565b878103604089015261043c91611b09565b868103606088015261044d91611b09565b858103608087015261045e91611b09565b84810360a086015261046f91611b09565b83810360c085015261048091611b09565b82810360e084015261049191611b09565b9042610100820152803392037f4c3449617a987f0d9b9e9b06cc25e185a3bf4ee8d294d61d2e310a9a0ec498b091a26040518091339442906104e492846040919493926060820195825260208201520152565b037feadf1668b2f8926f6538c3b24fceb72251daa320b74c8c36da738cce051c48c091a3604051908152f35b8d80fd5b6040513d8b823e3d90fd5b634e487b7160e01b8e52604160045260248efd5b610545916001600160a01b0316611ba2565b38806102ba565b60405163cd1c886760e01b8152600490fd5b6040516313d0ff5960e31b8152600490fd5b8a80fd5b8980fd5b8880fd5b8780fd5b8680fd5b8580fd5b634e487b7160e01b600052604160045260246000fd5b8380fd5b8480fd5b8280fd5b50346105d357806003193601126105d3576007546040516001600160a01b039091168152602090f35b80fd5b50346105d35760203660031901126105d3576105f06119c8565b6007546001600160a01b0391908216330361061c57166001600160601b0360a01b600854161760085580f35b6040516339218f3b60e01b8152600490fd5b50346105d357806003193601126105d3576020600654604051908152f35b50346105d357806003193601126105d3576020600554604051908152f35b50346105d357806003193601126105d3576020600454604051908152f35b50346105d357806003193601126105d35760206040516127108152f35b50346105d357806003193601126105d3576040517f00000000000000000000000039cd4db6460d8b5961f73e997e86ddbb7ca4d5f66001600160a01b03168152602090f35b50346105d35760403660031901126105d3576107046119c8565b60243591821561079257604060019161076f61075c61075461073860209861271061073160055483611aa6565b0490611acf565b96868060a01b0316968785526009895260048686200154611afc565b600354611adc565b8583526009875260028484200154611acf565b9381526009855220015480821161078a575b50604051908152f35b905038610781565b6040516365719fe160e11b8152600490fd5b50346105d357806003193601126105d35760206040516103e88152f35b50346105d35760203660031901126105d3576007546001600160a01b0316330361061c5760043560045580f35b506107f8366119e3565b61080493919293611b49565b6008549060ff8260a01c1661055e57421161113d578380341061054c578015610792576001600160a01b03831686526009602081905260408720015460a01c60ff1615610a7a57505082341061054c5761271061086360055485611aa6565b049160405161087181611a11565b6002815260403660208301376040516315ab88c960e31b81527f00000000000000000000000039cd4db6460d8b5961f73e997e86ddbb7ca4d5f66001600160a01b03169190602081600481865afa908115610a6f578891610a40575b506108d782611bed565b6001600160a01b03918216905284166108ef82611c10565b526108fa8587611acf565b603c420193844211610a2c57918893916109389360405196879586948593637ff36ab560e01b85526004850152608060248501526084840190611ce7565b90336044840152606483015203925af1908115610a215785916109ff575b5080516000198101919082116109eb579161099761097a6001959360209895611c20565b519261098f81878060a01b0360085416611ba2565b809396611afc565b9160405192835285878401526040830152426060830152836080830152838060a01b0316907f3893b12ea2017f00ca6b320ece400190bef0f01352a842b563729af4b14e8f3660a03392a355604051908152f35b634e487b7160e01b86526011600452602486fd5b610a1b91503d8087833e610a138183611a2d565b810190611c6b565b38610956565b6040513d87823e3d90fd5b634e487b7160e01b89526011600452602489fd5b610a62915060203d602011610a68575b610a5a8183611a2d565b810190611c34565b386108cd565b503d610a50565b6040513d8a823e3d90fd5b610a9e939450610aad6127109182610a9460055483611aa6565b0495868092611acf565b936001600160a01b0316611ba2565b6001600160a01b0383811687526009602081905260408820015416156110da576001600160a01b038316865260096020526040862060040154610af1908390611afc565b610afd81600354611adc565b9060018060a01b03851688526009602052610b1f82600260408b200154611acf565b6001600160a01b038616895260096020526040892060010154909790808911611135575b50871061112357610b84610b7960039360018060a01b0388168b52600960205260408b2093806004860155816002860155611d24565b806005840155611b6c565b600682015542600782015543600882015501610ba1838254611afc565b90556001600160a01b03831686526009602052604086206001018054610bc8908790611acf565b905560405163a9059cbb60e01b8152336004820152602481018690526020908790604490826001600160a01b0388165af13d15601f3d116001895114161716156110ec576001600160a01b038316808752600960209081526040808920600581015460069091015482519182529281019290925242908201523391907feadf1668b2f8926f6538c3b24fceb72251daa320b74c8c36da738cce051c48c090606090a36001600160a01b038316865260096020526040862060038101546002541115610ca1575b5050916020949161099782600195611afc565b600901546001600160a01b0316156110da576001600160a01b038316865260096020526040862042600782015543600882015560030154600654610ce491611aa6565b04610cf98160018060a01b0360085416611ba2565b6001600160a01b038316865260096020526040862060030154610d1d908290611acf565b906001600160a01b0384163b156105805760405163538a035b60e11b8152600160048201528781602481836001600160a01b038a165af18015610a6f576110aa575b5060405163095ea7b360e01b81526001600160a01b037f00000000000000000000000039cd4db6460d8b5961f73e997e86ddbb7ca4d5f6811660048301526aab24c7796fd2da388000006024830152602090829060449082908c908a165af1908115610a6f57889161107b575b501561103e576040516315ab88c960e31b8152906020826004817f00000000000000000000000039cd4db6460d8b5961f73e997e86ddbb7ca4d5f66001600160a01b03165afa918215610a6f57889261101d575b506040516364e329cb60e11b81526001600160a01b038681166004830152928316602482015291602090839060449082908c907f000000000000000000000000e30521fe7f3beb6ad556887b50739d6c7ca667e6165af1918215610a6f578892610ffc575b50603c4201804211610a2c576040519063f305d71960e01b825260018060a01b03871660048301526aab24c7796fd2da3880000060248301526aab24c7796fd2da38800000604483015284606483015289608483015260a482015260608160c4818760018060a01b037f00000000000000000000000039cd4db6460d8b5961f73e997e86ddbb7ca4d5f6165af1801561051457610fd1575b506001600160a01b03808616808a52600960208181526040808d20928301805460ff60a01b1916600160a01b179055600483018d9055600283018d9055600383018d905560019283018d905580519788526aab24c7796fd2da388000008883015287019490945242606087015292999297929692959294610997948794931691907f975531bb29dbf7996fcd8e163f4189c89f5aa16ef8c6c1178c8c3e59a67b7e0190608090a39350945081939650610c8e565b606090813d8311610ff5575b610fe78183611a2d565b8101031261057c5738610f1d565b503d610fdd565b61101691925060203d602011610a6857610a5a8183611a2d565b9038610e85565b61103791925060203d602011610a6857610a5a8183611a2d565b9038610e20565b60405162461bcd60e51b81526020600482015260156024820152741d1bdad95b88185c1c1c9bdd985b0819985a5b1959605a1b6044820152606490fd5b61109d915060203d6020116110a3575b6110958183611a2d565b810190611c53565b38610dcc565b503d61108b565b67ffffffffffffffff81989298116110c6576040529538610d5f565b634e487b7160e01b82526041600452602482fd5b60405163c1ab6dc160e01b8152600490fd5b60405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606490fd5b60405163bb2875c360e01b8152600490fd5b975038610b43565b60405163559895a360e01b8152600490fd5b50346105d35760203660031901126105d357600754600435906001600160a01b0316330361061c576103e881116111865760065580f35b60405163cd4e616760e01b8152600490fd5b50346105d357806003193601126105d35760206040516b037790968dc8efffd10000008152f35b50346105d357806003193601126105d3576020600254604051908152f35b50346105d357806003193601126105d35760206040516b033b2e3c9fd0803ce80000008152f35b50346105d357611213366119e3565b611221949394929192611b49565b60ff60085460a01c1661055e57421161113d578015610792576040516323b872dd60e01b815233600482015230602480830191909152604482018390526020956001600160a01b039081169490928790879060649082895af13d15601f3d1160018951141617161561161a5784865260098088528060408820015460ff8160a01c166000146114e15750506040516112b881611a11565b6002815260403689830137856112cd82611bed565b526040516315ab88c960e31b81527f00000000000000000000000039cd4db6460d8b5961f73e997e86ddbb7ca4d5f6851691908981600481865afa9081156105145789916114c4575b508561132183611c10565b9116905260405163095ea7b360e01b8152826004820152868582015289816044818c8c5af18015610514576114a7575b50603c420192834211611494579161139591898094604051968795869485936318cbafe560e01b85528d60048601528b85015260a0604485015260a4840190611ce7565b90306064840152608483015203925af190811561148957869161146f575b50805160001981019290831161145d5750600194926113da6113f897959361141093611c20565b516127106113ea60055483611aa6565b049788809360085416611ba2565b61140b6114058383611acf565b33611ba2565b611acf565b945b604051918252858783015260408201524260608201528260808201527f3893b12ea2017f00ca6b320ece400190bef0f01352a842b563729af4b14e8f3660a03392a355604051908152f35b634e487b7160e01b8752601160045286fd5b61148391503d8088833e610a138183611a2d565b386113b3565b6040513d88823e3d90fd5b634e487b7160e01b895260116004528489fd5b6114bd908a3d8c116110a3576110958183611a2d565b5038611351565b6114db91508a3d8c11610a6857610a5a8183611a2d565b38611316565b84969491929795935016156110da57828452808752611507826002604087200154611afc565b90600161151683600354611adc565b858752828a52611550610b7961153383600460408c200154611acf565b95888a52858d5260408a2093816002860155806004860155611d24565b60068201554260078201554360088201550161156d848254611afc565b905583855280885260036040862001611587838254611acf565b90556115a361271061159b60055485611aa6565b048093611acf565b968710611123576115ba8260019760085416611ba2565b6115c48733611ba2565b838552875260408085206005810154600690910154825191825260208201524291810191909152339084907feadf1668b2f8926f6538c3b24fceb72251daa320b74c8c36da738cce051c48c090606090a3611412565b60405162461bcd60e51b815260048101889052601481840152731514905394d1915497d19493d357d1905253115160621b6044820152606490fd5b50346105d35760203660031901126105d357610160906001600160a01b039060ff90604090836116836119c8565b168152600960205220828154169260018201549160028101546003820154600483015460058401549060068501549260078601549460096008880154970154986040519b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152811661012084015260a01c161515610140820152f35b50346105d35760203660031901126105d3576117226119c8565b600754906001600160a01b0390818316330361061c5716906001600160601b0360a01b161760075580f35b50346105d35760403660031901126105d3576117676119c8565b9060243591821561079257602092600460406117c1946117a36107546117b29660018060a01b03169586845260098a5260028585200154611afc565b93815260098752200154611acf565b61271061073160055483611aa6565b604051908152f35b50346105d357806003193601126105d3576008546040516001600160a01b039091168152602090f35b50346105d357806003193601126105d357602060ff60085460a01c166040519015158152f35b50346105d357806003193601126105d3576040517f000000000000000000000000e30521fe7f3beb6ad556887b50739d6c7ca667e66001600160a01b03168152602090f35b50346105d357806003193601126105d35760206040516b029009752660ad62af8000008152f35b50346105d357806003193601126105d3576020600154604051908152f35b50346105d35760203660031901126105d357600754600435906001600160a01b0316330361061c57806001556b037790968dc8efffd100000080820290828204148215171561190c57906ae787216768429d21800000826119069360035504611acf565b60025580f35b634e487b7160e01b83526011600452602483fd5b50346105d35760203660031901126105d357600435801515809103611971576007546001600160a01b0316330361061c576008805460ff60a01b191660a09290921b60ff60a01b1691909117905580f35b5080fd5b50346105d35760203660031901126105d357600754600435906001600160a01b0316330361061c576103e881116111865760055580f35b9050346119715781600319360112611971576020906003548152f35b600435906001600160a01b03821682036119de57565b600080fd5b60809060031901126119de576004356001600160a01b03811681036119de5790602435906044359060643590565b6060810190811067ffffffffffffffff82111761058857604052565b90601f8019910116810190811067ffffffffffffffff82111761058857604052565b81601f820112156119de5780359067ffffffffffffffff82116105885760405192611a84601f8401601f191660200185611a2d565b828452602083830101116119de57816000926020809301838601378301015290565b81810292918115918404141715611ab957565b634e487b7160e01b600052601160045260246000fd5b91908203918211611ab957565b8115611ae6570490565b634e487b7160e01b600052601260045260246000fd5b91908201809211611ab957565b919082519283825260005b848110611b35575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201611b14565b600260005414611b5a576002600055565b604051633ee5aeb560e01b8152600490fd5b670de0b6b3a7640000906b033b2e3c9fd0803ce800000060001982900481118202158302156119de570290808204910615150190565b600080809381935af115611bb257565b60405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606490fd5b805115611bfa5760200190565b634e487b7160e01b600052603260045260246000fd5b805160011015611bfa5760400190565b8051821015611bfa5760209160051b010190565b908160209103126119de57516001600160a01b03811681036119de5790565b908160209103126119de575180151581036119de5790565b9060209081838203126119de57825167ffffffffffffffff938482116119de570181601f820112156119de578051938411610588578360051b9060405194611cb585840187611a2d565b855283808601928201019283116119de578301905b828210611cd8575050505090565b81518152908301908301611cca565b90815180825260208080930193019160005b828110611d07575050505090565b83516001600160a01b031685529381019392810192600101611cf9565b670de0b6b3a7640000907812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f2181118202158302156119de5702049056fe6101a0604090808252346104bd5761183e803803809161001f82856104c2565b833981019060a0818303126104bd5780516001600160401b0392908381116104bd578161004d918401610508565b60209182840151908582116104bd57610067918501610508565b9461007381850161055c565b9260806100826060870161055c565b95015190825197838901898110898211176103d4578452600197888a52828a0198603160f81b8a5286518281116103d45760038054918383811c931680156104b3575b8784101461049d57601f92838111610457575b5080878482116001146103f5576000916103ea575b5060001982841b1c191690841b1781555b8451918483116103d45760049586548581811c911680156103ca575b898210146103b55782811161036f575b5087918411600114610309579383949184926000956102fe575b50501b92600019911b1c19161782555b61015d86610570565b98610120998a5261016d8b610701565b966101409788528481519101209a8b60e0525190206101009a818c524660a052865191858301917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83528884015260608301524660808301523060a083015260a0825260c0820192828410908411176102e957828752815190206080523060c05260ff196008541660085561016097885261018098895233156102d2575050600254908382018092116102bd57506000917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9160025533835282815284832084815401905584519384523393a35193610ff79586610847873960805186610b63015260a05186610c2f015260c05186610b2d015260e05186610bb201525185610bd80152518461045f01525183610489015251828181610301015281816105b401526109f1015251816108b50152f35b601190634e487b7160e01b6000525260246000fd5b63ec442f0560e01b8252600060c490910152602490fd5b604184634e487b7160e01b6000525260246000fd5b015193503880610144565b9190601f198416928760005284896000209460005b8b89838310610358575050501061033e575b50505050811b018255610154565b01519060f884600019921b161c1916905538808080610330565b86860151895590970196948501948893500161031e565b87600052886000208380870160051c8201928b88106103ac575b0160051c019086905b8281106103a057505061012a565b60008155018690610392565b92508192610389565b602288634e487b7160e01b6000525260246000fd5b90607f169061011a565b634e487b7160e01b600052604160045260246000fd5b90508a0151386100ed565b60008481528981208794509190601f198416908b8f5b838310610440575050508311610428575b5050811b0181556100fe565b8c015160001983861b60f8161c19169055388061041c565b840151855589969094019392830192018b8f61040b565b82600052876000208480840160051c8201928a8510610494575b0160051c019085905b8281106104885750506100d8565b6000815501859061047a565b92508192610471565b634e487b7160e01b600052602260045260246000fd5b92607f16926100c5565b600080fd5b601f909101601f19168101906001600160401b038211908210176103d457604052565b60005b8381106104f85750506000910152565b81810151838201526020016104e8565b81601f820112156104bd5780516001600160401b0381116103d4576040519261053b601f8301601f1916602001856104c2565b818452602082840101116104bd5761055991602080850191016104e5565b90565b51906001600160a01b03821682036104bd57565b805160209190828110156105eb575090601f8251116105ab578082519201519080831061059c57501790565b82600019910360031b1b161790565b6044906105dd9260405193849263305a27a960e01b8452806004850152825192839182602487015286860191016104e5565b601f01601f19168101030190fd5b6001600160401b0381116103d4576005928354926001938481811c911680156106f7575b8382101461049d57601f81116106c3575b5081601f841160011461065d5750928293918392600094610652575b50501b916000199060031b1c191617905560ff90565b01519250388061063c565b919083601f1981168760005284600020946000905b888383106106a95750505010610690575b505050811b01905560ff90565b015160001960f88460031b161c19169055388080610683565b858701518855909601959485019487935090810190610672565b8560005284601f846000209201871c820191601f8601881c015b8281106106eb575050610620565b600081550185906106dd565b90607f169061060f565b80516020908181101561072b5750601f8251116105ab578082519201519080831061059c57501790565b906001600160401b0382116103d457600654926001938481811c9116801561083c575b8382101461049d57601f8111610805575b5081601f841160011461079d5750928293918392600094610792575b50501b916000199060031b1c19161760065560ff90565b01519250388061077b565b919083601f198116600660005284600020946000905b888383106107eb57505050106107d2575b505050811b0160065560ff90565b015160001960f88460031b161c191690553880806107c4565b8587015188559096019594850194879350908101906107b3565b600660005284601f84600020920160051c820191601f860160051c015b82811061083057505061075f565b60008155018590610822565b90607f169061074e56fe608060408181526004918236101561001657600080fd5b600092833560e01c91826302d05d3f146108a15750816306fdde03146107c6578163095ea7b31461079457816318160ddd1461077557816323b872dd1461067e578163313ce5671461066257816331a18ea11461063e5781633644e5151461061a57816370a08231146105e35781637165485d1461059f5781637ecebe001461056757816384b0196e1461044757816395d89b4114610357578163a71406b6146102df578163a9059cbb146102ae578163d505accf1461012b575063dd62ed3e146100e057600080fd5b34610127578060031936011261012757806020926100fc610924565b61010461093f565b6001600160a01b0391821683526001865283832091168252845220549051908152f35b5080fd5b839150346101275760e036600319011261012757610147610924565b61014f61093f565b906044359260643560843560ff811681036102aa5760ff600854161561029a578142116102835760018060a01b0390818516928389526007602052898920908154916001830190558a519060208201927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98452868d840152858a1660608401528a608084015260a083015260c082015260c0815260e0810181811067ffffffffffffffff821117610270578b5251902061023e916102359161020f610b2a565b908c519161190160f01b83526002830152602282015260c43591604260a4359220610eac565b90929192610f3c565b168181036102555786610252878787610c55565b80f35b87516325c0072360e11b815292830152602482015260449150fd5b634e487b7160e01b8b526041875260248bfd5b875163313c898160e11b8152808401839052602490fd5b875163ad8c648b60e01b81528390fd5b8680fd5b5050346101275780600319360112610127576020906102d86102ce610924565b6024359033610a4c565b5160018152f35b9050346103535760203660031901126103535780359182151580930361034f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361034257505060ff80196008541691161760085580f35b516363f46cb560e01b8152fd5b8380fd5b8280fd5b91905034610353578260031936011261035357805183819490845461037b81610955565b918285526020966001928860018216918260001461041d5750506001146103c2575b85886103be896103af848a03856109c1565b519282849384528301906108e4565b0390f35b815286935091907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b82841061040557505050820101816103af6103be3861039d565b8054848a0186015288955087949093019281016103eb565b60ff19168882015294151560051b870190940194508593506103af92506103be915038905061039d565b919050346103535782600319360112610353576104837f0000000000000000000000000000000000000000000000000000000000000000610ce8565b926104ad7f0000000000000000000000000000000000000000000000000000000000000000610dec565b90825192602092602085019585871067ffffffffffffffff881117610554575092602061050a8388966104fd998b9996528686528151998a99600f60f81b8b5260e0868c015260e08b01906108e4565b91898303908a01526108e4565b924660608801523060808801528460a088015286840360c088015251928381520193925b82811061053d57505050500390f35b83518552869550938101939281019260010161052e565b634e487b7160e01b845260419052602483fd5b5050346101275760203660031901126101275760209181906001600160a01b0361058f610924565b1681526007845220549051908152f35b505034610127578160031936011261012757517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5050346101275760203660031901126101275760209181906001600160a01b0361060b610924565b16815280845220549051908152f35b505034610127578160031936011261012757602090610637610b2a565b9051908152f35b50503461012757816003193601126101275760209060ff6008541690519015158152f35b5050346101275781600319360112610127576020905160128152f35b905082346107725760603660031901126107725761069a610924565b6106a261093f565b916044359360018060a01b0383168083526001602052868320338452602052868320549160001983036106de575b6020886102d8898989610a4c565b86831061074657811561072f573315610718575082526001602090815286832033845281529186902090859003905582906102d8876106d0565b8751634a1406b160e11b8152908101849052602490fd5b875163e602df0560e01b8152908101849052602490fd5b8751637dc7a0d960e11b8152339181019182526020820193909352604081018790528291506060010390fd5b80fd5b5050346101275781600319360112610127576020906002549051908152f35b5050346101275780600319360112610127576020906107bd6107b4610924565b602435906109e3565b90519015158152f35b82843461077257806003193601126107725781519182826003546107e981610955565b908184526020956001918760018216918260001461087a57505060011461081e575b5050506103be92916103af9103856109c1565b9190869350600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061086257505050820101816103af6103be61080b565b8054848a018601528895508794909301928101610849565b60ff19168782015293151560051b860190930193508492506103af91506103be905061080b565b8490346101275781600319360112610127577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b919082519283825260005b848110610910575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016108ef565b600435906001600160a01b038216820361093a57565b600080fd5b602435906001600160a01b038216820361093a57565b90600182811c92168015610985575b602083101461096f57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610964565b6040810190811067ffffffffffffffff8211176109ab57604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176109ab57604052565b906001600160a01b038083167f0000000000000000000000000000000000000000000000000000000000000000909116148015610a40575b610a315760405163ad8c648b60e01b8152600490fd5b610a3b9133610c55565b600190565b5060ff60085416610a1b565b916001600160a01b03808416928315610b115716928315610af85760009083825281602052604082205490838210610ac6575091604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b60405163ec442f0560e01b815260006004820152602490fd5b604051634b637e8f60e11b815260006004820152602490fd5b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480610c2c575b15610b85577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a0815260c0810181811067ffffffffffffffff8211176109ab5760405251902090565b507f00000000000000000000000000000000000000000000000000000000000000004614610b5c565b6001600160a01b03908116918215610ccf5716918215610cb65760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260018252604060002085600052825280604060002055604051908152a3565b604051634a1406b160e11b815260006004820152602490fd5b60405163e602df0560e01b815260006004820152602490fd5b60ff8114610d265760ff811690601f8211610d145760405191610d0a8361098f565b8252602082015290565b604051632cd44ac360e21b8152600490fd5b50604051600554816000610d3983610955565b80835292602090600190818116908115610dc85750600114610d67575b5050610d64925003826109c1565b90565b91509260056000527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0936000925b828410610db05750610d649450505081016020013880610d56565b85548785018301529485019486945092810192610d95565b91505060209250610d6494915060ff191682840152151560051b8201013880610d56565b60ff8114610e0e5760ff811690601f8211610d145760405191610d0a8361098f565b50604051600654816000610e2183610955565b80835292602090600190818116908115610dc85750600114610e4b575050610d64925003826109c1565b91509260066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f936000925b828410610e945750610d649450505081016020013880610d56565b85548785018301529485019486945092810192610e79565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411610f3057926020929160ff608095604051948552168484015260408301526060820152600092839182805260015afa15610f245780516001600160a01b03811615610f1b57918190565b50809160019190565b604051903d90823e3d90fd5b50505060009160039190565b6004811015610fab5780610f4e575050565b60018103610f685760405163f645eedf60e01b8152600490fd5b60028103610f895760405163fce698f760e01b815260048101839052602490fd5b600314610f935750565b602490604051906335e2f38360e21b82526004820152fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220f7cc8e66c14588fcaaa301e0efc5838bc7d5a238db77c59c60d1c4e13142fbda64736f6c63430008190033a264697066735822122090635580932afa136f3509fe1a6f5fd80cd7acbf795fb711604fe34c84f690a264736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000038d7ea4c6800000000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000f65330dc75e32b20be62f503a337cd1a072f898f00000000000000000000000039cd4db6460d8b5961f73e997e86ddbb7ca4d5f6000000000000000000000000e30521fe7f3beb6ad556887b50739d6c7ca667e6
-----Decoded View---------------
Arg [0] : _tradingFeeRate (uint256): 100
Arg [1] : _migrationFeeRate (uint256): 500
Arg [2] : _creationFee (uint256): 1000000000000000
Arg [3] : _initVirtualEthReserve (uint256): 100000000000000
Arg [4] : feeRecipient (address): 0xF65330dC75e32B20Be62f503a337cD1a072f898f
Arg [5] : router (address): 0x39cd4db6460d8B5961F73E997E86DdbB7Ca4D5F6
Arg [6] : factory (address): 0xE30521fe7f3bEB6Ad556887b50739d6C7CA667E6
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [1] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [2] : 00000000000000000000000000000000000000000000000000038d7ea4c68000
Arg [3] : 00000000000000000000000000000000000000000000000000005af3107a4000
Arg [4] : 000000000000000000000000f65330dc75e32b20be62f503a337cd1a072f898f
Arg [5] : 00000000000000000000000039cd4db6460d8b5961f73e997e86ddbb7ca4d5f6
Arg [6] : 000000000000000000000000e30521fe7f3beb6ad556887b50739d6c7ca667e6
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$1.26
Net Worth in FRAX
1.224385
Token Allocations
FRAX
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| FRAXTAL | 100.00% | $1.03 | 1.2272 | $1.26 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.