Feature Tip: Add private address tag to any address under My Name Tag !
Latest 25 from a total of 1,299 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Migrate Se PSP1t... | 24533444 | 4 days ago | IN | 0.00003661 ETH | 0.0000547 | ||||
| Migrate Se PSP1t... | 24468796 | 13 days ago | IN | 0 ETH | 0.00000657 | ||||
| Migrate PS Pto V... | 24456713 | 15 days ago | IN | 0 ETH | 0.00000621 | ||||
| Migrate Se PSP2t... | 24430313 | 19 days ago | IN | 0 ETH | 0.00002793 | ||||
| Migrate Se PSP1t... | 24354160 | 29 days ago | IN | 0 ETH | 0.00002038 | ||||
| Migrate PS Pto V... | 24354074 | 29 days ago | IN | 0 ETH | 0.00001618 | ||||
| Migrate Se PSP1t... | 24298425 | 37 days ago | IN | 0 ETH | 0.00003979 | ||||
| Migrate PS Pto V... | 24294903 | 37 days ago | IN | 0 ETH | 0.00001419 | ||||
| Migrate Se PSP2t... | 24288662 | 38 days ago | IN | 0 ETH | 0.00003047 | ||||
| Migrate Se PSP1t... | 24286211 | 39 days ago | IN | 0.01500443 ETH | 0.00037152 | ||||
| Migrate Se PSP2t... | 24285205 | 39 days ago | IN | 0 ETH | 0.00014805 | ||||
| Migrate PS Pto V... | 24262391 | 42 days ago | IN | 0 ETH | 0.00001236 | ||||
| Migrate Se PSP2t... | 24262353 | 42 days ago | IN | 0 ETH | 0.00007941 | ||||
| Migrate Se PSP1t... | 24261482 | 42 days ago | IN | 0 ETH | 0.00000861 | ||||
| Migrate Se PSP1t... | 24250980 | 44 days ago | IN | 0 ETH | 0.00001475 | ||||
| Migrate Se PSP2t... | 24234023 | 46 days ago | IN | 0 ETH | 0.00053539 | ||||
| Migrate Se PSP2t... | 24226634 | 47 days ago | IN | 0 ETH | 0.00028806 | ||||
| Migrate PS Pto V... | 24174858 | 54 days ago | IN | 0 ETH | 0.00001576 | ||||
| Migrate Se PSP2t... | 24161751 | 56 days ago | IN | 0 ETH | 0.00035115 | ||||
| Migrate PS Pto V... | 24160187 | 56 days ago | IN | 0 ETH | 0.00001504 | ||||
| Migrate PS Pto V... | 24157357 | 57 days ago | IN | 0 ETH | 0.00000418 | ||||
| Migrate Se PSP1t... | 24147034 | 58 days ago | IN | 0 ETH | 0.00000637 | ||||
| Migrate Se PSP2t... | 24143560 | 59 days ago | IN | 0 ETH | 0.00003219 | ||||
| Migrate Se PSP1t... | 24132478 | 60 days ago | IN | 0 ETH | 0.00002174 | ||||
| Migrate PS Pto V... | 24128046 | 61 days ago | IN | 0 ETH | 0.00001621 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Deposit VLR And ... | 24533444 | 4 days ago | 0.00003661 ETH | ||||
| Deposit VLR And ... | 24286211 | 39 days ago | 0.01500443 ETH | ||||
| Deposit VLR And ... | 24126427 | 61 days ago | 0.00004713 ETH | ||||
| Deposit VLR And ... | 24114322 | 63 days ago | 0.00058935 ETH | ||||
| Deposit VLR And ... | 24017025 | 76 days ago | 0.00372644 ETH | ||||
| Deposit VLR And ... | 24015828 | 76 days ago | 0.00003126 ETH | ||||
| Deposit VLR And ... | 24010961 | 77 days ago | 0.00516222 ETH | ||||
| Deposit VLR And ... | 24010929 | 77 days ago | 0.00413682 ETH | ||||
| Deposit VLR And ... | 24003173 | 78 days ago | 0.00004459 ETH | ||||
| Migrate Se PSP1t... | 24003173 | 78 days ago | 0.00004459 ETH | ||||
| Deposit VLR And ... | 24003157 | 78 days ago | 0.00004447 ETH | ||||
| Migrate Se PSP1t... | 24003157 | 78 days ago | 0.00004447 ETH | ||||
| Deposit VLR And ... | 24003096 | 78 days ago | 0.00004453 ETH | ||||
| Migrate Se PSP1t... | 24003096 | 78 days ago | 0.00004453 ETH | ||||
| Deposit VLR And ... | 23995291 | 79 days ago | 0.00694325 ETH | ||||
| Migrate Se PSP1t... | 23995291 | 79 days ago | 0.00694325 ETH | ||||
| Deposit VLR And ... | 23941376 | 87 days ago | 0.00003741 ETH | ||||
| Migrate Se PSP1t... | 23941376 | 87 days ago | 0.00003741 ETH | ||||
| Deposit VLR And ... | 23876845 | 96 days ago | 0.99534093 ETH | ||||
| Migrate Se PSP1t... | 23876845 | 96 days ago | 0.99534093 ETH | ||||
| Deposit VLR And ... | 23862590 | 98 days ago | 0.00112322 ETH | ||||
| Deposit VLR And ... | 23834831 | 102 days ago | 0.00362448 ETH | ||||
| Migrate Se PSP1t... | 23834831 | 102 days ago | 0.00362448 ETH | ||||
| Deposit VLR And ... | 23797739 | 107 days ago | 0.03385796 ETH | ||||
| Deposit VLR And ... | 23783266 | 109 days ago | 0.01023978 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xA3556F2d...790bFf6fc The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
MiroMigrator
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
// Contracts
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol";
// Interfaces
import { IMiroMigrator } from "./interfaces/IMiroMigrator.sol";
import { IAcrossSpokePool } from "./interfaces/IAcrossSpokePool.sol";
import { ISeVLR } from "./interfaces/ISeVLR.sol";
import { ISePSP2 } from "./interfaces/ISePSP2.sol";
// Libraries
import { SafeTransferLib } from "solady/src/utils/SafeTransferLib.sol";
import { ERC20UtilsLib } from "./libraries/ERC20UtilsLib.sol";
import { WethLib } from "./libraries/WethLib.sol";
/// @title Miro Migrator contract
/// @author Laita Labs
/// @notice Migrator for Miro project.
/// Allows to migrate from legacy PSP staking, including sePSP1 and sePSP2
contract MiroMigrator is IMiroMigrator, Ownable, Pausable {
/*//////////////////////////////////////////////////////////////
LIBRARIES
//////////////////////////////////////////////////////////////*/
using SafeTransferLib for address;
using ERC20UtilsLib for address;
using WethLib for address;
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
/// @notice PSP token address
address public immutable PSP;
/// @notice VLR token address
address public immutable VLR;
/// @notice WETH token address
address public immutable WETH;
/// @notice Address to send burned tokens to
address private constant BURN_ADDR = 0x000000000000000000000000000000000000dEaD;
/// @notice seVLR staked token address
address public immutable SE_VLR;
/// @notice sePSP1 staked token address
address public immutable SE_PSP1;
/// @notice sePSP2 staked token address
address public immutable SE_PSP2;
/// @notice Across protocol's Spoke Pool address
IAcrossSpokePool public immutable SPOKE_POOL;
/// @notice Mapping for configured destination chain ids for cross-chain bridging
mapping(uint256 chainId => BridgeConfig config) public bridgeConfigs;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/// @param _bridgeConfigs Configuration for destination chain ids for cross-chain bridging
/// @param sePSP1 sePSP1 staked token address
/// @param sePSP2 sePSP2 staked token address
/// @param seVLR seVLR staked token address
/// @param spokePool Across protocol's Spoke Pool address
constructor(
BridgeConfig[] memory _bridgeConfigs,
address sePSP1,
address sePSP2,
address seVLR,
IAcrossSpokePool spokePool
) Ownable(msg.sender) {
SE_PSP1 = sePSP1;
SE_PSP2 = sePSP2;
SE_VLR = seVLR;
PSP = ISePSP2(SE_PSP2).PSP();
VLR = ISeVLR(SE_VLR).VLR();
WETH = ISeVLR(SE_VLR).WETH();
SPOKE_POOL = spokePool;
for (uint256 i = 0; i < _bridgeConfigs.length; i++) {
bridgeConfigs[_bridgeConfigs[i].destChainId] = _bridgeConfigs[i];
}
// pre-approve
VLR.safeApprove(address(SE_VLR), type(uint256).max);
WETH.safeApprove(address(SE_VLR), type(uint256).max);
}
/*//////////////////////////////////////////////////////////////
MIGRATE
//////////////////////////////////////////////////////////////*/
/// @inheritdoc IMiroMigrator
function migratePSPtoVLR(uint256 pspAmount, bytes calldata permitData) external whenNotPaused {
PSP.permit(permitData);
PSP.safeTransferFrom(msg.sender, BURN_ADDR, pspAmount);
VLR.safeTransfer(msg.sender, pspAmount);
emit Migrated(msg.sender, pspAmount);
}
/// @inheritdoc IMiroMigrator
function migrateSePSP1toVLR(uint256 sePSP1Amount, bytes calldata permitData) external whenNotPaused {
SE_PSP1.permit(permitData);
SE_PSP1.safeTransferFrom(msg.sender, BURN_ADDR, sePSP1Amount);
VLR.safeTransfer(msg.sender, sePSP1Amount);
emit Migrated(msg.sender, sePSP1Amount);
}
/// @inheritdoc IMiroMigrator
function migratePSPtoSeVLR(
uint256 pspAmount,
uint256 wethAmount,
uint256 minBptOut,
bytes calldata permitData
) external payable whenNotPaused {
PSP.permit(permitData);
PSP.safeTransferFrom(msg.sender, BURN_ADDR, pspAmount);
if (msg.value > 0) {
if (msg.value != wethAmount) {
revert InsufficientMsgValue();
}
ISeVLR(SE_VLR).depositVLRAndEth{ value: msg.value }(pspAmount, minBptOut, msg.sender, "");
} else {
WETH.safeTransferFrom(msg.sender, address(this), wethAmount);
ISeVLR(SE_VLR).depositVLRAndWeth(pspAmount, wethAmount, minBptOut, msg.sender, "");
}
emit Migrated(msg.sender, pspAmount);
}
/// @inheritdoc IMiroMigrator
function migrateSePSP1toSeVLR(
uint256 sePSP1Amount,
uint256 wethAmount,
uint256 minBptOut,
bytes calldata permitData
) external payable whenNotPaused {
SE_PSP1.permit(permitData);
SE_PSP1.safeTransferFrom(msg.sender, BURN_ADDR, sePSP1Amount);
if (msg.value > 0) {
if (msg.value != wethAmount) {
revert InsufficientMsgValue();
}
ISeVLR(SE_VLR).depositVLRAndEth{ value: msg.value }(sePSP1Amount, minBptOut, msg.sender, "");
} else {
WETH.safeTransferFrom(msg.sender, address(this), wethAmount);
ISeVLR(SE_VLR).depositVLRAndWeth(sePSP1Amount, wethAmount, minBptOut, msg.sender, "");
}
emit Migrated(msg.sender, sePSP1Amount);
}
/// @inheritdoc IMiroMigrator
function migrateSePSP2toSeVLR(
uint256 sePSP2Amount,
uint256 minPspAmount,
uint256 minWethAmount,
uint256 minBptOut,
bytes calldata permitData
) external whenNotPaused {
SE_PSP2.permit(permitData);
// Unstake sePSP2
(uint256 pspAmount, uint256 wethAmount) = _unstakeSePSP2(sePSP2Amount, minPspAmount, minWethAmount);
// Burn PSP
PSP.safeTransfer(BURN_ADDR, pspAmount);
// Deposit VLR + WETH -> seVLR with msg.sender as beneficiary, PSP to VLR is 1:1
ISeVLR(SE_VLR).depositVLRAndWeth(pspAmount, wethAmount, minBptOut, msg.sender, "");
emit Migrated(msg.sender, pspAmount);
}
/*//////////////////////////////////////////////////////////////
BRIDGE
//////////////////////////////////////////////////////////////*/
/// @inheritdoc IMiroMigrator
function bridgeVLRAndStake(
uint256 vlrAmount,
uint256 wethAmount,
uint256 destChainId,
uint256 minDestBptAmount,
address beneficiary,
BridgeData calldata vlrBridgeData,
BridgeData calldata wethBridgeData,
bytes calldata permitData
) external payable whenNotPaused {
// Make sure destination chain is supported
if (bridgeConfigs[destChainId].destChainId == 0) {
revert InvalidDestinationChainId();
}
if (beneficiary == address(0)) {
beneficiary = msg.sender;
}
VLR.permit(permitData);
VLR.safeTransferFrom(msg.sender, address(this), vlrAmount);
if (msg.value > 0) {
if (msg.value != wethAmount) {
revert InsufficientMsgValue();
}
WETH.deposit();
} else {
WETH.safeTransferFrom(msg.sender, address(this), wethAmount);
}
// Get ID for the bridge message
uint256 id = ISeVLR(SE_VLR).useNextId(beneficiary);
// Encode the message
bytes memory message = _encodeBridgeMessage(
id,
vlrAmount - vlrBridgeData.relayerFee,
wethAmount - wethBridgeData.relayerFee,
minDestBptAmount,
beneficiary
);
// Bridge VLR
_bridgeAcross(vlrAmount, false, destChainId, vlrBridgeData, message);
// Bridge WETH
_bridgeAcross(wethAmount, true, destChainId, wethBridgeData, message);
emit StakeBridgingInitiated(beneficiary, vlrAmount, wethAmount, destChainId, message);
}
/// @inheritdoc IMiroMigrator
function migrateSePSP2toSeVLRAndBridge(
uint256 sePSP2Amount,
uint256 minPspAmount,
uint256 minWethAmount,
uint256 destChainId,
uint256 minDestBptAmount,
address beneficiary,
BridgeData calldata vlrBridgeData,
BridgeData calldata wethBridgeData,
bytes calldata permitData
) external whenNotPaused {
// Make sure destination chain is supported
if (bridgeConfigs[destChainId].destChainId == 0) {
revert InvalidDestinationChainId();
}
if (beneficiary == address(0)) {
beneficiary = msg.sender;
}
SE_PSP2.permit(permitData);
(uint256 vlrAmount, uint256 wethAmount) = _unstakeSePSP2(sePSP2Amount, minPspAmount, minWethAmount);
// Get ID for the bridge message
uint256 id = ISeVLR(SE_VLR).useNextId(beneficiary);
// Burn PSP
PSP.safeTransfer(BURN_ADDR, vlrAmount);
// Emit Migrated event
emit Migrated(beneficiary, vlrAmount);
// Encode the message
bytes memory message = _encodeBridgeMessage(
id,
vlrAmount - vlrBridgeData.relayerFee,
wethAmount - wethBridgeData.relayerFee,
minDestBptAmount,
beneficiary
);
// Bridge VLR
_bridgeAcross(vlrAmount, false, destChainId, vlrBridgeData, message);
// Bridge WETH
_bridgeAcross(wethAmount, true, destChainId, wethBridgeData, message);
emit StakeBridgingInitiated(beneficiary, vlrAmount, wethAmount, destChainId, message);
}
/*//////////////////////////////////////////////////////////////
RECLAIM
//////////////////////////////////////////////////////////////*/
/// @inheritdoc IMiroMigrator
function reClaimVLR(address to) external onlyOwner {
VLR.safeTransfer(to, VLR.getBalance());
}
/*//////////////////////////////////////////////////////////////
ADMIN
//////////////////////////////////////////////////////////////*/
/// @inheritdoc IMiroMigrator
function setBridgeConfigs(BridgeConfig[] calldata _bridgeConfigs) external onlyOwner {
for (uint256 i = 0; i < _bridgeConfigs.length; i++) {
bridgeConfigs[_bridgeConfigs[i].destChainId] = _bridgeConfigs[i];
}
}
/// @inheritdoc IMiroMigrator
function pause() external onlyOwner {
_pause();
}
/// @inheritdoc IMiroMigrator
function unpause() external onlyOwner {
_unpause();
}
/*//////////////////////////////////////////////////////////////
INTERNAL
//////////////////////////////////////////////////////////////*/
/// @notice Internal function to unstake sePSP2
/// @param sePSP2Amount sePSP2 amount to unstake
/// @return (pspAmount, wethAmount) Withdrawal request id with received PSP and WETH amounts
function _unstakeSePSP2(
uint256 sePSP2Amount,
uint256 minPspAmount,
uint256 minWethAmount
) internal returns (uint256, uint256) {
SE_PSP2.safeTransferFrom(msg.sender, address(this), sePSP2Amount);
// The following withdraw request will have this id
int256 withdrawRequestId = ISePSP2(SE_PSP2).userVsNextID(address(this));
// Unstake sePSP2
ISePSP2(SE_PSP2).requestWithdraw(sePSP2Amount);
// Withdraw sePSP2 -> PSP + WETH
ISePSP2(SE_PSP2).withdrawPSPAndWeth(withdrawRequestId, minPspAmount, minWethAmount);
// Just withdrawn
uint256 wethAmount = WETH.getBalance();
uint256 pspAmount = PSP.getBalance();
return (pspAmount, wethAmount);
}
/// @notice Internal function to encode bridge staking message
/// @param id Staking ID
/// @param vlrAmount Amount of VLR to bridge and stake
/// @param wethAmount Amount of WETH to bridge and stake
/// @param minDestBptAmount Minimum amount of BPT token on dest chain to receive
/// @param beneficiary Staking beneficiary
/// @return message Encoded data for BridgeStaking contract, including chain ID
function _encodeBridgeMessage(
uint256 id,
uint256 vlrAmount,
uint256 wethAmount,
uint256 minDestBptAmount,
address beneficiary
) internal view returns (bytes memory message) {
return abi.encode(id, block.chainid, vlrAmount, wethAmount, minDestBptAmount, beneficiary);
}
/// @notice Internal function to deposit funds to Across Spoke Pool during cross-chain bridging
/// @param amount Token amount to deposit
/// @param isWeth Indicates if deposited token is WETH or VLR
/// @param destChainId Destination chain id for the deposit
/// @param bridgeData Struct containing data for performing cross-chain bridging
/// @param message Encoded data for BridgeStaking contract
function _bridgeAcross(
uint256 amount,
bool isWeth,
uint256 destChainId,
BridgeData memory bridgeData,
bytes memory message
) internal {
if (isWeth) {
WETH.safeApprove(address(SPOKE_POOL), amount);
} else {
VLR.safeApprove(address(SPOKE_POOL), amount);
}
SPOKE_POOL.depositV3(
msg.sender,
bridgeConfigs[destChainId].bridgeStaking,
isWeth ? address(WETH) : address(VLR),
isWeth ? bridgeConfigs[destChainId].weth : bridgeConfigs[destChainId].vlr,
amount,
amount - bridgeData.relayerFee,
destChainId,
bridgeData.exclusiveRelayer,
bridgeData.quoteTimestamp,
bridgeData.fillDeadline,
bridgeData.exclusivityDeadline,
message
);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.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) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/// @notice Interface for Across SpokePool contracts to perform bridge
interface IAcrossSpokePool {
/*//////////////////////////////////////////////////////////////
DEPOSIT
//////////////////////////////////////////////////////////////*/
/// @notice Deposits tokens into the pool
/// @dev This function allows to deposit tokens on origin chain and receive tokens on destination chain
/// @param depositor The address of the depositor
/// @param recipient The address of the recipient
/// @param inputToken The address of the input token
/// @param outputToken The address of the output token
/// @param inputAmount The amount of input tokens to deposit
/// @param outputAmount The amount of output tokens to receive
/// @param destinationChainId The ID of the destination chain
/// @param exclusiveRelayer The address of the exclusive relayer
/// @param quoteTimestamp The timestamp of the quote
/// @param fillDeadline The deadline for filling the deposit
/// @param exclusivityDeadline The deadline for exclusivity
/// @param message Additional message or data
function depositV3(
address depositor,
address recipient,
address inputToken,
address outputToken,
uint256 inputAmount,
uint256 outputAmount,
uint256 destinationChainId,
address exclusiveRelayer,
uint32 quoteTimestamp,
uint32 fillDeadline,
uint32 exclusivityDeadline,
bytes calldata message
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/// @notice Interface for Miro Project Migrator contract
/// @author Laita Labs
interface IMiroMigrator {
/*//////////////////////////////////////////////////////////////
TYPES
//////////////////////////////////////////////////////////////*/
/// @notice Struct containing configuration for destination chain for cross-chain bridging
struct BridgeConfig {
address vlr;
address weth;
address bridgeStaking;
uint256 destChainId;
}
/// @notice Struct containing data for performing cross-chain bridging
struct BridgeData {
/// @dev The fee charged by the relayer for this transaction
uint256 relayerFee;
/// @dev The address of the relayer that has exclusive rights to process this transaction
address exclusiveRelayer;
/// @dev The timestamp when the quote was provided
uint32 quoteTimestamp;
/// @dev The deadline by which the transaction must be filled
uint32 fillDeadline;
/// @dev The deadline until which the relayer has exclusive rights to process the transaction
uint32 exclusivityDeadline;
}
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/// @notice Insufficient msg.value for the operation
error InsufficientMsgValue();
/// @notice Given destination chain is not in config
error InvalidDestinationChainId();
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/// @notice PSP to VLR migration completed
/// @param user Beneficiary of the migration
/// @param amount Amount of PSP tokens migrated to VLR
event Migrated(address indexed user, uint256 indexed amount);
/// @notice Stake bridging has been initiated with deposits to Across Pool
/// @param user Beneficiary of the staking
/// @param vlrAmount VLR amount to bridge & stake
/// @param wethAmount WETH amount to bridge & stake
/// @param destChainId Destination chain
/// @param message Encoded message for `handleAcrossMessage`
event StakeBridgingInitiated(
address indexed user,
uint256 indexed vlrAmount,
uint256 indexed wethAmount,
uint256 destChainId,
bytes message
);
/*//////////////////////////////////////////////////////////////
MIGRATE
//////////////////////////////////////////////////////////////*/
/// @notice Migrates PSP to VLR 1:1
/// @param pspAmount Amount of PSP to migrate
/// @param permitData Optional encoded PSP permit data
function migratePSPtoVLR(uint256 pspAmount, bytes calldata permitData) external;
/// @notice Migrates sePSP1 to VLR 1:1
/// @param sePSP1Amount Amount of sePSP1 to migrate
/// @param permitData Optional encoded sePSP1 permit data
function migrateSePSP1toVLR(uint256 sePSP1Amount, bytes calldata permitData) external;
/// @notice Migrates PSP to VLR and deposits ETH/WETH to seVLR
/// @param pspAmount Amount of PSP to migrate
/// @param wethAmount Amount of ETH/WETH to deposit
/// @param minBptOut Minimum received amount of seVLR
/// @param permitData Optional encoded PSP permit data
function migratePSPtoSeVLR(
uint256 pspAmount,
uint256 wethAmount,
uint256 minBptOut,
bytes calldata permitData
) external payable;
/// @notice Migrates sePSP1 to VLR and deposits ETH/WETH to seVLR
/// @param sePSP1Amount Amount of sePSP1 to migrate
/// @param wethAmount Amount of ETH/WETH to deposit
/// @param minBptOut Minimum received amount of seVLR
/// @param permitData Optional encoded PSP permit data
function migrateSePSP1toSeVLR(
uint256 sePSP1Amount,
uint256 wethAmount,
uint256 minBptOut,
bytes calldata permitData
) external payable;
/// @notice Migrates sePSP2 to seVLR
/// @param sePSP2Amount Amount of sePSP2 to migrate
/// @param minPspAmount Minimum PSP amount to unstake
/// @param minWethAmount Minimum WETH amount to unstake
/// @param minBptOut Minimum received amount of seVLR
/// @param permitData Optional encoded sePSP2 permit data
function migrateSePSP2toSeVLR(
uint256 sePSP2Amount,
uint256 minPspAmount,
uint256 minWethAmount,
uint256 minBptOut,
bytes calldata permitData
) external;
/*//////////////////////////////////////////////////////////////
BRIDGE
//////////////////////////////////////////////////////////////*/
/// @notice Bridges both VLR and WETH and then stakes to seVLR on another supported chain
/// @param vlrAmount The amount of VLR tokens to stake
/// @param wethAmount The amount of WETH tokens to bridge
/// @param destChainId Destination chain
/// @param minDestBptAmount Minimum amount of BPT token on dest chain to receive
/// @param beneficiary Address to receive seVLR on destination chain
/// @param vlrBridgeData Struct containing data for performing cross-chain bridging of VLR using Across Protocol
/// @param wethBridgeData Struct containing data for performing cross-chain bridging of WETH using Across Protocol
/// @param permitData Optional encoded VLR permit data
function bridgeVLRAndStake(
uint256 vlrAmount,
uint256 wethAmount,
uint256 destChainId,
uint256 minDestBptAmount,
address beneficiary,
BridgeData calldata vlrBridgeData,
BridgeData calldata wethBridgeData,
bytes calldata permitData
) external payable;
/// @notice Migrates sePSP2 to seVLR and bridges seVLR to another supported chain
/// @param sePSP2Amount Amount of sePSP2 to migrate
/// @param minPspAmount Minimum PSP amount to unstake
/// @param minWethAmount Minimum WETH amount to unstake
/// @param destChainId Destination chain to receive seVLR on
/// @param minDestBptAmount Minimum amount of BPT token on dest chain to receive
/// @param beneficiary Address to receive seVLR on destination chain
/// @param vlrBridgeData Struct containing data for performing cross-chain bridging of VLR using Across Protocol
/// @param wethBridgeData Struct containing data for performing cross-chain bridging of WETH using Across Protocol
/// @param permitData Optional encoded sePSP permit data
function migrateSePSP2toSeVLRAndBridge(
uint256 sePSP2Amount,
uint256 minPspAmount,
uint256 minWethAmount,
uint256 destChainId,
uint256 minDestBptAmount,
address beneficiary,
BridgeData calldata vlrBridgeData,
BridgeData calldata wethBridgeData,
bytes calldata permitData
) external;
/*//////////////////////////////////////////////////////////////
RECLAIM
//////////////////////////////////////////////////////////////*/
/// @notice Allows owner to send contract's seVLR balance to a given address
/// For emergency use only
function reClaimVLR(address to) external;
/*//////////////////////////////////////////////////////////////
ADMIN
//////////////////////////////////////////////////////////////*/
/// @notice Sets bridge configurations for cross-chain stake bridging
function setBridgeConfigs(BridgeConfig[] calldata _bridgeConfigs) external;
/// @notice Pauses migration operations
function pause() external;
/// @notice Unpauses migration operations
function unpause() external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @title Interface for sePSP2 Staking Token
interface ISePSP2 is IERC20 {
/*//////////////////////////////////////////////////////////////
VIEW
//////////////////////////////////////////////////////////////*/
/// @notice PSP token address
function PSP() external view returns (address);
/// @notice WETH token address
function WETH() external view returns (address);
/// @notice Mapping to index user's withdrawal request ids. Meant to only be incremented by 1 for each new request
function userVsNextID(address owner) external returns (int256);
/*//////////////////////////////////////////////////////////////
DEPOSIT
//////////////////////////////////////////////////////////////*/
/// @notice Deposits PSP and ETH to join 20WETH-80PSP liquidity pool and receive sePSP2
/// @param pspAmount PSP token amount to deposit
/// @param minBptOut Minimum liquidity tokens to receive
/// @param pspPermit Optional PSP encoded permit data
function depositPSPAndEth(uint256 pspAmount, uint256 minBptOut, bytes memory pspPermit) external payable;
/// @notice Deposits PSP and ETH to join 20WETH-80PSP liquidity pool and receive sePSP2
/// @param pspAmount PSP token amount to deposit
/// @param wethAmount WETH token amount to deposit
/// @param minBptOut Minimum liquidity tokens to receive
/// @param pspPermit Optional PSP encoded permit data
function depositPSPAndWeth(
uint256 pspAmount,
uint256 wethAmount,
uint256 minBptOut,
bytes memory pspPermit
) external;
/*//////////////////////////////////////////////////////////////
WITHDRAW
//////////////////////////////////////////////////////////////*/
/// @notice Creates a withdrawal request for the given amount of asset tokens
/// @param amount The amount to withdraw
function requestWithdraw(uint256 amount) external;
/// @notice Withdraws PSP and WETH requested by given withdrawal request id
/// @param id Withdrawal request id
/// @param minPspAmount Minimum PSP token amount to receive
/// @param minWethAmount Minimum WETH amount to receive
function withdrawPSPAndWeth(int256 id, uint256 minPspAmount, uint256 minWethAmount) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import { ITimeLockedERC20 } from "../token/interfaces/ITimeLockedERC20.sol";
/// @title Interface for seVLR Staking Token
/// @author Laita Labs
interface ISeVLR is ITimeLockedERC20 {
/*//////////////////////////////////////////////////////////////
VIEW
//////////////////////////////////////////////////////////////*/
/// @notice VLR token address
function VLR() external view returns (address);
/// @notice WETH token address
function WETH() external view returns (address);
/*//////////////////////////////////////////////////////////////
DEPOSIT
//////////////////////////////////////////////////////////////*/
/// @notice Deposits VLR and ETH to join 20WETH-80VLR liquidity pool and receive seVLR
/// @param vlrAmount VLR token amount to deposit
/// @param minBptOut Minimum liquidity tokens to receive
/// @param beneficiary Beneficiary of the deposit
/// @param vlrPermit Optional VLR encoded permit data
function depositVLRAndEth(
uint256 vlrAmount,
uint256 minBptOut,
address beneficiary,
bytes memory vlrPermit
) external payable;
/// @notice Deposits VLR and WETH to join 20WETH-80VLR liquidity pool and receive seVLR
/// @param vlrAmount VLR token amount to deposit
/// @param wethAmount WETH token amount to deposit
/// @param minBptOut Minimum liquidity tokens to receive
/// @param beneficiary Beneficiary of the deposit
/// @param vlrPermit Optional VLR encoded permit data
function depositVLRAndWeth(
uint256 vlrAmount,
uint256 wethAmount,
uint256 minBptOut,
address beneficiary,
bytes memory vlrPermit
) external;
/*//////////////////////////////////////////////////////////////
WITHDRAW
//////////////////////////////////////////////////////////////*/
/// @notice Withdraws VLR and ETH requested by given withdrawal request id
/// @param id Withdrawal request id
/// @param minVlrAmount Minimum VLR token amount to receive
/// @param minEthAmount Minimum ETH amount to receive
/// @return (vlrAmount, ethAmount) Amounts withdrawn
function withdrawVLRAndEth(
uint256 id,
uint256 minVlrAmount,
uint256 minEthAmount
) external returns (uint256, uint256);
/// @notice Withdraws VLR and ETH requested by multiple withdrawal request id
/// @param ids Withdrawal request ids
/// @param minVlrAmount Minimum VLR token amount to receive
/// @param minEthAmount Minimum ETH amount to receive
/// @return (vlrAmount, ethAmount) Amounts withdrawn
function withdrawVLRAndEthMulti(
uint256[] calldata ids,
uint256 minVlrAmount,
uint256 minEthAmount
) external returns (uint256, uint256);
/// @notice Withdraws VLR and WETH requested by given withdrawal request id
/// @param id Withdrawal request id
/// @param minVlrAmount Minimum VLR token amount to receive
/// @param minWethAmount Minimum WETH amount to receive
/// @return (vlrAmount, wethAmount) Amounts withdrawn
function withdrawVLRAndWeth(
uint256 id,
uint256 minVlrAmount,
uint256 minWethAmount
) external returns (uint256, uint256);
/// @notice Withdraws VLR and WETH requested by multiple withdrawal request id
/// @param ids Withdrawal request ids
/// @param minVlrAmount Minimum VLR token amount to receive
/// @param minWethAmount Minimum ETH amount to receive
/// @return (vlrAmount, wethAmount) Amounts withdrawn
function withdrawVLRAndWethMulti(
uint256[] calldata ids,
uint256 minVlrAmount,
uint256 minWethAmount
) external returns (uint256, uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/// @title ERC20 Utility Library
library ERC20UtilsLib {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/// @notice Emitted when the permit execution fails
error PermitFailed();
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
/// @dev An address used to represent the native token
address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/*//////////////////////////////////////////////////////////////
PERMIT
//////////////////////////////////////////////////////////////*/
/// @dev Executes the EIP2612 permit function on the provided token
/// @param token The address of the token
/// @param data The permit data
function permit(address token, bytes calldata data) internal {
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
// check the permit length
switch data.length
// 0x00 = no permit
// solhint-disable-next-line no-empty-blocks
case 0x00 {
// do nothing
}
// 32 * 7 = 224 EIP2612 Permit
case 0xe0 {
let x := mload(0x40) // get the free memory pointer
mstore(x, 0xd505accf00000000000000000000000000000000000000000000000000000000) // store the selector
calldatacopy(add(x, 0x04), data.offset, 0xe0) // store the args
pop(call(gas(), token, 0x00, x, 0xe4, 0x00, 0x20)) // call ERC20 permit, skip checking return data
}
// Otherwise revert
default {
mstore(0x00, 0xb78cb0dd00000000000000000000000000000000000000000000000000000000) // store the selector
revert(0x00, 0x04) // Revert with PermitFailed error
}
}
}
/*//////////////////////////////////////////////////////////////
BALANCE
//////////////////////////////////////////////////////////////*/
/// @dev Returns the balance of address(this), works for both ETH and ERC20 tokens
function getBalance(address token) internal view returns (uint256 balanceOf) {
// solhint-disable-next-line no-inline-assembly
assembly {
switch eq(token, ETH_ADDRESS)
// ETH
case 0x01 {
balanceOf := selfbalance()
}
// ERC20
default {
let x := mload(0x40) // get the free memory pointer
mstore(x, 0x70a0823100000000000000000000000000000000000000000000000000000000) // store the selector
mstore(add(x, 0x04), address()) // store the account
let success := staticcall(gas(), token, x, 0x24, x, 0x20) // call balanceOf
if success {
balanceOf := mload(x)
} // load the balance
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/// @title Weth Library
library WethLib {
/*//////////////////////////////////////////////////////////////
DEPOSIT
//////////////////////////////////////////////////////////////*/
/// @dev Executes deposit of WETH with the msg.value
function deposit(address weth) internal {
// solhint-disable-next-line no-inline-assembly
assembly {
let x := mload(0x40) // get the free memory pointer
// Prepare call data for WETH.deposit()
// Store function selector and
mstore(x, 0xd0e30db000000000000000000000000000000000000000000000000000000000) // deposit()
// Perform the external call with the prepared calldata
// Check the outcome of the call and handle failure
if iszero(call(gas(), weth, callvalue(), x, 4, 0, 0)) {
// The call failed; we retrieve the exact error message and revert with it
returndatacopy(0, 0, returndatasize()) // Copy the error message to the start of memory
revert(0, returndatasize()) // Revert with the error message
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/// @title TimeLocked ERC20 Interface
/// @author Laita Labs
/// @notice Interface for the TimeLocked ERC20, which allows time locking erc20 tokens
interface ITimeLockedERC20 {
/*//////////////////////////////////////////////////////////////
TYPES
//////////////////////////////////////////////////////////////*/
/// @notice Represents different stages of asset token withdrawal
enum WithdrawStatus {
/// @dev Default value. Withdrawal was never requested
UNUSED,
/// @dev Withdrawal was requested. Asset tokens can be withdrawn when lock duration passes
UNLOCKING,
/// @dev Asset tokens were withdrawn
RELEASED,
/// @dev Withdrawal was cancelled
CANCELLED
}
/// @notice Withdrawal request data structure containing request details
struct WithdrawalRequest {
/// @dev Requested asset token amount
uint256 amount;
/// @dev Unix timestamp indicating when the requested amount can be withdrawn
uint256 releaseTime;
/// @dev Status of the request. Only requests with `UNLOCKING` status can be withdrawn
WithdrawStatus status;
}
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/// @notice Time lock is out of set limits
error TimelockOutOfRange(uint256 attemptedTimelockDuration);
/// @notice Trying to cancel request which is not pending
error CannotCancelWithdrawalRequest(uint256 reqId);
/// @notice Trying to withdraw request which is not pending
error CannotWithdraw(uint256 reqId);
/// @notice Trying to withdraw request before time lock duration passes
error CannotWithdrawYet(uint256 reqId);
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/// @notice Time lock duration has been changed
event TimeLockChanged(uint256 oldTimeLock, uint256 newTimeLock);
/// @notice Withdraw has been requested
event RequestedUnlocking(uint256 indexed id, address indexed user, uint256 amount);
/// @notice Locked tokens has been released
event Withdraw(uint256 indexed id, address indexed user, uint256 amount);
/// @notice Tokens has been locked
event Deposited(address indexed user, uint256 amount);
/// @notice Withdrawal request has been cancelled
event CancelledWithdrawalRequest(uint256 indexed id, address indexed user, uint256 amount);
/*//////////////////////////////////////////////////////////////
VIEW
//////////////////////////////////////////////////////////////*/
/// @notice Role which can bypass timelock during asset tokens withdrawal
function MIGRATOR_ROLE() external view returns (bytes32);
/// @notice Asset ERC20 token to lock
function ASSET() external view returns (address);
/// @notice Minimum asset tokens lock duration in seconds
function MIN_TIME_LOCK_DURATION() external view returns (uint256);
/// @notice Maximum asset tokens lock duration in seconds
function MAX_TIME_LOCK_DURATION() external view returns (uint256);
/// @notice Asset tokens lock duration in seconds. Can be adjusted by admin
function timeLockDuration() external view returns (uint256);
/// @notice Total amount of asset tokens currently in `UNLOCKING` state
function unlockingAssets() external view returns (uint256);
/// @notice Mapping to store user withdrawal requests by id
function userVsWithdrawals(address user, uint256 id) external view returns (WithdrawalRequest memory);
/// @notice Mapping to index user's withdrawal request ids. Meant to only be incremented by 1 for each new request
function userVsNextID(address user) external view returns (uint256);
/*//////////////////////////////////////////////////////////////
DEPOSIT
//////////////////////////////////////////////////////////////*/
/// @notice Deposits the amount of asset tokens
/// @param amount The amount to deposit
/// @param beneficiary The beneficiary of the deposit
function deposit(uint256 amount, address beneficiary) external;
/// @notice Deposits the amount of asset tokens with ERC-2612 Permit
/// @param amount The amount to deposit
/// @param beneficiary The beneficiary of the deposit
/// @param amount Encoded permit data
function depositWithPermit(uint256 amount, address beneficiary, bytes calldata permit) external;
/*//////////////////////////////////////////////////////////////
WITHDRAWAL REQUEST
//////////////////////////////////////////////////////////////*/
/// @notice Creates a withdrawal request for the given amount of asset tokens
/// @param amount The amount to withdraw
function requestWithdraw(uint256 amount) external;
/// @notice Cancels a withdrawal request for the given request id
/// @param id The request id
function cancelWithdrawalRequest(uint256 id) external;
/// @notice Cancels withdrawal requests for multiple given request ids
/// @param ids The request ids
function cancelMultipleWithdrawalRequests(uint256[] calldata ids) external;
/*//////////////////////////////////////////////////////////////
WITHDRAW
//////////////////////////////////////////////////////////////*/
/// @notice Withdraws an amount of asset tokens which were requested by given withdrawal request id
/// @param id The request id
function withdraw(uint256 id) external;
/// @notice Withdraws an amount of asset tokens which were requested by multiple withdrawal request ids
/// @param ids The request ids
function withdrawMultiple(uint256[] calldata ids) external;
/*//////////////////////////////////////////////////////////////
MIGRATOR
//////////////////////////////////////////////////////////////*/
/// @notice Increments next user id, intended to only be called by migrator
/// @param user The user to increment the next id for
/// @return usedId The user id before the increment
function useNextId(address user) external returns (uint256 usedId);
/*//////////////////////////////////////////////////////////////
ADMIN
//////////////////////////////////////////////////////////////*/
/// @notice Pauses token operations, intended to only be called by admin
function pause() external;
/// @notice Unpauses token operations, intended to only be called by admin
function unpause() external;
/// @notice Changes time lock duration to the given value, intended to only be called by admin
/// @param newTimeLockDuration New time lock duration, has to be in set duration limits
function changeTimeLock(uint256 newTimeLockDuration) external;
/*//////////////////////////////////////////////////////////////
VIEW HELPERS
//////////////////////////////////////////////////////////////*/
/// @notice Finds any locked IDs in the specified range, intended for off chain use
/// @param user User whose requests to look for
/// @param start Index to start the search with. If negative, the search is performed from the end
/// @param countToCheck Amount of ids to check in the search
function findUnlockingIDs(
address user,
int256 start,
uint256 countToCheck
) external view returns (uint256[] memory ids);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/// @dev The ERC20 `totalSupply` query has failed.
error TotalSupplyQueryFailed();
/// @dev The Permit2 operation has failed.
error Permit2Failed();
/// @dev The Permit2 amount must be less than `2**160 - 1`.
error Permit2AmountOverflow();
/// @dev The Permit2 approve operation has failed.
error Permit2ApproveFailed();
/// @dev The Permit2 lockdown operation has failed.
error Permit2LockdownFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/// @dev The unique EIP-712 domain domain separator for the DAI token contract.
bytes32 internal constant DAI_DOMAIN_SEPARATOR =
0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;
/// @dev The address for the WETH9 contract on Ethereum mainnet.
address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
/// @dev The canonical Permit2 address.
/// [Github](https://github.com/Uniswap/permit2)
/// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
//
// The regular variants:
// - Forwards all remaining gas to the target.
// - Reverts if the target reverts.
// - Reverts if the current contract has insufficient balance.
//
// The force variants:
// - Forwards with an optional gas stipend
// (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
// - If the target reverts, or if the gas stipend is exhausted,
// creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
// Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
// - Reverts if the current contract has insufficient balance.
//
// The try variants:
// - Forwards with a mandatory gas stipend.
// - Instead of reverting, returns whether the transfer succeeded.
/// @dev Sends `amount` (in wei) ETH to `to`.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Sends all the ETH in the current contract to `to`.
function safeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer all the ETH and check if it succeeded or not.
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// forgefmt: disable-next-item
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
/// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
///
/// The `from` account must have at least `amount` approved for the current contract to manage.
function trySafeTransferFrom(address token, address from, address to, uint256 amount)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
success := lt(or(iszero(extcodesize(token)), returndatasize()), success)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
// Perform the transfer, reverting upon failure.
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
// Check the `extcodesize` again just in case the token selfdestructs lol.
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
amount :=
mul( // The arguments of `mul` are evaluated from right to left.
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
/// @dev Returns the total supply of the `token`.
/// Reverts if the token does not exist or does not implement `totalSupply()`.
function totalSupply(address token) internal view returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x18160ddd) // `totalSupply()`.
if iszero(
and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x04, 0x00, 0x20))
) {
mstore(0x00, 0x54cd9435) // `TotalSupplyQueryFailed()`.
revert(0x1c, 0x04)
}
result := mload(0x00)
}
}
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// If the initial attempt fails, try to use Permit2 to transfer the token.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for the current contract to manage.
function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
if (!trySafeTransferFrom(token, from, to, amount)) {
permit2TransferFrom(token, from, to, amount);
}
}
/// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
/// Reverts upon failure.
function permit2TransferFrom(address token, address from, address to, uint256 amount)
internal
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(add(m, 0x74), shr(96, shl(96, token)))
mstore(add(m, 0x54), amount)
mstore(add(m, 0x34), to)
mstore(add(m, 0x20), shl(96, from))
// `transferFrom(address,address,uint160,address)`.
mstore(m, 0x36c78516000000000000000000000000)
let p := PERMIT2
let exists := eq(chainid(), 1)
if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
if iszero(
and(
call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00),
lt(iszero(extcodesize(token)), exists) // Token has code and Permit2 exists.
)
) {
mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
}
}
}
/// @dev Permit a user to spend a given amount of
/// another user's tokens via native EIP-2612 permit if possible, falling
/// back to Permit2 if native permit fails or is not implemented on the token.
function permit2(
address token,
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
for {} shl(96, xor(token, WETH9)) {} {
mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
// Gas stipend to limit gas burn for tokens that don't refund gas when
// an non-existing function is called. 5K should be enough for a SLOAD.
staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
)
) { break }
// After here, we can be sure that token is a contract.
let m := mload(0x40)
mstore(add(m, 0x34), spender)
mstore(add(m, 0x20), shl(96, owner))
mstore(add(m, 0x74), deadline)
if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
mstore(0x14, owner)
mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
mstore(
add(m, 0x94),
lt(iszero(amount), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
)
mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
// `nonces` is already at `add(m, 0x54)`.
// `amount != 0` is already stored at `add(m, 0x94)`.
mstore(add(m, 0xb4), and(0xff, v))
mstore(add(m, 0xd4), r)
mstore(add(m, 0xf4), s)
success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
break
}
mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
mstore(add(m, 0x54), amount)
mstore(add(m, 0x94), and(0xff, v))
mstore(add(m, 0xb4), r)
mstore(add(m, 0xd4), s)
success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
break
}
}
if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
}
/// @dev Simple permit on the Permit2 contract.
function simplePermit2(
address token,
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, 0x927da105) // `allowance(address,address,address)`.
{
let addressMask := shr(96, not(0))
mstore(add(m, 0x20), and(addressMask, owner))
mstore(add(m, 0x40), and(addressMask, token))
mstore(add(m, 0x60), and(addressMask, spender))
mstore(add(m, 0xc0), and(addressMask, spender))
}
let p := mul(PERMIT2, iszero(shr(160, amount)))
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
)
) {
mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
revert(add(0x18, shl(2, iszero(p))), 0x04)
}
mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
// `owner` is already `add(m, 0x20)`.
// `token` is already at `add(m, 0x40)`.
mstore(add(m, 0x60), amount)
mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
// `nonce` is already at `add(m, 0xa0)`.
// `spender` is already at `add(m, 0xc0)`.
mstore(add(m, 0xe0), deadline)
mstore(add(m, 0x100), 0x100) // `signature` offset.
mstore(add(m, 0x120), 0x41) // `signature` length.
mstore(add(m, 0x140), r)
mstore(add(m, 0x160), s)
mstore(add(m, 0x180), shl(248, v))
if iszero( // Revert if token does not have code, or if the call fails.
mul(extcodesize(token), call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00))) {
mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Approves `spender` to spend `amount` of `token` for `address(this)`.
function permit2Approve(address token, address spender, uint160 amount, uint48 expiration)
internal
{
/// @solidity memory-safe-assembly
assembly {
let addressMask := shr(96, not(0))
let m := mload(0x40)
mstore(m, 0x87517c45) // `approve(address,address,uint160,uint48)`.
mstore(add(m, 0x20), and(addressMask, token))
mstore(add(m, 0x40), and(addressMask, spender))
mstore(add(m, 0x60), and(addressMask, amount))
mstore(add(m, 0x80), and(0xffffffffffff, expiration))
if iszero(call(gas(), PERMIT2, 0, add(m, 0x1c), 0xa0, codesize(), 0x00)) {
mstore(0x00, 0x324f14ae) // `Permit2ApproveFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Revokes an approval for `token` and `spender` for `address(this)`.
function permit2Lockdown(address token, address spender) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, 0xcc53287f) // `Permit2.lockdown`.
mstore(add(m, 0x20), 0x20) // Offset of the `approvals`.
mstore(add(m, 0x40), 1) // `approvals.length`.
mstore(add(m, 0x60), shr(96, shl(96, token)))
mstore(add(m, 0x80), shr(96, shl(96, spender)))
if iszero(call(gas(), PERMIT2, 0, add(m, 0x1c), 0xa0, codesize(), 0x00)) {
mstore(0x00, 0x96b3de23) // `Permit2LockdownFailed()`.
revert(0x1c, 0x04)
}
}
}
}{
"optimizer": {
"enabled": true,
"runs": 1000000
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"address","name":"vlr","type":"address"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"bridgeStaking","type":"address"},{"internalType":"uint256","name":"destChainId","type":"uint256"}],"internalType":"struct IMiroMigrator.BridgeConfig[]","name":"_bridgeConfigs","type":"tuple[]"},{"internalType":"address","name":"sePSP1","type":"address"},{"internalType":"address","name":"sePSP2","type":"address"},{"internalType":"address","name":"seVLR","type":"address"},{"internalType":"contract IAcrossSpokePool","name":"spokePool","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"InsufficientMsgValue","type":"error"},{"inputs":[],"name":"InvalidDestinationChainId","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Migrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"vlrAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wethAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destChainId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"StakeBridgingInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"PSP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SE_PSP1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SE_PSP2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SE_VLR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPOKE_POOL","outputs":[{"internalType":"contract IAcrossSpokePool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VLR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"bridgeConfigs","outputs":[{"internalType":"address","name":"vlr","type":"address"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"bridgeStaking","type":"address"},{"internalType":"uint256","name":"destChainId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vlrAmount","type":"uint256"},{"internalType":"uint256","name":"wethAmount","type":"uint256"},{"internalType":"uint256","name":"destChainId","type":"uint256"},{"internalType":"uint256","name":"minDestBptAmount","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"},{"components":[{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"address","name":"exclusiveRelayer","type":"address"},{"internalType":"uint32","name":"quoteTimestamp","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"uint32","name":"exclusivityDeadline","type":"uint32"}],"internalType":"struct IMiroMigrator.BridgeData","name":"vlrBridgeData","type":"tuple"},{"components":[{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"address","name":"exclusiveRelayer","type":"address"},{"internalType":"uint32","name":"quoteTimestamp","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"uint32","name":"exclusivityDeadline","type":"uint32"}],"internalType":"struct IMiroMigrator.BridgeData","name":"wethBridgeData","type":"tuple"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"name":"bridgeVLRAndStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pspAmount","type":"uint256"},{"internalType":"uint256","name":"wethAmount","type":"uint256"},{"internalType":"uint256","name":"minBptOut","type":"uint256"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"name":"migratePSPtoSeVLR","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pspAmount","type":"uint256"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"name":"migratePSPtoVLR","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sePSP1Amount","type":"uint256"},{"internalType":"uint256","name":"wethAmount","type":"uint256"},{"internalType":"uint256","name":"minBptOut","type":"uint256"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"name":"migrateSePSP1toSeVLR","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sePSP1Amount","type":"uint256"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"name":"migrateSePSP1toVLR","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sePSP2Amount","type":"uint256"},{"internalType":"uint256","name":"minPspAmount","type":"uint256"},{"internalType":"uint256","name":"minWethAmount","type":"uint256"},{"internalType":"uint256","name":"minBptOut","type":"uint256"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"name":"migrateSePSP2toSeVLR","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sePSP2Amount","type":"uint256"},{"internalType":"uint256","name":"minPspAmount","type":"uint256"},{"internalType":"uint256","name":"minWethAmount","type":"uint256"},{"internalType":"uint256","name":"destChainId","type":"uint256"},{"internalType":"uint256","name":"minDestBptAmount","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"},{"components":[{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"address","name":"exclusiveRelayer","type":"address"},{"internalType":"uint32","name":"quoteTimestamp","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"uint32","name":"exclusivityDeadline","type":"uint32"}],"internalType":"struct IMiroMigrator.BridgeData","name":"vlrBridgeData","type":"tuple"},{"components":[{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"address","name":"exclusiveRelayer","type":"address"},{"internalType":"uint32","name":"quoteTimestamp","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"uint32","name":"exclusivityDeadline","type":"uint32"}],"internalType":"struct IMiroMigrator.BridgeData","name":"wethBridgeData","type":"tuple"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"name":"migrateSePSP2toSeVLRAndBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"reClaimVLR","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"vlr","type":"address"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"bridgeStaking","type":"address"},{"internalType":"uint256","name":"destChainId","type":"uint256"}],"internalType":"struct IMiroMigrator.BridgeConfig[]","name":"_bridgeConfigs","type":"tuple[]"}],"name":"setBridgeConfigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
0x61016060405234801561001157600080fd5b50604051612c98380380612c9883398101604081905261003091610439565b338061005657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61005f816102fa565b506000805460ff60a01b191690556001600160a01b038085166101005283811661012081905290831660e0526040805163f821902d60e01b8152905163f821902d916004808201926020929091908290030181865afa1580156100c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100ea9190610581565b6001600160a01b03166080816001600160a01b03168152505060e0516001600160a01b031663b045d89e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610143573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101679190610581565b6001600160a01b031660a0816001600160a01b03168152505060e0516001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e49190610581565b6001600160a01b0390811660c05281166101405260005b85518110156102b357858181518110610216576102166105a5565b602002602001015160016000888481518110610234576102346105a5565b6020908102919091018101516060908101518352828201939093526040918201600020845181546001600160a01b03199081166001600160a01b039283161783559286015160018084018054861692841692909217909155938601516002830180549094169116179091559290910151600390920191909155016101fb565b5060e05160a0516102d2916001600160a01b039091169060001961034a565b60e05160c0516102f0916001600160a01b039091169060001961034a565b50505050506105bb565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b81601452806034526f095ea7b300000000000000000000000060005260206000604460106000875af1806001600051141661039857803d853b15171061039857633e3f8f736000526004601cfd5b506000603452505050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156103db576103db6103a3565b60405290565b604051601f8201601f191681016001600160401b0381118282101715610409576104096103a3565b604052919050565b6001600160a01b038116811461042657600080fd5b50565b805161043481610411565b919050565b600080600080600060a0868803121561045157600080fd5b85516001600160401b0381111561046757600080fd5b8601601f8101881361047857600080fd5b80516001600160401b03811115610491576104916103a3565b6104a060208260051b016103e1565b8082825260208201915060208360071b85010192508a8311156104c257600080fd5b6020840193505b82841015610539576080848c0312156104e157600080fd5b6104e96103b9565b84516104f481610411565b8152602085015161050481610411565b6020820152604085015161051781610411565b60408201526060858101519082015282526080909301926020909101906104c9565b975061054b9250505060208701610429565b935061055960408701610429565b925061056760608701610429565b915061057560808701610429565b90509295509295909350565b60006020828403121561059357600080fd5b815161059e81610411565b9392505050565b634e487b7160e01b600052603260045260246000fd5b60805160a05160c05160e05161010051610120516101405161257961071f6000396000818161034301528181611a7d01528181611ae30152611b310152600081816102da01528181610b8101528181610ec30152818161177d015281816117d60152818161188a01526119360152600081816104d5015281816107a0015281816107e10152818161082d015261086e0152600081816101d90152818161092101528181610a2c01528181610c0401528181610f9101526112a00152600081816103ca015281816109b3015281816111d701528181611230015281816119b001528181611a5b0152611b890152600081816103fe0152818161069901528181610703015281816107540152818161112a0152818161116b01528181611ac10152611b6301526000818161055c015281816106140152818161065501528181610c8d01528181610e3601528181610e7701528181610f1701526119f301526125796000f3fe6080604052600436106101805760003560e01c80638021fef7116100d6578063d172f2f01161007f578063f2fde38b11610059578063f2fde38b14610517578063f711222514610537578063f821902d1461054a57600080fd5b8063d172f2f014610420578063e736c6ca146104c3578063ee06090b146104f757600080fd5b80638dad50f2116100b05780638dad50f2146103a5578063ad5c4648146103b8578063b045d89e146103ec57600080fd5b80638021fef7146103315780638456cb59146103655780638da5cb5b1461037a57600080fd5b80633c745a4f116101385780636ca55c25116101125780636ca55c25146102c8578063715018a6146102fc5780637854eb6c1461031157600080fd5b80633c745a4f146102655780633f4ba83a146102785780635c975abb1461028d57600080fd5b806321a32ec31161016957806321a32ec3146101c7578063299a278d1461022557806339b5cd5d1461024557600080fd5b806308c8a89d14610185578063174a81ab146101a7575b600080fd5b34801561019157600080fd5b506101a56101a0366004611dd9565b61057e565b005b3480156101b357600080fd5b506101a56101c2366004611e99565b6105f2565b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b506101a5610240366004611f17565b6106f2565b34801561025157600080fd5b506101a5610260366004611e99565b61077e565b6101a5610273366004611f3b565b61080b565b34801561028457600080fd5b506101a5610ad2565b34801561029957600080fd5b5060005474010000000000000000000000000000000000000000900460ff16604051901515815260200161021c565b3480156102d457600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b34801561030857600080fd5b506101a5610ae4565b34801561031d57600080fd5b506101a561032c366004611fae565b610af6565b34801561033d57600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b34801561037157600080fd5b506101a5610e04565b34801561038657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101fb565b6101a56103b3366004611f3b565b610e14565b3480156103c457600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103f857600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b34801561042c57600080fd5b5061048161043b36600461205d565b6001602081905260009182526040909120805491810154600282015460039092015473ffffffffffffffffffffffffffffffffffffffff93841693918216929091169084565b60405161021c949392919073ffffffffffffffffffffffffffffffffffffffff9485168152928416602084015292166040820152606081019190915260800190565b3480156104cf57600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b34801561050357600080fd5b506101a5610512366004612076565b610ea1565b34801561052357600080fd5b506101a5610532366004611f17565b611039565b6101a56105453660046120e0565b61109f565b34801561055657600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b610586611413565b60005b818110156105ed578282828181106105a3576105a3612185565b905060800201600160008585858181106105bf576105bf612185565b90506080020160600135815260200190815260200160002081816105e391906121b4565b5050600101610589565b505050565b6105fa611466565b61063b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683836114bb565b61067f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163361dead8661153c565b6106c073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633856115a3565b604051839033907f8b80bd19aea7b735bc6d75db8d6adbe18b28c30d62b3555245eb67b2340caedc90600090a3505050565b6106fa611413565b61077b8161073d7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166115fc565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691906115a3565b50565b610786611466565b6107c773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683836114bb565b61067f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163361dead8661153c565b610813611466565b61085473ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683836114bb565b61089873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163361dead8861153c565b3415610999578334146108d7576040517f78f38f7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70f16fd6000000000000000000000000000000000000000000000000000000008152600481018690526024810184905233604482015260806064820152600060848201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370f16fd690349060a4016000604051808303818588803b15801561097b57600080fd5b505af115801561098f573d6000803e3d6000fd5b5050505050610a9e565b6109db73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633308761153c565b6040517fc9fdcb4c00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044810184905233606482015260a06084820152600060a48201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063c9fdcb4c9060c401600060405180830381600087803b158015610a8557600080fd5b505af1158015610a99573d6000803e3d6000fd5b505050505b604051859033907f8b80bd19aea7b735bc6d75db8d6adbe18b28c30d62b3555245eb67b2340caedc90600090a35050505050565b610ada611413565b610ae261166e565b565b610aec611413565b610ae260006116eb565b610afe611466565b6000878152600160205260408120600301549003610b48576040517f90eaaa7000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8516610b67573394505b610ba873ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683836114bb565b600080610bb68c8c8c611760565b6040517f19f1048f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301529294509092506000917f000000000000000000000000000000000000000000000000000000000000000016906319f1048f906024016020604051808303816000875af1158015610c4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7191906122ae565b9050610cb673ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001661dead856115a3565b604051839073ffffffffffffffffffffffffffffffffffffffff8a16907f8b80bd19aea7b735bc6d75db8d6adbe18b28c30d62b3555245eb67b2340caedc90600090a36000610d6e82610d0a8a35876122c7565b610d158a35876122c7565b60408051602081019490945246848201526060840192909252608083015260a082018d905273ffffffffffffffffffffffffffffffffffffffff8c1660c0808401919091528151808403909101815260e0909201905290565b9050610d8c8460008d610d86368d90038d018d61231b565b85611a3b565b610da28360018d610d86368c90038c018c61231b565b82848a73ffffffffffffffffffffffffffffffffffffffff167f782334e555e7f5df3383da5b8d85e76ac57c38b6385a8ee43961e2064c5878958e85604051610dec92919061242f565b60405180910390a45050505050505050505050505050565b610e0c611413565b610ae2611c86565b610e1c611466565b610e5d73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683836114bb565b61089873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163361dead8861153c565b610ea9611466565b610eea73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683836114bb565b600080610ef8888888611760565b9092509050610f4073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001661dead846115a3565b6040517fc9fdcb4c00000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044810186905233606482015260a06084820152600060a48201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063c9fdcb4c9060c401600060405180830381600087803b158015610fea57600080fd5b505af1158015610ffe573d6000803e3d6000fd5b50506040518492503391507f8b80bd19aea7b735bc6d75db8d6adbe18b28c30d62b3555245eb67b2340caedc90600090a35050505050505050565b611041611413565b73ffffffffffffffffffffffffffffffffffffffff8116611096576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b61077b816116eb565b6110a7611466565b60008781526001602052604081206003015490036110f1576040517f90eaaa7000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8516611110573394505b61115173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683836114bb565b61119373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633308c61153c565b3415611216578734146111d2576040517f78f38f7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112117f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16611cf5565b611258565b61125873ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633308b61153c565b6040517f19f1048f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906319f1048f906024016020604051808303816000875af11580156112eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130f91906122ae565b905060006113868261132288358e6122c7565b61132d88358e6122c7565b60408051602081019490945246848201526060840192909252608083015260a082018b905273ffffffffffffffffffffffffffffffffffffffff8a1660c0808401919091528151808403909101815260e0909201905290565b905061139e8b60008b610d86368b90038b018b61231b565b6113b48a60018b610d86368a90038a018a61231b565b898b8873ffffffffffffffffffffffffffffffffffffffff167f782334e555e7f5df3383da5b8d85e76ac57c38b6385a8ee43961e2064c5878958c856040516113fe92919061242f565b60405180910390a45050505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ae2576040517f118cdaa700000000000000000000000000000000000000000000000000000000815233600482015260240161108d565b60005474010000000000000000000000000000000000000000900460ff1615610ae2576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8080156114f45760e081146114f9577fb78cb0dd0000000000000000000000000000000000000000000000000000000060005260046000fd5b611536565b6040517fd505accf00000000000000000000000000000000000000000000000000000000815260e08460048301376020600060e4836000895af150505b50505050565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af1806001600051141661159457803d873b15171061159457637939f4246000526004601cfd5b50600060605260405250505050565b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af180600160005114166115f157803d853b1517106115f1576390b8ec186000526004601cfd5b506000603452505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee821460018114611664576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602483875afa801561165d57815193505b5050611668565b4791505b50919050565b611676611d37565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000806117a573ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633308861153c565b6040517f138504c40000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063138504c4906024016020604051808303816000875af1158015611834573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185891906122ae565b6040517f745400c9000000000000000000000000000000000000000000000000000000008152600481018890529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063745400c990602401600060405180830381600087803b1580156118e357600080fd5b505af11580156118f7573d6000803e3d6000fd5b50506040517fb0d88d7f0000000000000000000000000000000000000000000000000000000081526004810184905260248101889052604481018790527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16925063b0d88d7f9150606401600060405180830381600087803b15801561199157600080fd5b505af11580156119a5573d6000803e3d6000fd5b5050505060006119ea7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166115fc565b90506000611a2d7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166115fc565b989197509095505050505050565b8315611aa757611aa273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000087611d8b565b611b08565b611b0873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000087611d8b565b60008381526001602052604090206002015473ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691637b9392329133911687611b87577f0000000000000000000000000000000000000000000000000000000000000000611ba9565b7f00000000000000000000000000000000000000000000000000000000000000005b88611bd85760008881526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16611c02565b6000888152600160208190526040909120015473ffffffffffffffffffffffffffffffffffffffff165b87518b90611c1090826122c7565b8a8a602001518b604001518c606001518d608001518d6040518d63ffffffff1660e01b8152600401611c4d9c9b9a99989796959493929190612450565b600060405180830381600087803b158015611c6757600080fd5b505af1158015611c7b573d6000803e3d6000fd5b505050505050505050565b611c8e611466565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586116c13390565b6040517fd0e30db000000000000000000000000000000000000000000000000000000000815260008060048334865af1611d33573d6000803e3d6000fd5b5050565b60005474010000000000000000000000000000000000000000900460ff16610ae2576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81601452806034526f095ea7b300000000000000000000000060005260206000604460106000875af180600160005114166115f157803d853b1517106115f157633e3f8f736000526004601cfd5b60008060208385031215611dec57600080fd5b823567ffffffffffffffff811115611e0357600080fd5b8301601f81018513611e1457600080fd5b803567ffffffffffffffff811115611e2b57600080fd5b8560208260071b8401011115611e4057600080fd5b6020919091019590945092505050565b60008083601f840112611e6257600080fd5b50813567ffffffffffffffff811115611e7a57600080fd5b602083019150836020828501011115611e9257600080fd5b9250929050565b600080600060408486031215611eae57600080fd5b83359250602084013567ffffffffffffffff811115611ecc57600080fd5b611ed886828701611e50565b9497909650939450505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461077b57600080fd5b8035611f1281611ee5565b919050565b600060208284031215611f2957600080fd5b8135611f3481611ee5565b9392505050565b600080600080600060808688031215611f5357600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff811115611f7f57600080fd5b611f8b88828901611e50565b969995985093965092949392505050565b600060a0828403121561166857600080fd5b6000806000806000806000806000806102208b8d031215611fce57600080fd5b8a35995060208b0135985060408b0135975060608b0135965060808b0135955060a08b0135611ffc81611ee5565b945061200b8c60c08d01611f9c565b935061201b8c6101608d01611f9c565b92506102008b013567ffffffffffffffff81111561203857600080fd5b6120448d828e01611e50565b915080935050809150509295989b9194979a5092959850565b60006020828403121561206f57600080fd5b5035919050565b60008060008060008060a0878903121561208f57600080fd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156120c257600080fd5b6120ce89828a01611e50565b979a9699509497509295939492505050565b60008060008060008060008060006102008a8c0312156120ff57600080fd5b8935985060208a0135975060408a0135965060608a0135955060808a013561212681611ee5565b94506121358b60a08c01611f9c565b93506121458b6101408c01611f9c565b92506101e08a013567ffffffffffffffff81111561216257600080fd5b61216e8c828d01611e50565b915080935050809150509295985092959850929598565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81356121bf81611ee5565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff821617825550602082013561220c81611ee5565b6001820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831617905550604082013561225d81611ee5565b6002820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831617905550606082013560038201555050565b6000602082840312156122c057600080fd5b5051919050565b81810381811115612301577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b803563ffffffff81168114611f1257600080fd5b600060a082840312801561232e57600080fd5b5060405160a0810167ffffffffffffffff81118282101715612379577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528235815261238c60208401611f07565b602082015261239d60408401612307565b60408201526123ae60608401612307565b60608201526123bf60808401612307565b60808201529392505050565b6000815180845260005b818110156123f1576020818501810151868301820152016123d5565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b82815260406020820152600061244860408301846123cb565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8d16815273ffffffffffffffffffffffffffffffffffffffff8c16602082015273ffffffffffffffffffffffffffffffffffffffff8b16604082015273ffffffffffffffffffffffffffffffffffffffff8a1660608201528860808201528760a08201528660c08201526124f160e082018773ffffffffffffffffffffffffffffffffffffffff169052565b63ffffffff851661010082015263ffffffff841661012082015263ffffffff831661014082015261018061016082015260006125316101808301846123cb565b9e9d505050505050505050505050505056fea2646970667358221220607e101d4c86a22588df957bbeeb78be6a5d561319c107e83acea78d1592c09c64736f6c634300081c003300000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000716fbc68e0c761684d9280484243ff094cc5ffab000000000000000000000000593f39a4ba26a9c8ed2128ac95d109e8e403c48500000000000000000000000040000320d200c110100638040f10500c8f0010b90000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c500000000000000000000000000000000000000000000000000000000000000020000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c74000000000000000000000000420000000000000000000000000000000000000600000000000000000000000017983b9c5e8905f38a7ea0d0f34f4ee5f34f14dc00000000000000000000000000000000000000000000000000000000000021050000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c7400000000000000000000000042000000000000000000000000000000000000060000000000000000000000001230de36a047abeb36fe0e07f89305a73e74d22d000000000000000000000000000000000000000000000000000000000000000a
Deployed Bytecode
0x6080604052600436106101805760003560e01c80638021fef7116100d6578063d172f2f01161007f578063f2fde38b11610059578063f2fde38b14610517578063f711222514610537578063f821902d1461054a57600080fd5b8063d172f2f014610420578063e736c6ca146104c3578063ee06090b146104f757600080fd5b80638dad50f2116100b05780638dad50f2146103a5578063ad5c4648146103b8578063b045d89e146103ec57600080fd5b80638021fef7146103315780638456cb59146103655780638da5cb5b1461037a57600080fd5b80633c745a4f116101385780636ca55c25116101125780636ca55c25146102c8578063715018a6146102fc5780637854eb6c1461031157600080fd5b80633c745a4f146102655780633f4ba83a146102785780635c975abb1461028d57600080fd5b806321a32ec31161016957806321a32ec3146101c7578063299a278d1461022557806339b5cd5d1461024557600080fd5b806308c8a89d14610185578063174a81ab146101a7575b600080fd5b34801561019157600080fd5b506101a56101a0366004611dd9565b61057e565b005b3480156101b357600080fd5b506101a56101c2366004611e99565b6105f2565b3480156101d357600080fd5b506101fb7f00000000000000000000000040000320d200c110100638040f10500c8f0010b981565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561023157600080fd5b506101a5610240366004611f17565b6106f2565b34801561025157600080fd5b506101a5610260366004611e99565b61077e565b6101a5610273366004611f3b565b61080b565b34801561028457600080fd5b506101a5610ad2565b34801561029957600080fd5b5060005474010000000000000000000000000000000000000000900460ff16604051901515815260200161021c565b3480156102d457600080fd5b506101fb7f000000000000000000000000593f39a4ba26a9c8ed2128ac95d109e8e403c48581565b34801561030857600080fd5b506101a5610ae4565b34801561031d57600080fd5b506101a561032c366004611fae565b610af6565b34801561033d57600080fd5b506101fb7f0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c581565b34801561037157600080fd5b506101a5610e04565b34801561038657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101fb565b6101a56103b3366004611f3b565b610e14565b3480156103c457600080fd5b506101fb7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156103f857600080fd5b506101fb7f0000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c7481565b34801561042c57600080fd5b5061048161043b36600461205d565b6001602081905260009182526040909120805491810154600282015460039092015473ffffffffffffffffffffffffffffffffffffffff93841693918216929091169084565b60405161021c949392919073ffffffffffffffffffffffffffffffffffffffff9485168152928416602084015292166040820152606081019190915260800190565b3480156104cf57600080fd5b506101fb7f000000000000000000000000716fbc68e0c761684d9280484243ff094cc5ffab81565b34801561050357600080fd5b506101a5610512366004612076565b610ea1565b34801561052357600080fd5b506101a5610532366004611f17565b611039565b6101a56105453660046120e0565b61109f565b34801561055657600080fd5b506101fb7f000000000000000000000000cafe001067cdef266afb7eb5a286dcfd277f3de581565b610586611413565b60005b818110156105ed578282828181106105a3576105a3612185565b905060800201600160008585858181106105bf576105bf612185565b90506080020160600135815260200190815260200160002081816105e391906121b4565b5050600101610589565b505050565b6105fa611466565b61063b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000cafe001067cdef266afb7eb5a286dcfd277f3de51683836114bb565b61067f73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000cafe001067cdef266afb7eb5a286dcfd277f3de5163361dead8661153c565b6106c073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c741633856115a3565b604051839033907f8b80bd19aea7b735bc6d75db8d6adbe18b28c30d62b3555245eb67b2340caedc90600090a3505050565b6106fa611413565b61077b8161073d7f0000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c7473ffffffffffffffffffffffffffffffffffffffff166115fc565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c741691906115a3565b50565b610786611466565b6107c773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000716fbc68e0c761684d9280484243ff094cc5ffab1683836114bb565b61067f73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000716fbc68e0c761684d9280484243ff094cc5ffab163361dead8661153c565b610813611466565b61085473ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000716fbc68e0c761684d9280484243ff094cc5ffab1683836114bb565b61089873ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000716fbc68e0c761684d9280484243ff094cc5ffab163361dead8861153c565b3415610999578334146108d7576040517f78f38f7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70f16fd6000000000000000000000000000000000000000000000000000000008152600481018690526024810184905233604482015260806064820152600060848201527f00000000000000000000000040000320d200c110100638040f10500c8f0010b973ffffffffffffffffffffffffffffffffffffffff16906370f16fd690349060a4016000604051808303818588803b15801561097b57600080fd5b505af115801561098f573d6000803e3d6000fd5b5050505050610a9e565b6109db73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21633308761153c565b6040517fc9fdcb4c00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044810184905233606482015260a06084820152600060a48201527f00000000000000000000000040000320d200c110100638040f10500c8f0010b973ffffffffffffffffffffffffffffffffffffffff169063c9fdcb4c9060c401600060405180830381600087803b158015610a8557600080fd5b505af1158015610a99573d6000803e3d6000fd5b505050505b604051859033907f8b80bd19aea7b735bc6d75db8d6adbe18b28c30d62b3555245eb67b2340caedc90600090a35050505050565b610ada611413565b610ae261166e565b565b610aec611413565b610ae260006116eb565b610afe611466565b6000878152600160205260408120600301549003610b48576040517f90eaaa7000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8516610b67573394505b610ba873ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000593f39a4ba26a9c8ed2128ac95d109e8e403c4851683836114bb565b600080610bb68c8c8c611760565b6040517f19f1048f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301529294509092506000917f00000000000000000000000040000320d200c110100638040f10500c8f0010b916906319f1048f906024016020604051808303816000875af1158015610c4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7191906122ae565b9050610cb673ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000cafe001067cdef266afb7eb5a286dcfd277f3de51661dead856115a3565b604051839073ffffffffffffffffffffffffffffffffffffffff8a16907f8b80bd19aea7b735bc6d75db8d6adbe18b28c30d62b3555245eb67b2340caedc90600090a36000610d6e82610d0a8a35876122c7565b610d158a35876122c7565b60408051602081019490945246848201526060840192909252608083015260a082018d905273ffffffffffffffffffffffffffffffffffffffff8c1660c0808401919091528151808403909101815260e0909201905290565b9050610d8c8460008d610d86368d90038d018d61231b565b85611a3b565b610da28360018d610d86368c90038c018c61231b565b82848a73ffffffffffffffffffffffffffffffffffffffff167f782334e555e7f5df3383da5b8d85e76ac57c38b6385a8ee43961e2064c5878958e85604051610dec92919061242f565b60405180910390a45050505050505050505050505050565b610e0c611413565b610ae2611c86565b610e1c611466565b610e5d73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000cafe001067cdef266afb7eb5a286dcfd277f3de51683836114bb565b61089873ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000cafe001067cdef266afb7eb5a286dcfd277f3de5163361dead8861153c565b610ea9611466565b610eea73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000593f39a4ba26a9c8ed2128ac95d109e8e403c4851683836114bb565b600080610ef8888888611760565b9092509050610f4073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000cafe001067cdef266afb7eb5a286dcfd277f3de51661dead846115a3565b6040517fc9fdcb4c00000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044810186905233606482015260a06084820152600060a48201527f00000000000000000000000040000320d200c110100638040f10500c8f0010b973ffffffffffffffffffffffffffffffffffffffff169063c9fdcb4c9060c401600060405180830381600087803b158015610fea57600080fd5b505af1158015610ffe573d6000803e3d6000fd5b50506040518492503391507f8b80bd19aea7b735bc6d75db8d6adbe18b28c30d62b3555245eb67b2340caedc90600090a35050505050505050565b611041611413565b73ffffffffffffffffffffffffffffffffffffffff8116611096576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b61077b816116eb565b6110a7611466565b60008781526001602052604081206003015490036110f1576040517f90eaaa7000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8516611110573394505b61115173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c741683836114bb565b61119373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c741633308c61153c565b3415611216578734146111d2576040517f78f38f7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112117f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16611cf5565b611258565b61125873ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21633308b61153c565b6040517f19f1048f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301526000917f00000000000000000000000040000320d200c110100638040f10500c8f0010b9909116906319f1048f906024016020604051808303816000875af11580156112eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130f91906122ae565b905060006113868261132288358e6122c7565b61132d88358e6122c7565b60408051602081019490945246848201526060840192909252608083015260a082018b905273ffffffffffffffffffffffffffffffffffffffff8a1660c0808401919091528151808403909101815260e0909201905290565b905061139e8b60008b610d86368b90038b018b61231b565b6113b48a60018b610d86368a90038a018a61231b565b898b8873ffffffffffffffffffffffffffffffffffffffff167f782334e555e7f5df3383da5b8d85e76ac57c38b6385a8ee43961e2064c5878958c856040516113fe92919061242f565b60405180910390a45050505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ae2576040517f118cdaa700000000000000000000000000000000000000000000000000000000815233600482015260240161108d565b60005474010000000000000000000000000000000000000000900460ff1615610ae2576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8080156114f45760e081146114f9577fb78cb0dd0000000000000000000000000000000000000000000000000000000060005260046000fd5b611536565b6040517fd505accf00000000000000000000000000000000000000000000000000000000815260e08460048301376020600060e4836000895af150505b50505050565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af1806001600051141661159457803d873b15171061159457637939f4246000526004601cfd5b50600060605260405250505050565b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af180600160005114166115f157803d853b1517106115f1576390b8ec186000526004601cfd5b506000603452505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee821460018114611664576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602483875afa801561165d57815193505b5050611668565b4791505b50919050565b611676611d37565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000806117a573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000593f39a4ba26a9c8ed2128ac95d109e8e403c4851633308861153c565b6040517f138504c40000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000593f39a4ba26a9c8ed2128ac95d109e8e403c48573ffffffffffffffffffffffffffffffffffffffff169063138504c4906024016020604051808303816000875af1158015611834573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185891906122ae565b6040517f745400c9000000000000000000000000000000000000000000000000000000008152600481018890529091507f000000000000000000000000593f39a4ba26a9c8ed2128ac95d109e8e403c48573ffffffffffffffffffffffffffffffffffffffff169063745400c990602401600060405180830381600087803b1580156118e357600080fd5b505af11580156118f7573d6000803e3d6000fd5b50506040517fb0d88d7f0000000000000000000000000000000000000000000000000000000081526004810184905260248101889052604481018790527f000000000000000000000000593f39a4ba26a9c8ed2128ac95d109e8e403c48573ffffffffffffffffffffffffffffffffffffffff16925063b0d88d7f9150606401600060405180830381600087803b15801561199157600080fd5b505af11580156119a5573d6000803e3d6000fd5b5050505060006119ea7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff166115fc565b90506000611a2d7f000000000000000000000000cafe001067cdef266afb7eb5a286dcfd277f3de573ffffffffffffffffffffffffffffffffffffffff166115fc565b989197509095505050505050565b8315611aa757611aa273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2167f0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c587611d8b565b611b08565b611b0873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c74167f0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c587611d8b565b60008381526001602052604090206002015473ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c5811691637b9392329133911687611b87577f0000000000000000000000004e107a0000db66f0e9fd2039288bf811dd1f9c74611ba9565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b88611bd85760008881526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16611c02565b6000888152600160208190526040909120015473ffffffffffffffffffffffffffffffffffffffff165b87518b90611c1090826122c7565b8a8a602001518b604001518c606001518d608001518d6040518d63ffffffff1660e01b8152600401611c4d9c9b9a99989796959493929190612450565b600060405180830381600087803b158015611c6757600080fd5b505af1158015611c7b573d6000803e3d6000fd5b505050505050505050565b611c8e611466565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586116c13390565b6040517fd0e30db000000000000000000000000000000000000000000000000000000000815260008060048334865af1611d33573d6000803e3d6000fd5b5050565b60005474010000000000000000000000000000000000000000900460ff16610ae2576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81601452806034526f095ea7b300000000000000000000000060005260206000604460106000875af180600160005114166115f157803d853b1517106115f157633e3f8f736000526004601cfd5b60008060208385031215611dec57600080fd5b823567ffffffffffffffff811115611e0357600080fd5b8301601f81018513611e1457600080fd5b803567ffffffffffffffff811115611e2b57600080fd5b8560208260071b8401011115611e4057600080fd5b6020919091019590945092505050565b60008083601f840112611e6257600080fd5b50813567ffffffffffffffff811115611e7a57600080fd5b602083019150836020828501011115611e9257600080fd5b9250929050565b600080600060408486031215611eae57600080fd5b83359250602084013567ffffffffffffffff811115611ecc57600080fd5b611ed886828701611e50565b9497909650939450505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461077b57600080fd5b8035611f1281611ee5565b919050565b600060208284031215611f2957600080fd5b8135611f3481611ee5565b9392505050565b600080600080600060808688031215611f5357600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff811115611f7f57600080fd5b611f8b88828901611e50565b969995985093965092949392505050565b600060a0828403121561166857600080fd5b6000806000806000806000806000806102208b8d031215611fce57600080fd5b8a35995060208b0135985060408b0135975060608b0135965060808b0135955060a08b0135611ffc81611ee5565b945061200b8c60c08d01611f9c565b935061201b8c6101608d01611f9c565b92506102008b013567ffffffffffffffff81111561203857600080fd5b6120448d828e01611e50565b915080935050809150509295989b9194979a5092959850565b60006020828403121561206f57600080fd5b5035919050565b60008060008060008060a0878903121561208f57600080fd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156120c257600080fd5b6120ce89828a01611e50565b979a9699509497509295939492505050565b60008060008060008060008060006102008a8c0312156120ff57600080fd5b8935985060208a0135975060408a0135965060608a0135955060808a013561212681611ee5565b94506121358b60a08c01611f9c565b93506121458b6101408c01611f9c565b92506101e08a013567ffffffffffffffff81111561216257600080fd5b61216e8c828d01611e50565b915080935050809150509295985092959850929598565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81356121bf81611ee5565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff821617825550602082013561220c81611ee5565b6001820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831617905550604082013561225d81611ee5565b6002820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831617905550606082013560038201555050565b6000602082840312156122c057600080fd5b5051919050565b81810381811115612301577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b803563ffffffff81168114611f1257600080fd5b600060a082840312801561232e57600080fd5b5060405160a0810167ffffffffffffffff81118282101715612379577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528235815261238c60208401611f07565b602082015261239d60408401612307565b60408201526123ae60608401612307565b60608201526123bf60808401612307565b60808201529392505050565b6000815180845260005b818110156123f1576020818501810151868301820152016123d5565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b82815260406020820152600061244860408301846123cb565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8d16815273ffffffffffffffffffffffffffffffffffffffff8c16602082015273ffffffffffffffffffffffffffffffffffffffff8b16604082015273ffffffffffffffffffffffffffffffffffffffff8a1660608201528860808201528760a08201528660c08201526124f160e082018773ffffffffffffffffffffffffffffffffffffffff169052565b63ffffffff851661010082015263ffffffff841661012082015263ffffffff831661014082015261018061016082015260006125316101808301846123cb565b9e9d505050505050505050505050505056fea2646970667358221220607e101d4c86a22588df957bbeeb78be6a5d561319c107e83acea78d1592c09c64736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$353,852.10
Net Worth in ETH
180.235856
Token Allocations
VLR
100.00%
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $0.000634 | 557,800,805.8176 | $353,852.1 |
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.