编译器
0.8.20+commit.a1b79de6
文件 1 的 10:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 2 的 10:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 3 的 10:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 4 的 10:ILpETH.sol
pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface ILpETH is IERC20 {
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
}
文件 5 的 10:ILpETHVault.sol
pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface ILpETHVault is IERC20 {
function stake(uint256 amount, address onBehalfOf, uint256 typeIndex) external;
}
文件 6 的 10:IMetaAggregationRouterV2.sol
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IMetaAggregationRouterV2 {
struct SwapDescriptionV2 {
IERC20 srcToken;
IERC20 dstToken;
address[] srcReceivers;
uint256[] srcAmounts;
address[] feeReceivers;
uint256[] feeAmounts;
address dstReceiver;
uint256 amount;
uint256 minReturnAmount;
uint256 flags;
bytes permit;
}
struct SwapExecutionParams {
address callTarget;
address approveTarget;
bytes targetData;
SwapDescriptionV2 desc;
bytes clientData;
}
struct SimpleSwapExecutionParams {
address caller;
SwapDescriptionV2 desc;
bytes executorData;
bytes clientData;
}
}
文件 7 的 10:IWETH.sol
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function withdraw(uint256) external;
}
文件 8 的 10:Math.sol
pragma solidity ^0.8.20;
library Math {
error MathOverflowedMulDiv();
enum Rounding {
Floor,
Ceil,
Trunc,
Expand
}
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);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
return a / b;
}
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0 = x * y;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (0 - denominator);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
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;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
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);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 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;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 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;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
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;
}
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);
}
}
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
文件 9 的 10:PrelaunchPoints.sol
pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import {ILpETH, IERC20} from "./interfaces/ILpETH.sol";
import {ILpETHVault} from "./interfaces/ILpETHVault.sol";
import {IWETH} from "./interfaces/IWETH.sol";
import {IMetaAggregationRouterV2} from "./interfaces/IMetaAggregationRouterV2.sol";
contract PrelaunchPoints {
using Math for uint256;
using SafeERC20 for IERC20;
using SafeERC20 for ILpETH;
ILpETH public lpETH;
ILpETHVault public lpETHVault;
IWETH public immutable WETH;
address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public immutable exchangeProxy;
address public owner;
address public proposedOwner;
uint256 public totalSupply;
uint256 public totalLpETH;
mapping(address => uint256) public maxDepositCap;
mapping(address => bool) public isTokenAllowed;
enum Exchange {
Swap,
SwapSimpleMode
}
bytes4 public constant SWAP_SELECTOR = 0xe21fd0e9;
bytes4 public constant SWAP_SIMPLE_MODE_SELECTOR = 0x8af033fb;
uint32 public loopActivation;
uint32 public startClaimDate;
uint32 public constant TIMELOCK = 7 days;
bool public emergencyMode;
mapping(address => mapping(address => uint256)) public balances;
event Locked(address indexed user, uint256 amount, address indexed token, bytes32 indexed referral);
event StakedVault(address indexed user, uint256 amount, uint256 typeIndex);
event Converted(uint256 amountETH, uint256 amountlpETH);
event Withdrawn(address indexed user, address indexed token, uint256 amount);
event Claimed(address indexed user, address indexed token, uint256 reward);
event Recovered(address token, uint256 amount);
event OwnerProposed(address newOwner);
event OwnerUpdated(address newOwner);
event LoopAddressesUpdated(address loopAddress, address vaultAddress);
event SwappedTokens(address sellToken, uint256 sellAmount, uint256 buyETHAmount);
event NewTokenAllowed(address token);
event DepositMaxCapUpdated(address indexed token, uint256 amount);
event EmergencyModeSet(bool mode);
error InvalidToken();
error NothingToClaim();
error TokenNotAllowed(address token);
error CannotLockZero();
error CannotClaimZero();
error CannotWithdrawZero();
error UseClaimInstead();
error FailedToSendEther();
error SellTokenApprovalFailed();
error SwapCallFailed();
error WrongSelector(bytes4 selector);
error WrongDataTokens(address inputToken, address outputToken);
error WrongDataAmount(uint256 inputTokenAmount);
error WrongRecipient(address recipient);
error WrongExchange();
error LoopNotActivated();
error NotValidToken();
error NotAuthorized();
error NotProposedOwner();
error CurrentlyNotPossible();
error NoLongerPossible();
error ReceiveDisabled();
error ArrayLenghtsDoNotMatch();
error MaxDepositCapReached(address token);
constructor(
address _exchangeProxy,
address _wethAddress,
address[] memory _allowedTokens,
uint256[] memory _initialMaxCap
) {
owner = msg.sender;
exchangeProxy = _exchangeProxy;
WETH = IWETH(_wethAddress);
loopActivation = uint32(block.timestamp + 120 days);
startClaimDate = 4294967295;
uint256 length = _allowedTokens.length;
if (_initialMaxCap.length != length + 1) {
revert ArrayLenghtsDoNotMatch();
}
for (uint256 i = 0; i < length;) {
isTokenAllowed[_allowedTokens[i]] = true;
_setDepositMaxCap(_allowedTokens[i], _initialMaxCap[i + 1]);
unchecked {
i++;
}
}
isTokenAllowed[_wethAddress] = true;
_setDepositMaxCap(_wethAddress, _initialMaxCap[0]);
}
function lockETH(bytes32 _referral) external payable {
_processLock(ETH, msg.value, msg.sender, _referral);
}
function lockETHFor(address _for, bytes32 _referral) external payable {
_processLock(ETH, msg.value, _for, _referral);
}
function lock(address _token, uint256 _amount, bytes32 _referral) external {
if (_token == ETH) {
revert InvalidToken();
}
_processLock(_token, _amount, msg.sender, _referral);
}
function lockFor(address _token, uint256 _amount, address _for, bytes32 _referral) external {
if (_token == ETH) {
revert InvalidToken();
}
_processLock(_token, _amount, _for, _referral);
}
function _processLock(address _token, uint256 _amount, address _receiver, bytes32 _referral)
internal
onlyBeforeDate(startClaimDate)
{
if (_amount == 0) {
revert CannotLockZero();
}
if (_token == ETH) {
WETH.deposit{value: _amount}();
if (IERC20(WETH).balanceOf(address(this)) > maxDepositCap[address(WETH)]) {
revert MaxDepositCapReached(address(WETH));
}
totalSupply += _amount;
balances[_receiver][address(WETH)] += _amount;
} else {
if (!isTokenAllowed[_token]) {
revert TokenNotAllowed(_token);
}
if (IERC20(_token).balanceOf(address(this)) + _amount > maxDepositCap[_token]) {
revert MaxDepositCapReached(_token);
}
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
if (_token == address(WETH)) {
totalSupply += _amount;
}
balances[_receiver][_token] += _amount;
}
emit Locked(_receiver, _amount, _token, _referral);
}
function claim(address _token, uint8 _percentage, Exchange _exchange, bytes calldata _data)
external
onlyAfterDate(startClaimDate)
{
_claim(_token, msg.sender, _percentage, _exchange, _data);
}
function claimAndStake(
address _token,
uint8 _percentage,
Exchange _exchange,
uint256 _typeIndex,
bytes calldata _data
) external onlyAfterDate(startClaimDate) {
uint256 claimedAmount = _claim(_token, address(this), _percentage, _exchange, _data);
lpETH.approve(address(lpETHVault), claimedAmount);
lpETHVault.stake(claimedAmount, msg.sender, _typeIndex);
emit StakedVault(msg.sender, claimedAmount, _typeIndex);
}
function _claim(address _token, address _receiver, uint8 _percentage, Exchange _exchange, bytes calldata _data)
internal
returns (uint256 claimedAmount)
{
if (_percentage == 0) {
revert CannotClaimZero();
}
uint256 userStake = balances[msg.sender][_token];
if (userStake == 0) {
revert NothingToClaim();
}
if (_token == address(WETH)) {
claimedAmount = userStake.mulDiv(totalLpETH, totalSupply);
balances[msg.sender][_token] = 0;
if (_receiver != address(this)) {
lpETH.safeTransfer(_receiver, claimedAmount);
}
} else {
uint256 userClaim = userStake * _percentage / 100;
_validateData(_token, userClaim, _exchange, _data);
balances[msg.sender][_token] = userStake - userClaim;
uint256 balanceWethBefore = WETH.balanceOf(address(this));
_fillQuote(IERC20(_token), userClaim, _data);
claimedAmount = WETH.balanceOf(address(this)) - balanceWethBefore;
WETH.approve(address(lpETH), claimedAmount);
lpETH.deposit(claimedAmount, _receiver);
}
emit Claimed(msg.sender, _token, claimedAmount);
}
function withdraw(address _token) external {
if (!emergencyMode) {
if (block.timestamp >= startClaimDate) {
revert NoLongerPossible();
}
}
uint256 lockedAmount = balances[msg.sender][_token];
balances[msg.sender][_token] = 0;
if (lockedAmount == 0) {
revert CannotWithdrawZero();
}
if (_token == address(WETH)) {
if (block.timestamp >= startClaimDate) {
revert UseClaimInstead();
}
totalSupply -= lockedAmount;
}
IERC20(_token).safeTransfer(msg.sender, lockedAmount);
emit Withdrawn(msg.sender, _token, lockedAmount);
}
function convertAllETH() external onlyAuthorized onlyBeforeDate(startClaimDate) {
if (block.timestamp <= TIMELOCK + loopActivation) {
revert LoopNotActivated();
}
WETH.approve(address(lpETH), totalSupply);
lpETH.deposit(totalSupply, address(this));
totalLpETH = lpETH.balanceOf(address(this));
startClaimDate = uint32(block.timestamp);
emit Converted(totalSupply, totalLpETH);
}
function proposeOwner(address _owner) external onlyAuthorized {
proposedOwner = _owner;
emit OwnerProposed(_owner);
}
function acceptOwnership() external {
if (msg.sender != proposedOwner) {
revert NotProposedOwner();
}
owner = proposedOwner;
emit OwnerUpdated(owner);
}
function setLoopAddresses(address _loopAddress, address _vaultAddress)
external
onlyAuthorized
onlyBeforeDate(loopActivation)
{
lpETH = ILpETH(_loopAddress);
lpETHVault = ILpETHVault(_vaultAddress);
loopActivation = uint32(block.timestamp);
emit LoopAddressesUpdated(_loopAddress, _vaultAddress);
}
function allowToken(address _token) external onlyAuthorized {
isTokenAllowed[_token] = true;
emit NewTokenAllowed(_token);
}
function setDepositMaxCaps(address[] memory _tokens, uint256[] memory _amounts) external onlyAuthorized {
uint256 length = _tokens.length;
if (length != _amounts.length) {
revert ArrayLenghtsDoNotMatch();
}
for (uint256 i = 0; i < length;) {
_setDepositMaxCap(_tokens[i], _amounts[i]);
emit DepositMaxCapUpdated(_tokens[i], _amounts[i]);
unchecked {
i++;
}
}
}
function setEmergencyMode(bool _mode) external onlyAuthorized {
emergencyMode = _mode;
emit EmergencyModeSet(_mode);
}
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyAuthorized {
if (tokenAddress == address(lpETH) || isTokenAllowed[tokenAddress]) {
revert NotValidToken();
}
IERC20(tokenAddress).safeTransfer(owner, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
}
receive() external payable {
revert ReceiveDisabled();
}
function _validateData(address _token, uint256 _amount, Exchange _exchange, bytes calldata _data) internal view {
address inputToken;
address outputToken;
uint256 inputTokenAmount;
address recipient;
bytes4 selector;
if (_exchange == Exchange.Swap) {
(inputToken, outputToken, inputTokenAmount, recipient, selector) = _decodeSwapTargetData(_data);
if (selector != SWAP_SELECTOR) {
revert WrongSelector(selector);
}
} else if (_exchange == Exchange.SwapSimpleMode) {
(inputToken, outputToken, inputTokenAmount, recipient, selector) = _decodeSwapSimpleMode(_data);
if (selector != SWAP_SIMPLE_MODE_SELECTOR) {
revert WrongSelector(selector);
}
} else {
revert WrongExchange();
}
if (inputToken != _token) {
revert WrongDataTokens(inputToken, outputToken);
}
if (outputToken != address(WETH)) {
revert WrongDataTokens(inputToken, outputToken);
}
if (inputTokenAmount != _amount) {
revert WrongDataAmount(inputTokenAmount);
}
if (recipient != address(this)) {
revert WrongRecipient(recipient);
}
}
function _decodeSwapTargetData(bytes calldata _data)
internal
pure
returns (address inputToken, address outputToken, uint256 inputTokenAmount, address recipient, bytes4 selector)
{
assembly {
let p := _data.offset
selector := calldataload(p)
}
(,,, IMetaAggregationRouterV2.SwapDescriptionV2 memory desc,) =
abi.decode(_data[36:], (address, address, bytes, IMetaAggregationRouterV2.SwapDescriptionV2, bytes));
inputToken = address(desc.srcToken);
outputToken = address(desc.dstToken);
recipient = desc.dstReceiver;
inputTokenAmount = desc.amount;
}
function _decodeSwapSimpleMode(bytes calldata _data)
internal
pure
returns (address inputToken, address outputToken, uint256 inputTokenAmount, address recipient, bytes4 selector)
{
assembly {
let p := _data.offset
selector := calldataload(p)
}
(, IMetaAggregationRouterV2.SwapDescriptionV2 memory desc,,) =
abi.decode(_data[4:], (address, IMetaAggregationRouterV2.SwapDescriptionV2, bytes, bytes));
inputToken = address(desc.srcToken);
outputToken = address(desc.dstToken);
recipient = desc.dstReceiver;
inputTokenAmount = desc.amount;
}
function _fillQuote(IERC20 _sellToken, uint256 _amount, bytes calldata _swapCallData) internal {
uint256 boughtWETHAmount = WETH.balanceOf(address(this));
if (!_sellToken.approve(exchangeProxy, _amount)) {
revert SellTokenApprovalFailed();
}
(bool success,) = payable(exchangeProxy).call{value: 0}(_swapCallData);
if (!success) {
revert SwapCallFailed();
}
boughtWETHAmount = WETH.balanceOf(address(this)) - boughtWETHAmount;
emit SwappedTokens(address(_sellToken), _amount, boughtWETHAmount);
}
function _setDepositMaxCap(address _token, uint256 _amount) internal {
if (!isTokenAllowed[_token]) {
revert TokenNotAllowed(_token);
}
maxDepositCap[_token] = _amount;
}
modifier onlyAuthorized() {
if (msg.sender != owner) {
revert NotAuthorized();
}
_;
}
modifier onlyAfterDate(uint256 limitDate) {
if (block.timestamp <= limitDate) {
revert CurrentlyNotPossible();
}
_;
}
modifier onlyBeforeDate(uint256 limitDate) {
if (block.timestamp >= limitDate) {
revert NoLongerPossible();
}
_;
}
}
文件 10 的 10:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
{
"compilationTarget": {
"src/PrelaunchPoints.sol": "PrelaunchPoints"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 100
},
"remappings": [
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/"
]
}
[{"inputs":[{"internalType":"address","name":"_exchangeProxy","type":"address"},{"internalType":"address","name":"_wethAddress","type":"address"},{"internalType":"address[]","name":"_allowedTokens","type":"address[]"},{"internalType":"uint256[]","name":"_initialMaxCap","type":"uint256[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ArrayLenghtsDoNotMatch","type":"error"},{"inputs":[],"name":"CannotClaimZero","type":"error"},{"inputs":[],"name":"CannotLockZero","type":"error"},{"inputs":[],"name":"CannotWithdrawZero","type":"error"},{"inputs":[],"name":"CurrentlyNotPossible","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FailedToSendEther","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"LoopNotActivated","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"MaxDepositCapReached","type":"error"},{"inputs":[],"name":"NoLongerPossible","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotProposedOwner","type":"error"},{"inputs":[],"name":"NotValidToken","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[],"name":"ReceiveDisabled","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SellTokenApprovalFailed","type":"error"},{"inputs":[],"name":"SwapCallFailed","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"TokenNotAllowed","type":"error"},{"inputs":[],"name":"UseClaimInstead","type":"error"},{"inputs":[{"internalType":"uint256","name":"inputTokenAmount","type":"uint256"}],"name":"WrongDataAmount","type":"error"},{"inputs":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"}],"name":"WrongDataTokens","type":"error"},{"inputs":[],"name":"WrongExchange","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"WrongRecipient","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"WrongSelector","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountlpETH","type":"uint256"}],"name":"Converted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositMaxCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"mode","type":"bool"}],"name":"EmergencyModeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"bytes32","name":"referral","type":"bytes32"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"loopAddress","type":"address"},{"indexed":false,"internalType":"address","name":"vaultAddress","type":"address"}],"name":"LoopAddressesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"NewTokenAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"typeIndex","type":"uint256"}],"name":"StakedVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sellToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"sellAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"buyETHAmount","type":"uint256"}],"name":"SwappedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"ETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWAP_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWAP_SIMPLE_MODE_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"allowToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint8","name":"_percentage","type":"uint8"},{"internalType":"enum PrelaunchPoints.Exchange","name":"_exchange","type":"uint8"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint8","name":"_percentage","type":"uint8"},{"internalType":"enum PrelaunchPoints.Exchange","name":"_exchange","type":"uint8"},{"internalType":"uint256","name":"_typeIndex","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"claimAndStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"convertAllETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isTokenAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_referral","type":"bytes32"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_referral","type":"bytes32"}],"name":"lockETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_for","type":"address"},{"internalType":"bytes32","name":"_referral","type":"bytes32"}],"name":"lockETHFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_for","type":"address"},{"internalType":"bytes32","name":"_referral","type":"bytes32"}],"name":"lockFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"loopActivation","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpETH","outputs":[{"internalType":"contract ILpETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpETHVault","outputs":[{"internalType":"contract ILpETHVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDepositCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"proposeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proposedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"setDepositMaxCaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_mode","type":"bool"}],"name":"setEmergencyMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_loopAddress","type":"address"},{"internalType":"address","name":"_vaultAddress","type":"address"}],"name":"setLoopAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startClaimDate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLpETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]