Source Code
Overview
ETH Balance
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 28289723 | 1 hr ago | 0 ETH | ||||
| 28286602 | 3 hrs ago | 0 ETH | ||||
| 28283391 | 5 hrs ago | 0 ETH | ||||
| 28280184 | 7 hrs ago | 0 ETH | ||||
| 28276987 | 9 hrs ago | 0 ETH | ||||
| 28274047 | 11 hrs ago | 0 ETH | ||||
| 28271025 | 13 hrs ago | 0 ETH | ||||
| 28268323 | 15 hrs ago | 0 ETH | ||||
| 28267317 | 16 hrs ago | 0.00102858 ETH | ||||
| 28267317 | 16 hrs ago | 0 ETH | ||||
| 28265160 | 17 hrs ago | 0 ETH | ||||
| 28264744 | 17 hrs ago | 0 ETH | ||||
| 28261591 | 19 hrs ago | 0 ETH | ||||
| 28258243 | 21 hrs ago | 0 ETH | ||||
| 28254927 | 23 hrs ago | 0 ETH | ||||
| 28251625 | 25 hrs ago | 0 ETH | ||||
| 28245696 | 29 hrs ago | 0 ETH | ||||
| 28242604 | 31 hrs ago | 0 ETH | ||||
| 28239301 | 33 hrs ago | 0 ETH | ||||
| 28236383 | 35 hrs ago | 0 ETH | ||||
| 28233191 | 37 hrs ago | 0 ETH | ||||
| 28229928 | 39 hrs ago | 0 ETH | ||||
| 28227071 | 41 hrs ago | 0 ETH | ||||
| 28226663 | 41 hrs ago | 0 ETH | ||||
| 28225037 | 42 hrs ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SpokePortal
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 10000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
import { ISpokeMTokenLike } from "./interfaces/ISpokeMTokenLike.sol";
import { IRegistrarLike } from "./interfaces/IRegistrarLike.sol";
import { ISpokePortal } from "./interfaces/ISpokePortal.sol";
import { IPortal } from "./interfaces/IPortal.sol";
import { Portal } from "./Portal.sol";
import { PayloadType, PayloadEncoder } from "./libs/PayloadEncoder.sol";
/**
* @title SpokePortal
* @author M^0 Labs
* @notice Deployed on Spoke chains and responsible for sending and receiving M tokens
* as well as updating M index and Registrar keys.
* @dev Tokens are bridged using mint-burn mechanism.
*/
contract SpokePortal is Portal, ISpokePortal {
using PayloadEncoder for bytes;
/**
* @notice Constructs SpokePortal Implementation contract
* @dev Sets immutable storage.
* @param mToken_ The address of M token.
* @param registrar_ The address of Registrar.
* @param swapFacility_ The address of Swap Facility.
*/
constructor(address mToken_, address registrar_, address swapFacility_) Portal(mToken_, registrar_, swapFacility_) { }
/// @inheritdoc IPortal
function initialize(address bridge_, address initialOwner_, address initialPauser_) external initializer {
_initialize(bridge_, initialOwner_, initialPauser_);
}
///////////////////////////////////////////////////////////////////////////
// INTERNAL/PRIVATE INTERACTIVE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
function _receiveCustomPayload(PayloadType payloadType_, bytes memory payload_) internal override {
if (payloadType_ == PayloadType.Index) {
_updateMTokenIndex(payload_);
} else if (payloadType_ == PayloadType.Key) {
_setRegistrarKey(payload_);
} else if (payloadType_ == PayloadType.List) {
_updateRegistrarList(payload_);
}
}
/// @notice Updates M Token index to the index received from the remote chain.
function _updateMTokenIndex(bytes memory payload_) private {
uint128 index_ = payload_.decodeIndex();
emit MTokenIndexReceived(index_);
if (index_ > _currentIndex()) {
ISpokeMTokenLike(mToken).updateIndex(index_);
}
}
/// @notice Sets a Registrar key received from the Hub chain.
function _setRegistrarKey(bytes memory payload_) private {
(bytes32 key_, bytes32 value_) = payload_.decodeKey();
emit RegistrarKeyReceived(key_, value_);
IRegistrarLike(registrar).setKey(key_, value_);
}
/// @notice Adds or removes an account from the Registrar List based on the message from the Hub chain.
function _updateRegistrarList(bytes memory payload_) private {
(bytes32 listName_, address account_, bool add_) = payload_.decodeListUpdate();
emit RegistrarListStatusReceived(listName_, account_, add_);
if (add_) {
IRegistrarLike(registrar).addToList(listName_, account_);
} else {
IRegistrarLike(registrar).removeFromList(listName_, account_);
}
}
/**
* @dev Mints M Token to the `recipient_`.
* @param recipient_ The account to mint M tokens to.
* @param amount_ The amount of M Token to mint to the recipient.
* @param index_ The index from the source chain.
*/
function _mintOrUnlock(uint256, address recipient_, uint256 amount_, uint128 index_) internal override {
// Update M token index only if the index received from the remote chain is bigger
if (index_ > _currentIndex()) {
ISpokeMTokenLike(mToken).mint(recipient_, amount_, index_);
} else {
ISpokeMTokenLike(mToken).mint(recipient_, amount_);
}
}
/**
* @dev Burns M Token.
* @param amount_ The amount of M Token to burn from the SpokePortal.
*/
function _burnOrLock(uint256, uint256 amount_) internal override {
ISpokeMTokenLike(mToken).burn(amount_);
}
///////////////////////////////////////////////////////////////////////////
// INTERNAL/PRIVATE VIEW/PURE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @dev Returns the current M token index used by the Spoke Portal.
function _currentIndex() internal view override returns (uint128) {
return ISpokeMTokenLike(mToken).currentIndex();
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
import { IMTokenLike } from "./IMTokenLike.sol";
/**
* @title Subset of Spoke M Token interface required for `SpokePortal` contract.
* @author M^0 Labs
*/
interface ISpokeMTokenLike is IMTokenLike {
/**
* @notice Mints tokens.
* @dev MUST only be callable by the SpokePortal.
* @param account The address of account to mint to.
* @param amount The amount of M Token to mint.
*/
function mint(address account, uint256 amount) external;
/**
* @notice Updates the index and mints tokens.
* @dev MUST only be callable by the SpokePortal.
* @param account The address of account to mint to.
* @param amount The amount of M Token to mint.
* @param index The index to update to.
*/
function mint(address account, uint256 amount, uint128 index) external;
/**
* @notice Burns tokens of msg.sender.
* @dev MUST only be callable by the SpokePortal.
* @param amount The amount of M Token to burn.
*/
function burn(uint256 amount) external;
/**
* @notice Updates the latest index and latest accrual time in storage.
* @param index The new index to compute present amounts from principal amounts.
*/
function updateIndex(uint128 index) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
/**
* @title IRegistrarLike interface
* @author M^0 Labs
* @notice Subset of Registrar interface required for Portal contracts.
*/
interface IRegistrarLike {
/**
* @notice Adds `account` to `list`.
* @param list The key for some list.
* @param account The address of some account to be added.
*/
function addToList(bytes32 list, address account) external;
/**
* @notice Removes `account` from `list`.
* @param list The key for some list.
* @param account The address of some account to be removed.
*/
function removeFromList(bytes32 list, address account) external;
/**
* @notice Sets `key` to `value`.
* @param key Some key.
* @param value Some value.
*/
function setKey(bytes32 key, bytes32 value) external;
/**
* @notice Returns the value of `key`.
* @param key Some key.
* @return Some value.
*/
function get(bytes32 key) external view returns (bytes32);
/**
* @notice Returns whether `list` contains `account`.
* @param list The key for some list.
* @param account The address of some account.
* @return Whether `list` contains `account`.
*/
function listContains(bytes32 list, address account) external view returns (bool);
/// @notice Returns the address of the Portal contract.
function portal() external view returns (address);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
import { IPortal } from "./IPortal.sol";
/**
* @title SpokePortal interface.
* @author M^0 Labs
*/
interface ISpokePortal is IPortal {
///////////////////////////////////////////////////////////////////////////
// EVENTS //
///////////////////////////////////////////////////////////////////////////
/**
* @notice Emitted when M Token index is received from Mainnet.
* @param index M token index.
*/
event MTokenIndexReceived(uint128 index);
/**
* @notice Emitted when the Registrar key is received from Mainnet.
* @param key The Registrar key of some value.
* @param value The value.
*/
event RegistrarKeyReceived(bytes32 indexed key, bytes32 value);
/**
* @notice Emitted when the Registrar list status is received from Mainnet.
* @param listName The name of the list.
* @param account The account.
* @param status Indicates if the account is added or removed from the list.
*/
event RegistrarListStatusReceived(bytes32 indexed listName, address indexed account, bool status);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
import { PayloadType } from "../libs/PayloadEncoder.sol";
/**
* @title IPortal interface
* @author M^0 Labs
* @notice Subset of functions inherited by both IHubPortal and ISpokePortal.
*/
interface IPortal {
///////////////////////////////////////////////////////////////////////////
// EVENTS //
///////////////////////////////////////////////////////////////////////////
/**
* @notice Emitted when M token is sent to a destination chain.
* @param sourceToken The address of the token on the source chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param destinationToken The address of the token on the destination chain.
* @param sender The address that bridged the M tokens via the Portal.
* @param recipient The account receiving tokens on destination chain.
* @param amount The amount of tokens.
* @param index The M token index.
* @param messageId The unique identifier for the sent message.
*/
event MTokenSent(
address indexed sourceToken,
uint256 destinationChainId,
address destinationToken,
address indexed sender,
address indexed recipient,
uint256 amount,
uint128 index,
bytes32 messageId
);
/**
* @notice Emitted when M token is received from a source chain.
* @param sourceChainId The EVM chain Id of the source chain.
* @param destinationToken The address of the token on the destination chain.
* @param sender The account sending tokens.
* @param recipient The account receiving tokens.
* @param amount The amount of tokens.
* @param index The M token index
*/
event MTokenReceived(
uint256 sourceChainId,
address indexed destinationToken,
address indexed sender,
address indexed recipient,
uint256 amount,
uint128 index
);
/**
* @notice Emitted when wrapping M token is failed on the destination.
* @param destinationWrappedToken The address of the Wrapped M Token on the destination chain.
* @param recipient The account receiving tokens.
* @param amount The amount of tokens.
*/
event WrapFailed(address indexed destinationWrappedToken, address indexed recipient, uint256 amount);
/**
* @notice Emitted when the Bridge contract responsible for cross-chain communication is set
* @param previousBridge The address of the previous Bridge.
* @param newBridge The address of the new Bridge.
*/
event BridgeSet(address indexed previousBridge, address indexed newBridge);
/**
* @notice Emitted when M token is set for the remote chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param mToken The address of M token on the destination chain.
*/
event DestinationMTokenSet(uint256 indexed destinationChainId, address mToken);
/**
* @notice Emitted when a bridging path support status is updated.
* @param sourceToken The address of the token on the current chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param destinationToken The address of the token on the destination chain.
* @param supported `True` if the token is supported, `false` otherwise.
*/
event SupportedBridgingPathSet(
address indexed sourceToken, uint256 indexed destinationChainId, address indexed destinationToken, bool supported
);
/**
* @notice Emitted when the gas limit for a payload type is updated.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param payloadType The type of payload.
* @param gasLimit The gas limit.
*/
event PayloadGasLimitSet(uint256 indexed destinationChainId, PayloadType indexed payloadType, uint256 gasLimit);
///////////////////////////////////////////////////////////////////////////
// CUSTOM ERRORS //
///////////////////////////////////////////////////////////////////////////
/// @notice Thrown when the M token is 0x0.
error ZeroMToken();
/// @notice Thrown when the M token is 0x0.
error ZeroRemoteMToken();
/// @notice Thrown when the Registrar address is 0x0.
error ZeroRegistrar();
/// @notice Thrown when the Swap Facility address is 0x0.
error ZeroSwapFacility();
/// @notice Thrown when the Bridge address is 0x0.
error ZeroBridge();
/// @notice Thrown when the source token address is 0x0.
error ZeroSourceToken();
/// @notice Thrown when the destination token address is 0x0.
error ZeroDestinationToken();
/// @notice Thrown when the transfer amount is 0.
error ZeroAmount();
/// @notice Thrown when the refund address is 0x0.
error ZeroRefundAddress();
/// @notice Thrown when the recipient address is 0x0.
error ZeroRecipient();
/// @notice Thrown when `receiveMessage` function caller is not the bridge.
error NotBridge();
/// @notice Thrown in `transferMLikeToken` function when bridging path is not supported
error UnsupportedBridgingPath(address sourceToken, uint256 destinationChainId, address destinationToken);
/// @notice Thrown when the destination chain id is equal to the source one.
error InvalidDestinationChain(uint256 destinationChainId);
///////////////////////////////////////////////////////////////////////////
// VIEW/PURE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @notice The current index of the Portal's earning mechanism.
function currentIndex() external view returns (uint128);
/// @notice The address of the M token.
function mToken() external view returns (address);
/// @notice The address of the Registrar contract.
function registrar() external view returns (address);
/// @notice The address of the Bridge contract responsible for cross-chain communication.
function bridge() external view returns (address);
/// @notice The address of the Swap Facility contract.
function swapFacility() external view returns (address);
/// @notice The address of the original caller of `transfer` and `transferMLikeToken` functions.
function msgSender() external view returns (address);
/**
* @notice Returns the address of M token on the destination chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @return mToken The address of M token on the destination chain.
*/
function destinationMToken(uint256 destinationChainId) external view returns (address mToken);
/**
* @notice Indicates whether the provided bridging path is supported.
* @param sourceToken The address of the token on the current chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param destinationToken The address of the token on the destination chain.
* @return supported `True` if the token is supported, `false` otherwise.
*/
function supportedBridgingPath(
address sourceToken,
uint256 destinationChainId,
address destinationToken
) external view returns (bool supported);
/**
* @notice Returns the gas limit required to process a message
* with the specified payload type on the destination chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param payloadType The type of payload.
* @return gasLimit The gas limit.
*/
function payloadGasLimit(uint256 destinationChainId, PayloadType payloadType) external view returns (uint256 gasLimit);
/**
* @notice Returns the delivery fee for token transfer.
* @dev The fee must be passed as mgs.value when calling `transfer` or `transferMLikeToken`.
* @param amount The amount of tokens to transfer.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param recipient The account to receive tokens.
* @param fee The delivery fee.
*/
function quoteTransfer(uint256 amount, uint256 destinationChainId, address recipient) external view returns (uint256 fee);
///////////////////////////////////////////////////////////////////////////
// INTERACTIVE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/**
* @notice Initializes the Proxy's storage
* @param bridge_ The address of the Bridge contract.
* @param initialOwner_ The address of the owner.
* @param initialPauser_ The address of the pauser.
*/
function initialize(address bridge_, address initialOwner_, address initialPauser_) external;
/**
* @notice Sets address of the Bridge contract responsible for cross-chain communication.
* @param bridge The address of the Bridge.
*/
function setBridge(address bridge) external;
/**
* @notice Sets M token address on the remote chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param mToken The address of M token on the destination chain.
*/
function setDestinationMToken(uint256 destinationChainId, address mToken) external;
/**
* @notice Sets a bridging path support status.
* @param sourceToken The address of the token on the current chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param destinationToken The address of the token on the destination chain.
* @param supported `True` if the token is supported, `false` otherwise.
*/
function setSupportedBridgingPath(
address sourceToken,
uint256 destinationChainId,
address destinationToken,
bool supported
) external;
/**
* @notice Sets the gas limit required to process a message
* with the specified payload type on the destination chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param payloadType The payload type.
* @param gasLimit The gas limit required to process the message.
*/
function setPayloadGasLimit(uint256 destinationChainId, PayloadType payloadType, uint256 gasLimit) external;
/**
* @notice Transfers M token to the destination chain.
* @param amount The amount of tokens to transfer.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param recipient The account to receive tokens.
* @param refundAddress The address to receive excess native gas on the source chain.
* @return messageId The unique identifier of the message sent.
*/
function transfer(
uint256 amount,
uint256 destinationChainId,
address recipient,
address refundAddress
) external payable returns (bytes32 messageId);
/**
* @notice Transfers M or Wrapped M Token to the destination chain.
* @dev If wrapping on the destination fails, the recipient will receive $M token.
* @param amount The amount of tokens to transfer.
* @param sourceToken The address of the token (M or Wrapped M) on the source chain.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param destinationToken The address of the token (M or Wrapped M) on the destination chain.
* @param recipient The account to receive tokens.
* @param refundAddress The address to receive excess native gas on the source chain.
* @return messageId The unique identifier of the message sent.
*/
function transferMLikeToken(
uint256 amount,
address sourceToken,
uint256 destinationChainId,
address destinationToken,
address recipient,
address refundAddress
) external payable returns (bytes32 messageId);
/**
* @notice Receives a message from the bridge.
* @param sourceChainId The EVM chain Id of the source chain.
* @param payload The message payload.
*/
function receiveMessage(uint256 sourceChainId, bytes calldata payload) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
import { IERC20 } from "../lib/common/src/interfaces/IERC20.sol";
import { Migratable } from "../lib/common/src/Migratable.sol";
import { IndexingMath } from "../lib/common/src/libs/IndexingMath.sol";
import { IPortal } from "./interfaces/IPortal.sol";
import { IBridge } from "./interfaces/IBridge.sol";
import { ISwapFacilityLike } from "./interfaces/ISwapFacilityLike.sol";
import { PausableOwnableUpgradeable } from "./access/PausableOwnableUpgradeable.sol";
import { TypeConverter } from "./libs/TypeConverter.sol";
import { SafeCall } from "./libs/SafeCall.sol";
import { PayloadType, PayloadEncoder } from "./libs/PayloadEncoder.sol";
import { ReentrancyLock } from "./libs/ReentrancyLock.sol";
/**
* @title Portal
* @author M^0 Labs
* @notice Base Portal contract inherited by HubPortal and SpokePortal.
*/
abstract contract Portal is IPortal, PausableOwnableUpgradeable, ReentrancyLock, Migratable {
using TypeConverter for *;
using PayloadEncoder for bytes;
using SafeCall for address;
/// @inheritdoc IPortal
address public immutable mToken;
/// @inheritdoc IPortal
address public immutable registrar;
/// @inheritdoc IPortal
address public immutable swapFacility;
/// @inheritdoc IPortal
address public bridge;
/// @inheritdoc IPortal
mapping(address sourceToken => mapping(uint256 destinationChainId => mapping(address destinationToken => bool supported)))
public supportedBridgingPath;
/// @inheritdoc IPortal
mapping(uint256 destinationChainId => address mToken) public destinationMToken;
/// @inheritdoc IPortal
mapping(uint256 destinationChainId => mapping(PayloadType payloadType => uint256 gasLimit)) public payloadGasLimit;
/**
* @notice Constructs the Implementation contract
* @dev Sets immutable storage.
* @param mToken_ The address of M token.
* @param registrar_ The address of Registrar.
* @param swapFacility_ The address of Swap Facility.
*/
constructor(address mToken_, address registrar_, address swapFacility_) {
_disableInitializers();
if ((mToken = mToken_) == address(0)) revert ZeroMToken();
if ((registrar = registrar_) == address(0)) revert ZeroRegistrar();
if ((swapFacility = swapFacility_) == address(0)) revert ZeroSwapFacility();
}
/**
* @notice Initializes the Proxy's storage
* @param bridge_ The address of M token.
* @param initialOwner_ The address of the owner.
* @param initialPauser_ The address of the pauser.
*/
function _initialize(address bridge_, address initialOwner_, address initialPauser_) internal onlyInitializing {
if ((bridge = bridge_) == address(0)) revert ZeroBridge();
__PausableOwnable_init(initialOwner_, initialPauser_);
}
///////////////////////////////////////////////////////////////////////////
// EXTERNAL VIEW/PURE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @inheritdoc IPortal
function currentIndex() external view returns (uint128) {
return _currentIndex();
}
/// @inheritdoc IPortal
function quoteTransfer(
uint256 amount_,
uint256 destinationChainId_,
address recipient_
) external view returns (uint256 fee_) {
// NOTE: for quoting delivery only the payload size and destination chain matter.
address destinationToken_ = destinationMToken[destinationChainId_];
bytes memory payload_ =
PayloadEncoder.encodeTokenTransfer(amount_, destinationToken_, msg.sender, recipient_, _currentIndex());
return IBridge(bridge).quote(destinationChainId_, payloadGasLimit[destinationChainId_][PayloadType.Token], payload_);
}
/// @inheritdoc IPortal
function msgSender() public view returns (address) {
return _getLocker();
}
///////////////////////////////////////////////////////////////////////////
// EXTERNAL INTERACTIVE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @inheritdoc IPortal
function transfer(
uint256 amount_,
uint256 destinationChainId_,
address recipient_,
address refundAddress_
) external payable whenNotPaused isNotLocked returns (bytes32 messageId_) {
return _transferMLikeToken(
amount_, mToken, destinationChainId_, destinationMToken[destinationChainId_], recipient_, refundAddress_
);
}
/// @inheritdoc IPortal
function transferMLikeToken(
uint256 amount_,
address sourceToken_,
uint256 destinationChainId_,
address destinationToken_,
address recipient_,
address refundAddress_
) external payable whenNotPaused isNotLocked returns (bytes32 messageId_) {
if (!supportedBridgingPath[sourceToken_][destinationChainId_][destinationToken_]) {
revert UnsupportedBridgingPath(sourceToken_, destinationChainId_, destinationToken_);
}
return _transferMLikeToken(amount_, sourceToken_, destinationChainId_, destinationToken_, recipient_, refundAddress_);
}
/// @inheritdoc IPortal
function receiveMessage(uint256 sourceChainId_, bytes calldata payload_) external {
if (msg.sender != bridge) revert NotBridge();
PayloadType payloadType_ = payload_.getPayloadType();
if (payloadType_ == PayloadType.Token) {
_receiveMLikeToken(sourceChainId_, payload_);
return;
}
_receiveCustomPayload(payloadType_, payload_);
}
///////////////////////////////////////////////////////////////////////////
// OWNER INTERACTIVE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @inheritdoc IPortal
function setBridge(address newBridge_) external onlyOwner {
if (newBridge_ == address(0)) revert ZeroBridge();
address previousBridge_ = bridge;
bridge = newBridge_;
emit BridgeSet(previousBridge_, newBridge_);
}
/// @inheritdoc IPortal
function setDestinationMToken(uint256 destinationChainId_, address mToken_) external onlyOwner {
if (destinationChainId_ == block.chainid) revert InvalidDestinationChain(destinationChainId_);
if (mToken_ == address(0)) revert ZeroMToken();
destinationMToken[destinationChainId_] = mToken_;
emit DestinationMTokenSet(destinationChainId_, mToken_);
}
/// @inheritdoc IPortal
function setSupportedBridgingPath(
address sourceToken_,
uint256 destinationChainId_,
address destinationToken_,
bool supported_
) external onlyOwner {
if (sourceToken_ == address(0)) revert ZeroSourceToken();
if (destinationChainId_ == block.chainid) revert InvalidDestinationChain(destinationChainId_);
if (destinationToken_ == address(0)) revert ZeroDestinationToken();
supportedBridgingPath[sourceToken_][destinationChainId_][destinationToken_] = supported_;
emit SupportedBridgingPathSet(sourceToken_, destinationChainId_, destinationToken_, supported_);
}
/// @inheritdoc IPortal
function setPayloadGasLimit(uint256 destinationChainId_, PayloadType payloadType_, uint256 gasLimit_) external onlyOwner {
payloadGasLimit[destinationChainId_][payloadType_] = gasLimit_;
emit PayloadGasLimitSet(destinationChainId_, payloadType_, gasLimit_);
}
/**
* @dev Performs the contract migration by delegate-calling `migrator_`.
* @param migrator_ The address of a migrator contract.
*/
function migrate(address migrator_) external onlyOwner {
_migrate(migrator_);
}
///////////////////////////////////////////////////////////////////////////
// INTERNAL/PRIVATE INTERACTIVE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/**
* @dev Transfers M or Wrapped M token to the remote chain.
* @param amount_ The amount of tokens to transfer.
* @param sourceToken_ The address of the source token.
* @param destinationChainId_ The EVM chain Id of the destination chain.
* @param destinationToken_ The address of the destination token.
* @param recipient_ The address of the recipient.
* @param refundAddress_ The address to receive the fee refund.
* @return messageId_ The ID uniquely identifying the message.
*/
function _transferMLikeToken(
uint256 amount_,
address sourceToken_,
uint256 destinationChainId_,
address destinationToken_,
address recipient_,
address refundAddress_
) private returns (bytes32 messageId_) {
_revertIfZeroAmount(amount_);
_revertIfZeroRefundAddress(refundAddress_);
if (destinationToken_ == address(0)) revert ZeroDestinationToken();
if (recipient_ == address(0)) revert ZeroRecipient();
IERC20 mToken_ = IERC20(mToken);
uint256 startingBalance_ = mToken_.balanceOf(address(this));
// transfer source token from the sender
IERC20(sourceToken_).transferFrom(msg.sender, address(this), amount_);
// if the source token isn't M token, unwrap it
if (sourceToken_ != address(mToken_)) {
IERC20(sourceToken_).approve(swapFacility, amount_);
ISwapFacilityLike(swapFacility).swapOutM(sourceToken_, amount_, address(this));
}
// The actual amount of M tokens that Portal received from the sender.
// Accounts for potential rounding errors when transferring between earners and non-earners,
// as well as potential fee-on-transfer functionality in the source token.
uint256 actualAmount_ = mToken_.balanceOf(address(this)) - startingBalance_;
if (amount_ > actualAmount_) {
unchecked {
// If the difference between the specified transfer amount and the actual amount exceeds
// the maximum acceptable rounding error (e.g., due to fee-on-transfer in an extension token)
// transfer the actual amount, not the specified.
// Otherwise, the specified amount will be transferred and the deficit caused by rounding error will
// be covered from the yield earned by HubPortal.
if (amount_ - actualAmount_ > _getMaxRoundingError()) {
amount_ = actualAmount_;
// Ensure that updated transfer amount is greater than 0
_revertIfZeroAmount(amount_);
}
}
}
// Burn M tokens on Spoke.
// In case of Hub, only update the bridged principal amount as tokens already transferred.
_burnOrLock(destinationChainId_, amount_);
uint128 index_ = _currentIndex();
bytes memory payload_ = PayloadEncoder.encodeTokenTransfer(amount_, destinationToken_, msg.sender, recipient_, index_);
messageId_ = _sendMessage(destinationChainId_, PayloadType.Token, refundAddress_, payload_);
// Prevent stack too deep
uint256 transferAmount_ = amount_;
emit MTokenSent(
sourceToken_, destinationChainId_, destinationToken_, msg.sender, recipient_, transferAmount_, index_, messageId_
);
}
/**
* @dev Sends a cross-chain message using the bridge.
* @param destinationChainId_ The EVM chain Id of the destination chain.
* @param payloadType_ The type of the payload.
* @param refundAddress_ The address to receive the fee refund.
* @param payload_ The message payload to send.
* @return messageId_ The ID uniquely identifying the message.
*/
function _sendMessage(
uint256 destinationChainId_,
PayloadType payloadType_,
address refundAddress_,
bytes memory payload_
) internal returns (bytes32 messageId_) {
return IBridge(bridge).sendMessage{ value: msg.value }(
destinationChainId_, payloadGasLimit[destinationChainId_][payloadType_], refundAddress_, payload_
);
}
/**
* @dev Handles token transfer message on the destination.
* @param sourceChainId_ The EVM chain Id of the source chain.
* @param payload_ The message payload.
*/
function _receiveMLikeToken(uint256 sourceChainId_, bytes memory payload_) private {
(uint256 amount_, address destinationToken_, address sender_, address recipient_, uint128 index_) =
payload_.decodeTokenTransfer();
emit MTokenReceived(sourceChainId_, destinationToken_, sender_, recipient_, amount_, index_);
address mToken_ = mToken;
if (destinationToken_ == mToken_) {
// mints or unlocks M Token to the recipient
_mintOrUnlock(sourceChainId_, recipient_, amount_, index_);
} else {
// mints or unlocks M Token to the Portal
_mintOrUnlock(sourceChainId_, address(this), amount_, index_);
// wraps M token and transfers it to the recipient
_wrap(mToken_, destinationToken_, recipient_, amount_);
}
}
/**
* @dev Wraps $M token to the token specified by `destinationWrappedToken_`.
* If wrapping fails transfers $M token to `recipient_`.
* @param mToken_ The address of $M token.
* @param destinationWrappedToken_ The address of the wrapped token.
* @param recipient_ The account to receive wrapped token.
* @param amount_ The amount to wrap.
*/
function _wrap(address mToken_, address destinationWrappedToken_, address recipient_, uint256 amount_) private {
IERC20(mToken_).approve(swapFacility, amount_);
// Attempt to wrap $M token
// NOTE: the call might fail with out-of-gas exception
// even if the destination token is the valid wrapped M token.
// Recipients must support both $M and wrapped $M transfers.
(bool success,) =
swapFacility.call(abi.encodeCall(ISwapFacilityLike.swapInM, (destinationWrappedToken_, amount_, recipient_)));
if (!success) {
emit WrapFailed(destinationWrappedToken_, recipient_, amount_);
// Reset approval to prevent a potential double-spend attack
IERC20(mToken_).approve(swapFacility, 0);
// Transfer $M token to the recipient
IERC20(mToken_).transfer(recipient_, amount_);
}
}
/**
* @dev Overridden in SpokePortal to handle custom payload messages.
* @param payloadType_ The type of the payload (Index, Key, or List).
* @param payload_ The message payload to process.
*/
function _receiveCustomPayload(PayloadType payloadType_, bytes memory payload_) internal virtual { }
/**
* @dev HubPortal: unlocks and transfers `amount_` M tokens to `recipient_`.
* SpokePortal: mints `amount_` M tokens to `recipient_`.
* @param sourceChainId_ The EVM id of the source chain.
* @param recipient_ The account receiving M tokens.
* @param amount_ The amount of M tokens to unlock/mint.
* @param index_ The index from the source chain.
*/
function _mintOrUnlock(uint256 sourceChainId_, address recipient_, uint256 amount_, uint128 index_) internal virtual { }
/**
* @dev HubPortal: locks amount_` M tokens.
* SpokePortal: burns `amount_` M tokens.
* @param destinationChainId_ The EVM id of the destination chain.
* @param amount_ The amount of M tokens to lock/burn.
*/
function _burnOrLock(uint256 destinationChainId_, uint256 amount_) internal virtual { }
///////////////////////////////////////////////////////////////////////////
// INTERNAL/PRIVATE VIEW/PURE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @dev Reverts if `amount` is zero.
function _revertIfZeroAmount(uint256 amount_) private pure {
if (amount_ == 0) revert ZeroAmount();
}
/// @dev Reverts if `refundAddress` is zero address.
function _revertIfZeroRefundAddress(address refundAddress_) internal pure {
if (refundAddress_ == address(0)) revert ZeroRefundAddress();
}
/// @inheritdoc Migratable
function _getMigrator() internal pure override returns (address migrator_) {
// NOTE: in this version only the owner-controlled migration via `migrate()` function is supported
return address(0);
}
/// @dev Returns the current M token index used by the Portal.
function _currentIndex() internal view virtual returns (uint128) { }
/// @dev Returns the maximum rounding error that can occur when transferring M tokens to the Portal
function _getMaxRoundingError() private view returns (uint256) {
return _currentIndex() / IndexingMath.EXP_SCALED_ONE + 1;
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
import { BytesParser } from "./BytesParser.sol";
import { TypeConverter } from "./TypeConverter.sol";
enum PayloadType {
Token,
Index,
Key,
List
}
/**
* @title PayloadEncoder
* @author M^0 Labs
* @notice Encodes and decodes cross-chain message payloads.
*/
library PayloadEncoder {
using BytesParser for bytes;
using TypeConverter for *;
uint256 internal constant PAYLOAD_TYPE_LENGTH = 1;
/// @dev PayloadType.Token = 0, PayloadType.Index = 1, PayloadType.Key = 2, PayloadType.List = 3
uint256 internal constant MAX_PAYLOAD_TYPE = 3;
error InvalidPayloadLength(uint256 length);
error InvalidPayloadType(uint8 value);
/**
* @notice Decodes the payload type from the payload.
* @param payload_ The payload to decode.
* @return payloadType_ The decoded payload type.
*/
function getPayloadType(bytes memory payload_) internal pure returns (PayloadType payloadType_) {
if (payload_.length < PAYLOAD_TYPE_LENGTH) revert InvalidPayloadLength(payload_.length);
uint8 type_;
(type_,) = payload_.asUint8Unchecked(0);
if (type_ > MAX_PAYLOAD_TYPE) revert InvalidPayloadType(type_);
payloadType_ = PayloadType(type_);
}
/**
* @notice Encodes a token transfer payload.
* @dev Encoded values are packed using `abi.encodePacked`.
* @param amount_ The amount of tokens to transfer.
* @param destinationToken_ The address of the destination token.
* @param sender_ The address of the sender.
* @param recipient_ The address of the recipient.
* @param index_ The M token index.
* @return encoded_ The encoded payload.
*/
function encodeTokenTransfer(
uint256 amount_,
address destinationToken_,
address sender_,
address recipient_,
uint128 index_
) internal pure returns (bytes memory encoded_) {
encoded_ = abi.encodePacked(PayloadType.Token, amount_, destinationToken_, sender_, recipient_, index_);
}
/**
* @notice Decodes a token transfer payload.
* @param payload_ The payload to decode.
* @return amount_ The amount of tokens to transfer.
* @return destinationToken_ The address of the destination token.
* @return sender_ The address of the sender.
* @return recipient_ The address of the recipient.
* @return index_ The M token index.
*/
function decodeTokenTransfer(bytes memory payload_)
internal
pure
returns (uint256 amount_, address destinationToken_, address sender_, address recipient_, uint128 index_)
{
uint256 offset_ = PAYLOAD_TYPE_LENGTH;
(amount_, offset_) = payload_.asUint256Unchecked(offset_);
(destinationToken_, offset_) = payload_.asAddressUnchecked(offset_);
(sender_, offset_) = payload_.asAddressUnchecked(offset_);
(recipient_, offset_) = payload_.asAddressUnchecked(offset_);
(index_, offset_) = payload_.asUint128Unchecked(offset_);
payload_.checkLength(offset_);
}
/**
* @notice Encodes M token index payload.
* @param index_ The M token index.
* @return encoded_ The encoded payload.
*/
function encodeIndex(uint128 index_) internal pure returns (bytes memory encoded_) {
encoded_ = abi.encodePacked(PayloadType.Index, index_);
}
/**
* @notice Decodes M token index payload.
* @param payload_ The payload to decode.
* @return index_ The M token index.
*/
function decodeIndex(bytes memory payload_) internal pure returns (uint128 index_) {
uint256 offset_ = PAYLOAD_TYPE_LENGTH;
(index_, offset_) = payload_.asUint128Unchecked(offset_);
payload_.checkLength(offset_);
}
/**
* @notice Encodes a Registrar key-value pair payload.
* @param key_ The key.
* @param value_ The value.
* @return encoded_ The encoded payload.
*/
function encodeKey(bytes32 key_, bytes32 value_) internal pure returns (bytes memory encoded_) {
encoded_ = abi.encodePacked(PayloadType.Key, key_, value_);
}
/**
* @notice Decodes a Registrar key-value pair payload.
* @param payload_ The payload to decode.
* @return key_ The key.
* @return value_ The value.
*/
function decodeKey(bytes memory payload_) internal pure returns (bytes32 key_, bytes32 value_) {
uint256 offset_ = PAYLOAD_TYPE_LENGTH;
(key_, offset_) = payload_.asBytes32Unchecked(offset_);
(value_, offset_) = payload_.asBytes32Unchecked(offset_);
payload_.checkLength(offset_);
}
/**
* @notice Encodes a list update payload.
* @param listName_ The name of the list.
* @param account_ The address of the account.
* @param add_ Indicates whether to add or remove the account from the list.
* @return encoded_ The encoded payload.
*/
function encodeListUpdate(bytes32 listName_, address account_, bool add_) internal pure returns (bytes memory encoded_) {
encoded_ = abi.encodePacked(PayloadType.List, listName_, account_, add_);
}
/**
* @notice Decodes a list update payload.
* @param payload_ The payload to decode.
* @return listName_ The name of the list.
* @return account_ The address of the account.
* @return add_ Indicates whether the account was added or removed from the list.
*/
function decodeListUpdate(bytes memory payload_) internal pure returns (bytes32 listName_, address account_, bool add_) {
uint256 offset_ = PAYLOAD_TYPE_LENGTH;
(listName_, offset_) = payload_.asBytes32Unchecked(offset_);
(account_, offset_) = payload_.asAddressUnchecked(offset_);
(add_, offset_) = payload_.asBoolUnchecked(offset_);
payload_.checkLength(offset_);
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
/**
* @title IMTokenLike interface
* @author M^0 Labs
* @notice Subset of M Token interface required for Portal contracts.
*/
interface IMTokenLike {
/**
* @notice Emitted when there is insufficient balance to decrement from `account`.
* @param account The account with insufficient balance.
* @param rawBalance The raw balance of the account.
* @param amount The amount to decrement the `rawBalance` by.
*/
error InsufficientBalance(address account, uint256 rawBalance, uint256 amount);
/// @notice The current index that would be written to storage if `updateIndex` is called.
function currentIndex() external view returns (uint128);
/**
* @notice Checks if account is an earner.
* @param account The account to check.
* @return True if account is an earner, false otherwise.
*/
function isEarning(address account) external view returns (bool);
/// @notice Starts earning for caller if allowed by TTG.
function startEarning() external;
/// @notice Stops earning for the account.
function stopEarning(address account) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.20 <0.9.0;
/**
* @title ERC20 Token Standard.
* @author M^0 Labs
* @dev The interface as defined by EIP-20: https://eips.ethereum.org/EIPS/eip-20
*/
interface IERC20 {
/* ============ Events ============ */
/**
* @notice Emitted when `spender` has been approved for `amount` of the token balance of `account`.
* @param account The address of the account.
* @param spender The address of the spender being approved for the allowance.
* @param amount The amount of the allowance being approved.
*/
event Approval(address indexed account, address indexed spender, uint256 amount);
/**
* @notice Emitted when `amount` tokens is transferred from `sender` to `recipient`.
* @param sender The address of the sender who's token balance is decremented.
* @param recipient The address of the recipient who's token balance is incremented.
* @param amount The amount of tokens being transferred.
*/
event Transfer(address indexed sender, address indexed recipient, uint256 amount);
/* ============ Interactive Functions ============ */
/**
* @notice Allows a calling account to approve `spender` to spend up to `amount` of its token balance.
* @dev MUST emit an `Approval` event.
* @param spender The address of the account being allowed to spend up to the allowed amount.
* @param amount The amount of the allowance being approved.
* @return Whether or not the approval was successful.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @notice Allows a calling account to transfer `amount` tokens to `recipient`.
* @param recipient The address of the recipient who's token balance will be incremented.
* @param amount The amount of tokens being transferred.
* @return Whether or not the transfer was successful.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @notice Allows a calling account to transfer `amount` tokens from `sender`, with allowance, to a `recipient`.
* @param sender The address of the sender who's token balance will be decremented.
* @param recipient The address of the recipient who's token balance will be incremented.
* @param amount The amount of tokens being transferred.
* @return Whether or not the transfer was successful.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/* ============ View/Pure Functions ============ */
/**
* @notice Returns the allowance `spender` is allowed to spend on behalf of `account`.
* @param account The address of the account who's token balance `spender` is allowed to spend.
* @param spender The address of an account allowed to spend on behalf of `account`.
* @return The amount `spender` can spend on behalf of `account`.
*/
function allowance(address account, address spender) external view returns (uint256);
/**
* @notice Returns the token balance of `account`.
* @param account The address of some account.
* @return The token balance of `account`.
*/
function balanceOf(address account) external view returns (uint256);
/// @notice Returns the number of decimals UIs should assume all amounts have.
function decimals() external view returns (uint8);
/// @notice Returns the name of the contract/token.
function name() external view returns (string memory);
/// @notice Returns the symbol of the token.
function symbol() external view returns (string memory);
/// @notice Returns the current total supply of the token.
function totalSupply() external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.20 <0.9.0;
import { IMigratable } from "./interfaces/IMigratable.sol";
/**
* @title Abstract implementation for exposing the ability to migrate a contract, extending ERC-1967.
* @author M^0 Labs
*/
abstract contract Migratable is IMigratable {
/* ============ Variables ============ */
/// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.implementation') - 1`.
uint256 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/* ============ Interactive Functions ============ */
/// @inheritdoc IMigratable
function migrate() external {
_migrate(_getMigrator());
}
/* ============ View/Pure Functions ============ */
/// @inheritdoc IMigratable
function implementation() public view returns (address implementation_) {
assembly {
implementation_ := sload(_IMPLEMENTATION_SLOT)
}
}
/* ============ Internal Interactive Functions ============ */
/**
* @dev Performs an arbitrary migration by delegate-calling `migrator_`.
* @param migrator_ The address of a migrator contract.
*/
function _migrate(address migrator_) internal {
if (migrator_ == address(0)) revert ZeroMigrator();
if (migrator_.code.length == 0) revert InvalidMigrator();
address oldImplementation_ = implementation();
(bool success_, ) = migrator_.delegatecall("");
if (!success_) revert MigrationFailed();
address newImplementation_ = implementation();
emit Migrated(migrator_, oldImplementation_, newImplementation_);
// NOTE: Redundant event emitted to conform to the EIP-1967 standard.
emit Upgraded(newImplementation_);
}
/* ============ Internal View/Pure Functions ============ */
/// @dev Returns the address of a migrator contract.
function _getMigrator() internal view virtual returns (address);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.20 <0.9.0;
import { UIntMath } from "./UIntMath.sol";
/**
* @title Helper library for indexing math functions.
* @author M^0 Labs
*/
library IndexingMath {
/* ============ Variables ============ */
/// @notice The scaling of indexes for exponent math.
uint56 internal constant EXP_SCALED_ONE = 1e12;
/* ============ Custom Errors ============ */
/// @notice Emitted when a division by zero occurs.
error DivisionByZero();
/* ============ Exposed Functions ============ */
/**
* @notice Helper function to calculate `(x * EXP_SCALED_ONE) / y`, rounded down.
* @dev Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
*/
function divide240By128Down(uint240 x, uint128 y) internal pure returns (uint112) {
if (y == 0) revert DivisionByZero();
unchecked {
// NOTE: While `uint256(x) * EXP_SCALED_ONE` can technically overflow, these divide/multiply functions are
// only used for the purpose of principal/present amount calculations for continuous indexing, and
// so for an `x` to be large enough to overflow this, it would have to be a possible result of
// `multiply112By128Down` or `multiply112By128Up`, which would already satisfy
// `uint256(x) * EXP_SCALED_ONE < type(uint240).max`.
return UIntMath.safe112((uint256(x) * EXP_SCALED_ONE) / y);
}
}
/**
* @notice Helper function to calculate `(x * EXP_SCALED_ONE) / y`, rounded up.
* @dev Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
*/
function divide240By128Up(uint240 x, uint128 y) internal pure returns (uint112) {
if (y == 0) revert DivisionByZero();
unchecked {
// NOTE: While `uint256(x) * EXP_SCALED_ONE` can technically overflow, these divide/multiply functions are
// only used for the purpose of principal/present amount calculations for continuous indexing, and
// so for an `x` to be large enough to overflow this, it would have to be a possible result of
// `multiply112By128Down` or `multiply112By128Up`, which would already satisfy
// `uint256(x) * EXP_SCALED_ONE < type(uint240).max`.
return UIntMath.safe112(((uint256(x) * EXP_SCALED_ONE) + y - 1) / y);
}
}
/**
* @notice Helper function to calculate `(x * y) / EXP_SCALED_ONE`, rounded down.
* @dev Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
*/
function multiply112By128Down(uint112 x, uint128 y) internal pure returns (uint240) {
unchecked {
return uint240((uint256(x) * y) / EXP_SCALED_ONE);
}
}
/**
* @notice Helper function to calculate `(x * index) / EXP_SCALED_ONE`, rounded up.
* @dev Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
*/
function multiply112By128Up(uint112 x, uint128 index) internal pure returns (uint240 z) {
unchecked {
return uint240(((uint256(x) * index) + (EXP_SCALED_ONE - 1)) / EXP_SCALED_ONE);
}
}
/**
* @dev Returns the present amount (rounded down) given the principal amount and an index.
* @param principalAmount The principal amount.
* @param index An index.
* @return The present amount rounded down.
*/
function getPresentAmountRoundedDown(uint112 principalAmount, uint128 index) internal pure returns (uint240) {
return multiply112By128Down(principalAmount, index);
}
/**
* @dev Returns the present amount (rounded up) given the principal amount and an index.
* @param principalAmount The principal amount.
* @param index An index.
* @return The present amount rounded up.
*/
function getPresentAmountRoundedUp(uint112 principalAmount, uint128 index) internal pure returns (uint240) {
return multiply112By128Up(principalAmount, index);
}
/**
* @dev Returns the principal amount given the present amount, using the current index.
* @param presentAmount The present amount.
* @param index An index.
* @return The principal amount rounded down.
*/
function getPrincipalAmountRoundedDown(uint240 presentAmount, uint128 index) internal pure returns (uint112) {
return divide240By128Down(presentAmount, index);
}
/**
* @dev Returns the principal amount given the present amount, using the current index.
* @param presentAmount The present amount.
* @param index An index.
* @return The principal amount rounded up.
*/
function getPrincipalAmountRoundedUp(uint240 presentAmount, uint128 index) internal pure returns (uint112) {
return divide240By128Up(presentAmount, index);
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
interface IBridge {
///////////////////////////////////////////////////////////////////////////
// CUSTOM ERRORS //
///////////////////////////////////////////////////////////////////////////
/// @notice Thrown when `sendMessage` function caller is not the portal.
error NotPortal();
/// @notice Thrown when the portal address is 0x0.
error ZeroPortal();
///////////////////////////////////////////////////////////////////////////
// VIEW/PURE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @notice Returns the address of the portal.
function portal() external view returns (address);
/**
* @notice Returns the fee for sending a message to the remote chain
* @param destinationChainId The EVM chain Id of the destination chain.
* @param gasLimit The gas limit to execute the message on the destination chain.
* @param payload The message payload to send.
* @return fee The fee for sending a message.
*/
function quote(uint256 destinationChainId, uint256 gasLimit, bytes memory payload) external view returns (uint256 fee);
///////////////////////////////////////////////////////////////////////////
// INTERACTIVE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/**
* @notice Sends a message to the remote chain.
* @dev Only EVM chains are supported.
* @param destinationChainId The EVM chain Id of the destination chain.
* @param gasLimit The gas limit to execute the message on the destination chain.
* @param refundAddress The address to refund the fee to.
* @param payload The message payload to send.
* @return messageId The unique identifier of the message sent.
*/
function sendMessage(
uint256 destinationChainId,
uint256 gasLimit,
address refundAddress,
bytes memory payload
) external payable returns (bytes32 messageId);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
/**
* @title Subset of SwapFacility interface.
* @author M0 Labs
*/
interface ISwapFacilityLike {
/**
* @notice Swaps $M token to $M Extension.
* @param extensionOut The address of the M Extension to swap to.
* @param amount The amount of $M token to swap.
* @param recipient The address to receive the swapped $M Extension tokens.
*/
function swapInM(address extensionOut, uint256 amount, address recipient) external;
/**
* @notice Swaps $M Extension to $M token.
* @param extensionIn The address of the $M Extension to swap from.
* @param amount The amount of $M Extension tokens to swap.
* @param recipient The address to receive $M tokens.
*/
function swapOutM(address extensionIn, uint256 amount, address recipient) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
import { OwnableUpgradeable } from "../../lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
import { PausableUpgradeable } from "../../lib/openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol";
import { IPausableOwnable } from "../interfaces/IPausableOwnable.sol";
abstract contract PausableOwnableUpgradeable is OwnableUpgradeable, PausableUpgradeable, IPausableOwnable {
/// @custom:storage-location erc7201:m0.storage.PausableOwnable
struct PausableOwnableStorage {
address _pauser;
}
/// @dev keccak256(abi.encode(uint256(keccak256("m0.storage.PausableOwnable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant _PAUSER_SLOT = 0x9ab2df69adadda616016eab34dbdcdbe8b11549e0ceb446652474b2cb1ced800;
/// @dev Modifier to allow only the pauser and the owner to access pausing functionality
modifier onlyOwnerOrPauser() {
if (pauser() != _msgSender() && owner() != _msgSender()) revert Unauthorized(_msgSender());
_;
}
///////////////////////////////////////////////////////////////////////////
// EXTERNAL VIEW FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @dev Returns the address of the current pauser.
function pauser() public view virtual returns (address) {
PausableOwnableStorage storage $ = _getPausableOwnableStorage();
return $._pauser;
}
///////////////////////////////////////////////////////////////////////////
// EXTERNAL INTERACTIVE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @inheritdoc IPausableOwnable
function transferPauserRole(address newPauser_) external onlyOwner {
if (newPauser_ == address(0)) revert ZeroPauser();
_transferPauserRole(newPauser_);
}
/// @inheritdoc IPausableOwnable
function pause() external onlyOwnerOrPauser {
_pause();
}
/// @inheritdoc IPausableOwnable
function unpause() external onlyOwnerOrPauser {
_unpause();
}
///////////////////////////////////////////////////////////////////////////
// PRIVATE PURE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
function _getPausableOwnableStorage() private pure returns (PausableOwnableStorage storage $) {
assembly {
$.slot := _PAUSER_SLOT
}
}
///////////////////////////////////////////////////////////////////////////
// INITIALIZERS //
///////////////////////////////////////////////////////////////////////////
/**
* @dev Initializes itself and the parent contracts.
* @param initialOwner_ The address of initial owner.
* @param initialPauser_ The address of initial pauser.
*/
function __PausableOwnable_init(address initialOwner_, address initialPauser_) internal onlyInitializing {
__Ownable_init_unchained(initialOwner_);
__Pausable_init_unchained();
__PausableOwnable_init_unchained(initialPauser_);
}
/**
* @dev Initializes the contract.
* @param initialPauser_ The address of initial pauser.
*/
function __PausableOwnable_init_unchained(address initialPauser_) internal onlyInitializing {
if (initialPauser_ == address(0)) revert ZeroPauser();
_transferPauserRole(initialPauser_);
}
///////////////////////////////////////////////////////////////////////////
// INTERNAL INTERACTIVE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
function _transferPauserRole(address newPauser_) internal {
PausableOwnableStorage storage $ = _getPausableOwnableStorage();
address previousPauser_ = $._pauser;
$._pauser = newPauser_;
emit PauserTransferred(previousPauser_, newPauser_);
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
library TypeConverter {
function toBytes32(address address_) internal pure returns (bytes32) {
return bytes32(uint256(uint160(address_)));
}
function toAddress(bytes32 addressBytes32_) internal pure returns (address) {
return address(uint160(uint256(addressBytes32_)));
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
library SafeCall {
function safeCall(address target, bytes memory data) internal returns (bool success) {
if (target.code.length > 0) {
(success,) = target.call(data);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import { Locker } from "./Locker.sol";
/**
* @author Uniswap Labs.
* Copied from https://github.com/Uniswap/v4-periphery/blob/main/src/base/ReentrancyLock.sol.
* @dev Use Uniswap version of the contract when Linea supports transient storage.
*/
contract ReentrancyLock {
error ContractLocked();
modifier isNotLocked() {
if (Locker.get() != address(0)) revert ContractLocked();
Locker.set(msg.sender);
_;
Locker.set(address(0));
}
function _getLocker() internal view returns (address) {
return Locker.get();
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
/**
* @title BytesParser
* @author Wormhole Labs
* @notice Parses tightly packed data.
* @dev Modified from
* https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/libraries/BytesParsing.sol
*/
library BytesParser {
error LengthMismatch(uint256 encodedLength, uint256 expectedLength);
error InvalidBool(uint8 value);
function checkLength(bytes memory encoded_, uint256 expected_) internal pure {
if (encoded_.length != expected_) revert LengthMismatch(encoded_.length, expected_);
}
function asUint8Unchecked(bytes memory encoded_, uint256 offset_) internal pure returns (uint8 value_, uint256 nextOffset_) {
assembly ("memory-safe") {
nextOffset_ := add(offset_, 1)
value_ := mload(add(encoded_, nextOffset_))
}
}
function asBoolUnchecked(bytes memory encoded_, uint256 offset_) internal pure returns (bool value_, uint256 nextOffset_) {
uint8 uint8Value_;
(uint8Value_, nextOffset_) = asUint8Unchecked(encoded_, offset_);
if (uint8Value_ & 0xfe != 0) revert InvalidBool(uint8Value_);
uint256 cleanedValue_ = uint256(uint8Value_);
// skip 2x iszero opcode
assembly ("memory-safe") {
value_ := cleanedValue_
}
}
function asUint256Unchecked(
bytes memory encoded_,
uint256 offset_
) internal pure returns (uint256 value_, uint256 nextOffset_) {
assembly ("memory-safe") {
nextOffset_ := add(offset_, 32)
value_ := mload(add(encoded_, nextOffset_))
}
}
function asBytes32Unchecked(
bytes memory encoded_,
uint256 offset_
) internal pure returns (bytes32 value_, uint256 nextOffset_) {
uint256 uint256Value_;
(uint256Value_, nextOffset_) = asUint256Unchecked(encoded_, offset_);
value_ = bytes32(uint256Value_);
}
function asUint128Unchecked(
bytes memory encoded_,
uint256 offset_
) internal pure returns (uint128 value_, uint256 nextOffset_) {
assembly ("memory-safe") {
nextOffset_ := add(offset_, 16)
value_ := mload(add(encoded_, nextOffset_))
}
}
function asAddressUnchecked(
bytes memory encoded_,
uint256 offset_
) internal pure returns (address value_, uint256 nextOffset_) {
assembly ("memory-safe") {
nextOffset_ := add(offset_, 20)
value_ := mload(add(encoded_, nextOffset_))
}
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.20 <0.9.0;
/**
* @title Interface for exposing the ability to migrate a contract, extending the ERC-1967 interface.
* @author M^0 Labs
*/
interface IMigratable {
/* ============ Events ============ */
/**
* @notice Emitted when a migration to a new implementation is performed.
* @param migrator The address that performed the migration.
* @param oldImplementation The address of the old implementation.
* @param newImplementation The address of the new implementation.
*/
event Migrated(address indexed migrator, address indexed oldImplementation, address indexed newImplementation);
/**
* @notice Emitted when the implementation address for the proxy is changed.
* @param implementation The address of the new implementation for the proxy.
*/
event Upgraded(address indexed implementation);
/// @notice Emitted when calling `stopEarning` for an account approved as earner by the Registrar.
error InvalidMigrator();
/// @notice Emitted when the delegatecall to a migrator fails.
error MigrationFailed();
/// @notice Emitted when the zero address is passed as a migrator.
error ZeroMigrator();
/* ============ Interactive Functions ============ */
/// @notice Performs an arbitrarily defined migration.
function migrate() external;
/* ============ View/Pure Functions ============ */
/// @notice Returns the address of the current implementation contract.
function implementation() external view returns (address);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.20 <0.9.0;
/**
* @title Library to perform safe math operations on uint types
* @author M^0 Labs
*/
library UIntMath {
/* ============ Custom Errors ============ */
/// @notice Emitted when a passed value is greater than the maximum value of uint16.
error InvalidUInt16();
/// @notice Emitted when a passed value is greater than the maximum value of uint40.
error InvalidUInt40();
/// @notice Emitted when a passed value is greater than the maximum value of uint48.
error InvalidUInt48();
/// @notice Emitted when a passed value is greater than the maximum value of uint112.
error InvalidUInt112();
/// @notice Emitted when a passed value is greater than the maximum value of uint128.
error InvalidUInt128();
/// @notice Emitted when a passed value is greater than the maximum value of uint240.
error InvalidUInt240();
/* ============ Internal View/Pure Functions ============ */
/**
* @notice Casts a uint256 value to a uint16, ensuring that it is less than or equal to the maximum uint16 value.
* @param n The value to cast.
* @return The value casted to uint16.
*/
function safe16(uint256 n) internal pure returns (uint16) {
if (n > type(uint16).max) revert InvalidUInt16();
return uint16(n);
}
/**
* @notice Casts a uint256 value to a uint40, ensuring that it is less than or equal to the maximum uint40 value.
* @param n The value to cast.
* @return The value casted to uint40.
*/
function safe40(uint256 n) internal pure returns (uint40) {
if (n > type(uint40).max) revert InvalidUInt40();
return uint40(n);
}
/**
* @notice Casts a uint256 value to a uint48, ensuring that it is less than or equal to the maximum uint48 value.
* @param n The value to cast.
* @return The value casted to uint48.
*/
function safe48(uint256 n) internal pure returns (uint48) {
if (n > type(uint48).max) revert InvalidUInt48();
return uint48(n);
}
/**
* @notice Casts a uint256 value to a uint112, ensuring that it is less than or equal to the maximum uint112 value.
* @param n The value to cast.
* @return The value casted to uint112.
*/
function safe112(uint256 n) internal pure returns (uint112) {
if (n > type(uint112).max) revert InvalidUInt112();
return uint112(n);
}
/**
* @notice Casts a uint256 value to a uint128, ensuring that it is less than or equal to the maximum uint128 value.
* @param n The value to cast.
* @return The value casted to uint128.
*/
function safe128(uint256 n) internal pure returns (uint128) {
if (n > type(uint128).max) revert InvalidUInt128();
return uint128(n);
}
/**
* @notice Casts a uint256 value to a uint240, ensuring that it is less than or equal to the maximum uint240 value.
* @param n The value to cast.
* @return The value casted to uint240.
*/
function safe240(uint256 n) internal pure returns (uint240) {
if (n > type(uint240).max) revert InvalidUInt240();
return uint240(n);
}
/**
* @notice Limits a uint256 value to the maximum uint32 value.
* @param n The value to bound.
* @return The value limited to within uint32 bounds.
*/
function bound32(uint256 n) internal pure returns (uint32) {
return uint32(min256(n, uint256(type(uint32).max)));
}
/**
* @notice Limits a uint256 value to the maximum uint112 value.
* @param n The value to bound.
* @return The value limited to within uint112 bounds.
*/
function bound112(uint256 n) internal pure returns (uint112) {
return uint112(min256(n, uint256(type(uint112).max)));
}
/**
* @notice Limits a uint256 value to the maximum uint128 value.
* @param n The value to bound.
* @return The value limited to within uint128 bounds.
*/
function bound128(uint256 n) internal pure returns (uint128) {
return uint128(min256(n, uint256(type(uint128).max)));
}
/**
* @notice Limits a uint256 value to the maximum uint240 value.
* @param n The value to bound.
* @return The value limited to within uint240 bounds.
*/
function bound240(uint256 n) internal pure returns (uint240) {
return uint240(min256(n, uint256(type(uint240).max)));
}
/**
* @notice Compares two uint32 values and returns the larger one.
* @param a Value to compare.
* @param b Value to compare.
* @return The larger value.
*/
function max32(uint32 a, uint32 b) internal pure returns (uint32) {
return a > b ? a : b;
}
/**
* @notice Compares two uint40 values and returns the larger one.
* @param a Value to compare.
* @param b Value to compare.
* @return The larger value.
*/
function max40(uint40 a, uint40 b) internal pure returns (uint40) {
return a > b ? a : b;
}
/**
* @notice Compares two uint128 values and returns the larger one.
* @param a Value to compare.
* @param b Value to compare.
* @return The larger value.
*/
function max128(uint128 a, uint128 b) internal pure returns (uint128) {
return a > b ? a : b;
}
/**
* @notice Compares two uint240 values and returns the larger one.
* @param a Value to compare.
* @param b Value to compare.
* @return The larger value.
*/
function max240(uint240 a, uint240 b) internal pure returns (uint240) {
return a > b ? a : b;
}
/**
* @notice Compares two uint32 values and returns the lesser one.
* @param a Value to compare.
* @param b Value to compare.
* @return The lesser value.
*/
function min32(uint32 a, uint32 b) internal pure returns (uint32) {
return a < b ? a : b;
}
/**
* @notice Compares two uint40 values and returns the lesser one.
* @param a Value to compare.
* @param b Value to compare.
* @return The lesser value.
*/
function min40(uint40 a, uint40 b) internal pure returns (uint40) {
return a < b ? a : b;
}
/**
* @notice Compares two uint240 values and returns the lesser one.
* @param a Value to compare.
* @param b Value to compare.
* @return The lesser value.
*/
function min240(uint240 a, uint240 b) internal pure returns (uint240) {
return a < b ? a : b;
}
/**
* @notice Compares two uint112 values and returns the lesser one.
* @param a Value to compare.
* @param b Value to compare.
* @return The lesser value.
*/
function min112(uint112 a, uint112 b) internal pure returns (uint112) {
return a < b ? a : b;
}
/**
* @notice Compares two uint256 values and returns the lesser one.
* @param a Value to compare.
* @param b Value to compare.
* @return The lesser value.
*/
function min256(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PausableStorageLocation
}
}
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev 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();
_;
}
function __Pausable_init() internal onlyInitializing {
}
function __Pausable_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
PausableStorage storage $ = _getPausableStorage();
return $._paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.26;
interface IPausableOwnable {
///////////////////////////////////////////////////////////////////////////
// EVENTS //
///////////////////////////////////////////////////////////////////////////
/**
* @notice Emitted when the pauser role is transferred.
* @param previousPauser The previous pauser.
* @param newPauser The new pauser.
*/
event PauserTransferred(address indexed previousPauser, address indexed newPauser);
///////////////////////////////////////////////////////////////////////////
// CUSTOM ERRORS //
///////////////////////////////////////////////////////////////////////////
/// @notice Thrown when the pauser address is 0x0.
error ZeroPauser();
/**
* @notice Thrown when the caller account is not authorized to perform an operation.
* @param account The caller.
*/
error Unauthorized(address account);
///////////////////////////////////////////////////////////////////////////
// VIEW/PURE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/// @notice Returns the address of the pauser.
function pauser() external view returns (address);
/// @notice Returns `true` if the contract is paused, and `false` otherwise.
//function paused() external view returns (bool);
///////////////////////////////////////////////////////////////////////////
// INTERACTIVE FUNCTIONS //
///////////////////////////////////////////////////////////////////////////
/**
* @notice Transfers the pauser role to new address
* @param newPauser Address of the new pauser
*/
function transferPauserRole(address newPauser) external;
/**
* @notice Triggers the paused state.
* @dev The contract must not be paused.
*/
function pause() external;
/**
* @notice Returns to normal state.
* @dev The contract must be paused.
*/
function unpause() external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
/**
* @author Uniswap Labs.
* Adapted from https://github.com/Uniswap/v4-periphery/blob/main/src/libraries/Locker.sol for Linea deployment.
* @dev Use Uniswap version of the contract when Linea supports transient storage.
*/
library Locker {
// The slot holding the locker state. bytes32(uint256(keccak256("LockedBy")) - 1)
bytes32 constant LOCKED_BY_SLOT = 0x0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a;
function set(address locker) internal {
assembly {
sstore(LOCKED_BY_SLOT, locker)
}
}
function get() internal view returns (address locker) {
assembly {
locker := sload(LOCKED_BY_SLOT)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}{
"remappings": [
"@ensdomains/=lib/uniswap-v4-periphery/lib/v4-core/node_modules/@ensdomains/",
"@openzeppelin/=lib/uniswap-v4-periphery/lib/v4-core/lib/openzeppelin-contracts/",
"@uniswap/v4-core/=lib/uniswap-v4-periphery/lib/v4-core/",
"common/=lib/common/src/",
"ds-test/=lib/safe-utils/lib/solidity-stringutils/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-gas-snapshot/=lib/uniswap-v4-periphery/lib/permit2/lib/forge-gas-snapshot/src/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"hardhat/=lib/uniswap-v4-periphery/lib/v4-core/node_modules/hardhat/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin/",
"permit2/=lib/uniswap-v4-periphery/lib/permit2/",
"protocol/=lib/protocol/",
"safe-smart-account/=lib/safe-utils/lib/safe-smart-account/",
"safe-utils/=lib/safe-utils/src/",
"solidity-http/=lib/safe-utils/lib/solidity-http/src/",
"solidity-stringutils/=lib/safe-utils/lib/solidity-stringutils/",
"solmate/=lib/uniswap-v4-periphery/lib/v4-core/lib/solmate/",
"ttg/=lib/ttg/",
"uniswap-v4-periphery/=lib/uniswap-v4-periphery/",
"v4-core/=lib/uniswap-v4-periphery/lib/v4-core/src/",
"wrapped-m-token/=lib/wrapped-m-token/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"mToken_","type":"address"},{"internalType":"address","name":"registrar_","type":"address"},{"internalType":"address","name":"swapFacility_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ContractLocked","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"uint8","name":"value","type":"uint8"}],"name":"InvalidBool","type":"error"},{"inputs":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"}],"name":"InvalidDestinationChain","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidMigrator","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"InvalidPayloadLength","type":"error"},{"inputs":[{"internalType":"uint8","name":"value","type":"uint8"}],"name":"InvalidPayloadType","type":"error"},{"inputs":[{"internalType":"uint256","name":"encodedLength","type":"uint256"},{"internalType":"uint256","name":"expectedLength","type":"uint256"}],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"MigrationFailed","type":"error"},{"inputs":[],"name":"NotBridge","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"address","name":"sourceToken","type":"address"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"address","name":"destinationToken","type":"address"}],"name":"UnsupportedBridgingPath","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroBridge","type":"error"},{"inputs":[],"name":"ZeroDestinationToken","type":"error"},{"inputs":[],"name":"ZeroMToken","type":"error"},{"inputs":[],"name":"ZeroMigrator","type":"error"},{"inputs":[],"name":"ZeroPauser","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroRefundAddress","type":"error"},{"inputs":[],"name":"ZeroRegistrar","type":"error"},{"inputs":[],"name":"ZeroRemoteMToken","type":"error"},{"inputs":[],"name":"ZeroSourceToken","type":"error"},{"inputs":[],"name":"ZeroSwapFacility","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousBridge","type":"address"},{"indexed":true,"internalType":"address","name":"newBridge","type":"address"}],"name":"BridgeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"mToken","type":"address"}],"name":"DestinationMTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"index","type":"uint128"}],"name":"MTokenIndexReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"sourceChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"destinationToken","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"index","type":"uint128"}],"name":"MTokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sourceToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"destinationToken","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"index","type":"uint128"},{"indexed":false,"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MTokenSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"migrator","type":"address"},{"indexed":true,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"newImplementation","type":"address"}],"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":"previousPauser","type":"address"},{"indexed":true,"internalType":"address","name":"newPauser","type":"address"}],"name":"PauserTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":true,"internalType":"enum PayloadType","name":"payloadType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"PayloadGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"value","type":"bytes32"}],"name":"RegistrarKeyReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"listName","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"RegistrarListStatusReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sourceToken","type":"address"},{"indexed":true,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"destinationToken","type":"address"},{"indexed":false,"internalType":"bool","name":"supported","type":"bool"}],"name":"SupportedBridgingPathSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"destinationWrappedToken","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WrapFailed","type":"event"},{"inputs":[],"name":"bridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentIndex","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"}],"name":"destinationMToken","outputs":[{"internalType":"address","name":"mToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"implementation_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bridge_","type":"address"},{"internalType":"address","name":"initialOwner_","type":"address"},{"internalType":"address","name":"initialPauser_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migrator_","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"msgSender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"enum PayloadType","name":"payloadType","type":"uint8"}],"name":"payloadGasLimit","outputs":[{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"destinationChainId_","type":"uint256"},{"internalType":"address","name":"recipient_","type":"address"}],"name":"quoteTransfer","outputs":[{"internalType":"uint256","name":"fee_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sourceChainId_","type":"uint256"},{"internalType":"bytes","name":"payload_","type":"bytes"}],"name":"receiveMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registrar","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newBridge_","type":"address"}],"name":"setBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"destinationChainId_","type":"uint256"},{"internalType":"address","name":"mToken_","type":"address"}],"name":"setDestinationMToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"destinationChainId_","type":"uint256"},{"internalType":"enum PayloadType","name":"payloadType_","type":"uint8"},{"internalType":"uint256","name":"gasLimit_","type":"uint256"}],"name":"setPayloadGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sourceToken_","type":"address"},{"internalType":"uint256","name":"destinationChainId_","type":"uint256"},{"internalType":"address","name":"destinationToken_","type":"address"},{"internalType":"bool","name":"supported_","type":"bool"}],"name":"setSupportedBridgingPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sourceToken","type":"address"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"address","name":"destinationToken","type":"address"}],"name":"supportedBridgingPath","outputs":[{"internalType":"bool","name":"supported","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapFacility","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"destinationChainId_","type":"uint256"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"address","name":"refundAddress_","type":"address"}],"name":"transfer","outputs":[{"internalType":"bytes32","name":"messageId_","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"address","name":"sourceToken_","type":"address"},{"internalType":"uint256","name":"destinationChainId_","type":"uint256"},{"internalType":"address","name":"destinationToken_","type":"address"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"address","name":"refundAddress_","type":"address"}],"name":"transferMLikeToken","outputs":[{"internalType":"bytes32","name":"messageId_","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPauser_","type":"address"}],"name":"transferPauserRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60e060405234801561001057600080fd5b5060405161337b38038061337b83398101604081905261002f91610197565b82828261003a6100c9565b6001600160a01b03831660808190526100665760405163b01d5e2b60e01b815260040160405180910390fd5b6001600160a01b03821660a0819052610092576040516379a6314960e01b815260040160405180910390fd5b6001600160a01b03811660c08190526100be57604051636880ffc960e11b815260040160405180910390fd5b5050505050506101da565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156101195760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146101785780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b80516001600160a01b038116811461019257600080fd5b919050565b6000806000606084860312156101ac57600080fd5b6101b58461017b565b92506101c36020850161017b565b91506101d16040850161017b565b90509250925092565b60805160a05160c0516131026102796000396000818161047901528181611621015281816116e30152818161207a0152818161211e015261228d015260008181610257015281816125460152818161264e01526126bc01526000818161050d015281816107de015281816112e9015281816114cc015281816118b701528181611f5001528181611ff10152818161246501526127d001526131026000f3fe6080604052600436106101c25760003560e01c80638dd14802116100f7578063c0c53b8b11610095578063d737d0c711610064578063d737d0c714610590578063e78cea92146105a5578063e80f94cf146105c5578063f2fde38b146105e557600080fd5b8063c0c53b8b146104db578063c3b6f939146104fb578063ce5494bb1461052f578063d18150611461054f57600080fd5b80639fd0506d116100d15780639fd0506d14610452578063ae06b7e414610467578063b3c2c2141461049b578063bad383a6146104bb57600080fd5b80638dd14802146103e75780638fd3ab80146104075780639ca029921461041c57600080fd5b8063515c494611610164578063715018a61161013e578063715018a6146103705780638456cb59146103855780638b2717181461039a5780638da5cb5b146103d257600080fd5b8063515c4946146102d95780635c60da1b146102f95780635c975abb1461032d57600080fd5b80632b20e397116101a05780632b20e3971461024557806337090dc7146102915780633e2786fc146102a45780633f4ba83a146102c457600080fd5b806304291b56146101c757806308d11ceb146101e957806326987b601461020f575b600080fd5b3480156101d357600080fd5b506101e76101e2366004612ac5565b610605565b005b6101fc6101f7366004612b5f565b61072b565b6040519081526020015b60405180910390f35b34801561021b57600080fd5b50610224610843565b6040516fffffffffffffffffffffffffffffffff9091168152602001610206565b34801561025157600080fd5b506102797f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610206565b6101fc61029f366004612ba5565b610852565b3480156102b057600080fd5b506101fc6102bf366004612c0b565b6109b7565b3480156102d057600080fd5b506101e7610a8c565b3480156102e557600080fd5b506101e76102f4366004612c4f565b610b0b565b34801561030557600080fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54610279565b34801561033957600080fd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff165b6040519015158152602001610206565b34801561037c57600080fd5b506101e7610bae565b34801561039157600080fd5b506101e7610bc0565b3480156103a657600080fd5b506101fc6103b5366004612c85565b600360209081526000928352604080842090915290825290205481565b3480156103de57600080fd5b50610279610c03565b3480156103f357600080fd5b506101e7610402366004612cb1565b610c38565b34801561041357600080fd5b506101e7610ce8565b34801561042857600080fd5b50610279610437366004612ccc565b6002602052600090815260409020546001600160a01b031681565b34801561045e57600080fd5b50610279610cf2565b34801561047357600080fd5b506102797f000000000000000000000000000000000000000000000000000000000000000081565b3480156104a757600080fd5b506101e76104b6366004612cf3565b610d1b565b3480156104c757600080fd5b506101e76104d6366004612cb1565b610e76565b3480156104e757600080fd5b506101e76104f6366004612d42565b610eca565b34801561050757600080fd5b506102797f000000000000000000000000000000000000000000000000000000000000000081565b34801561053b57600080fd5b506101e761054a366004612cb1565b61103a565b34801561055b57600080fd5b5061036061056a366004612d7c565b600160209081526000938452604080852082529284528284209052825290205460ff1681565b34801561059c57600080fd5b5061027961104b565b3480156105b157600080fd5b50600054610279906001600160a01b031681565b3480156105d157600080fd5b506101e76105e0366004612daf565b611055565b3480156105f157600080fd5b506101e7610600366004612cb1565b611155565b6000546001600160a01b03163314610649576040517f7fea9dc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061068a83838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111a992505050565b905060008160038111156106a0576106a0612dd2565b036106eb576106e58484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061125092505050565b50505050565b6106e58184848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061134492505050565b60006107356113ae565b600061075f7f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a5490565b6001600160a01b03161461079f576040517f6f5ffb7e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107c7337f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a55565b6000848152600260205260409020546108109086907f00000000000000000000000000000000000000000000000000000000000000009087906001600160a01b0316878761140a565b905061083b60007f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a55565b949350505050565b600061084d6118b3565b905090565b600061085c6113ae565b60006108867f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a5490565b6001600160a01b0316146108c6576040517f6f5ffb7e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108ee337f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a55565b6001600160a01b03808716600090815260016020908152604080832089845282528083209388168352929052205460ff16610974576040517ff05eff4d0000000000000000000000000000000000000000000000000000000081526001600160a01b03808816600483015260248201879052851660448201526064015b60405180910390fd5b61098287878787878761140a565b90506109ad60007f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a55565b9695505050505050565b6000828152600260205260408120546001600160a01b0316816109e4868333876109df6118b3565b611937565b60008054878252600360209081526040808420848052909152918290205491517fa66f84a90000000000000000000000000000000000000000000000000000000081529293506001600160a01b03169163a66f84a991610a4b918991908690600401612e6f565b602060405180830381865afa158015610a68573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ad9190612e8e565b33610a95610cf2565b6001600160a01b031614158015610abc575033610ab0610c03565b6001600160a01b031614155b15610b0157335b6040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240161096b565b610b0961196f565b565b610b136119ff565b80600360008581526020019081526020016000206000846003811115610b3b57610b3b612dd2565b6003811115610b4c57610b4c612dd2565b8152602081019190915260400160002055816003811115610b6f57610b6f612dd2565b837f1a5992a751b521ef246a1a59ba188f21a01ef4df77a46061eacc5604768157e283604051610ba191815260200190565b60405180910390a3505050565b610bb66119ff565b610b096000611a4a565b33610bc9610cf2565b6001600160a01b031614158015610bf0575033610be4610c03565b6001600160a01b031614155b15610bfb5733610ac3565b610b09611ad3565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b546001600160a01b031692915050565b610c406119ff565b6001600160a01b038116610c80576040517f361106cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917fc0634c245ce7b7b309744c30c030a783629555dc9f0c2c4cb54bdc9d9812d6209190a35050565b610b096000611b4c565b6000807f9ab2df69adadda616016eab34dbdcdbe8b11549e0ceb446652474b2cb1ced800610c28565b610d236119ff565b6001600160a01b038416610d63576040517f2dc2f38200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b468303610d9f576040517f202cb5130000000000000000000000000000000000000000000000000000000081526004810184905260240161096b565b6001600160a01b038216610ddf576040517f7c37399000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03848116600081815260016020908152604080832088845282528083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182528692917fb30eec013773a40f5bfc408b77c3eb479af144a816a0250387480ba905a06f95910160405180910390a450505050565b610e7e6119ff565b6001600160a01b038116610ebe576040517f042d717b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec781611d36565b50565b6000610ed4611dbf565b805490915060ff68010000000000000000820416159067ffffffffffffffff16600081158015610f015750825b905060008267ffffffffffffffff166001148015610f1e5750303b155b905081158015610f2c575080155b15610f63576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610fc45784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b610fcf888888611dea565b83156110305784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6110426119ff565b610ec781611b4c565b600061084d611e6d565b61105d6119ff565b468203611099576040517f202cb5130000000000000000000000000000000000000000000000000000000081526004810183905260240161096b565b6001600160a01b0381166110d9576040517fb01d5e2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526002602090815260409182902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038516908117909155915191825283917fe1f5ca8210e2b8950e4626ed9e65573e6a90daf4c4f5d098ad4b7665a08992cb910160405180910390a25050565b61115d6119ff565b6001600160a01b0381166111a0576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526000600482015260240161096b565b610ec781611a4a565b60006001825110156111ec5781516040517ff61df23200000000000000000000000000000000000000000000000000000000815260040161096b91815260200190565b6001820151600360ff82161115611234576040517f55791e9400000000000000000000000000000000000000000000000000000000815260ff8216600482015260240161096b565b8060ff16600381111561124957611249612dd2565b9392505050565b600080600080600061126186611e97565b94509450945094509450816001600160a01b0316836001600160a01b0316856001600160a01b03167f4dc9c05fa45102b9417bba8bc740e033a518560a8a91b3c3059d6124b381f2d28a89866040516112df9392919092835260208301919091526fffffffffffffffffffffffffffffffff16604082015260600190565b60405180910390a47f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038082169086160361132c5761132788848885611ec6565b611030565b61133888308885611ec6565b6110308186858961204a565b600182600381111561135857611358612dd2565b0361136a576113668161239f565b5050565b600282600381111561137e5761137e612dd2565b0361138c57611366816124c6565b60038260038111156113a0576113a0612dd2565b0361136657611366816125af565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615610b09576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611415876126eb565b61141e82612725565b6001600160a01b03841661145e576040517f7c37399000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03831661149e576040517fd27b444300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611520573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115449190612e8e565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018b90529091506001600160a01b038916906323b872dd906064016020604051808303816000875af11580156115b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d79190612ea7565b50816001600160a01b0316886001600160a01b031614611740576040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018b905289169063095ea7b3906044016020604051808303816000875af1158015611679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169d9190612ea7565b506040517f9e5e91f40000000000000000000000000000000000000000000000000000000081526001600160a01b038981166004830152602482018b90523060448301527f00000000000000000000000000000000000000000000000000000000000000001690639e5e91f490606401600060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b505050505b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009082906001600160a01b038516906370a0823190602401602060405180830381865afa1580156117a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c69190612e8e565b6117d09190612ef3565b9050808a11156117f7576117e2612765565b818b0311156117f7578099506117f78a6126eb565b611801888b6127a1565b600061180b6118b3565b9050600061181c8c8a338b86611937565b905061182b8a60008984612807565b604080518c81526001600160a01b038c811660208301529181018f90526fffffffffffffffffffffffffffffffff85166060820152608081018390529197508d91818b16913391908f16907f4c812797ac478127450f6a846f8ad0ae1ad2f055778469bcccc65d1db7a062039060a00160405180910390a45050505050509695505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166326987b606040518163ffffffff1660e01b8152600401602060405180830381865afa158015611913573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084d9190612f06565b60606000868686868660405160200161195596959493929190612f38565b604051602081830303815290604052905095945050505050565b6119776128cf565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b33611a08610c03565b6001600160a01b031614610b09576040517f118cdaa700000000000000000000000000000000000000000000000000000000815233600482015260240161096b565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080547fffffffffffffffffffffffff000000000000000000000000000000000000000081166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b611adb6113ae565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258336119e1565b6001600160a01b038116611b8c576040517f0d626a3200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611bd0576040517f8d1e7cf400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611bfa7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b90506000826001600160a01b0316604051600060405180830381855af49150503d8060008114611c46576040519150601f19603f3d011682016040523d82523d6000602084013e611c4b565b606091505b5050905080611c86576040517fa27bfda200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611cb07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b9050806001600160a01b0316836001600160a01b0316856001600160a01b03167fe1b831b0e6f3aa16b4b1a6bd526b5cdeab4940744ca6e0251f5fe5f8caf1c81a60405160405180910390a46040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250505050565b7f9ab2df69adadda616016eab34dbdcdbe8b11549e0ceb446652474b2cb1ced80080547fffffffffffffffffffffffff000000000000000000000000000000000000000081166001600160a01b03848116918217845560405192169182907f51c4874e0f23f262e04a38c51751336dde72126d67f53eb672aaff02996b3ef690600090a3505050565b6000807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005b92915050565b611df261292a565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038516908117909155611e5e576040517f361106cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611e688282612968565b505050565b600061084d7f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a5490565b602181015160358201516049830151605d840151606d8086015190611ebc878261298a565b5091939590929450565b611ece6118b3565b6fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff161115611fb2576040517f499d10810000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490526fffffffffffffffffffffffffffffffff831660448301527f0000000000000000000000000000000000000000000000000000000000000000169063499d1081906064015b600060405180830381600087803b158015611f9557600080fd5b505af1158015611fa9573d6000803e3d6000fd5b505050506106e5565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490527f000000000000000000000000000000000000000000000000000000000000000016906340c10f19906044015b600060405180830381600087803b15801561203657600080fd5b505af1158015611030573d6000803e3d6000fd5b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820183905285169063095ea7b3906044016020604051808303816000875af11580156120d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f69190612ea7565b506040516001600160a01b0384811660248301526044820183905283811660648301526000917f000000000000000000000000000000000000000000000000000000000000000090911690608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe274ffb800000000000000000000000000000000000000000000000000000000179052516121c59190612ff3565b6000604051808303816000865af19150503d8060008114612202576040519150601f19603f3d011682016040523d82523d6000602084013e612207565b606091505b505090508061239857826001600160a01b0316846001600160a01b03167f5e484dc77b9161908da1d2f0da5131cdaabac752ae7f0dd633ec8905627b51898460405161225591815260200190565b60405180910390a36040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000602483015286169063095ea7b3906044016020604051808303816000875af11580156122e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123099190612ea7565b506040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526024820184905286169063a9059cbb906044016020604051808303816000875af1158015612372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123969190612ea7565b505b5050505050565b60006123aa826129d1565b6040516fffffffffffffffffffffffffffffffff821681529091507f26eac4431e1be7751a56292f289f392a5dfffd40080f0980ae5305ece0b591f89060200160405180910390a16123fa6118b3565b6fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff161115611366576040517ffc387d5a0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff821660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063fc387d5a906024015b600060405180830381600087803b1580156124b257600080fd5b505af1158015612396573d6000803e3d6000fd5b6000806124d2836129e8565b91509150817f5e43f70ccc1c30e0a7e05c19edac5a078eeb1b68861d07f720d35e9320cc3d098260405161250891815260200190565b60405180910390a26040517f07a0033000000000000000000000000000000000000000000000000000000000815260048101839052602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906307a0033090604401600060405180830381600087803b15801561259257600080fd5b505af11580156125a6573d6000803e3d6000fd5b50505050505050565b60008060006125bd84612a04565b925092509250816001600160a01b0316837fadc61adcfd899e8535ed93fa1cfde40cd26793bfdcc8787bab210378d8de9be083604051612601911515815260200190565b60405180910390a3801561267d576040517fb4d87a12000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0383811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063b4d87a1290604401611f7b565b6040517fd48d8423000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0383811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063d48d84239060440161201c565b80600003610ec7576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116610ec7576040517f66928bea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600064e8d4a510006127756118b3565b61277f919061300f565b61278a906001613076565b6fffffffffffffffffffffffffffffffff16905090565b6040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401612498565b6000805485825260036020819052604083206001600160a01b03909216916360c0c0ba913491899186908a9081111561284257612842612dd2565b600381111561285357612853612dd2565b81526020019081526020016000205487876040518663ffffffff1660e01b8152600401612883949392919061309e565b60206040518083038185885af11580156128a1573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906128c69190612e8e565b95945050505050565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610b09576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612932612a34565b610b09576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61297061292a565b61297982612a53565b612981612a5b565b61136681612a63565b808251146113665781516040517fab8b67c600000000000000000000000000000000000000000000000000000000815260048101919091526024810182905260440161096b565b601181810151906129e2838261298a565b50919050565b6021810151604180830151906129fe848261298a565b50915091565b602181015160358083015190600090612a1d8582612a6b565b9092509050612a2c858261298a565b509193909250565b6000612a3e611dbf565b5468010000000000000000900460ff16919050565b61115d61292a565b610b0961292a565b610e7e61292a565b600181830181015160009183019060fe811615612ab9576040517f63e37c1800000000000000000000000000000000000000000000000000000000815260ff8216600482015260240161096b565b60ff1694909350915050565b600080600060408486031215612ada57600080fd5b83359250602084013567ffffffffffffffff811115612af857600080fd5b8401601f81018613612b0957600080fd5b803567ffffffffffffffff811115612b2057600080fd5b866020828401011115612b3257600080fd5b939660209190910195509293505050565b80356001600160a01b0381168114612b5a57600080fd5b919050565b60008060008060808587031215612b7557600080fd5b8435935060208501359250612b8c60408601612b43565b9150612b9a60608601612b43565b905092959194509250565b60008060008060008060c08789031215612bbe57600080fd5b86359550612bce60208801612b43565b945060408701359350612be360608801612b43565b9250612bf160808801612b43565b9150612bff60a08801612b43565b90509295509295509295565b600080600060608486031215612c2057600080fd5b8335925060208401359150612c3760408501612b43565b90509250925092565b803560048110612b5a57600080fd5b600080600060608486031215612c6457600080fd5b83359250612c7460208501612c40565b929592945050506040919091013590565b60008060408385031215612c9857600080fd5b82359150612ca860208401612c40565b90509250929050565b600060208284031215612cc357600080fd5b61124982612b43565b600060208284031215612cde57600080fd5b5035919050565b8015158114610ec757600080fd5b60008060008060808587031215612d0957600080fd5b612d1285612b43565b935060208501359250612d2760408601612b43565b91506060850135612d3781612ce5565b939692955090935050565b600080600060608486031215612d5757600080fd5b612d6084612b43565b9250612d6e60208501612b43565b9150612c3760408501612b43565b600080600060608486031215612d9157600080fd5b612d9a84612b43565b925060208401359150612c3760408501612b43565b60008060408385031215612dc257600080fd5b82359150612ca860208401612b43565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60005b83811015612e1c578181015183820152602001612e04565b50506000910152565b60008151808452612e3d816020860160208601612e01565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8381528260208201526060604082015260006128c66060830184612e25565b600060208284031215612ea057600080fd5b5051919050565b600060208284031215612eb957600080fd5b815161124981612ce5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115611de457611de4612ec4565b600060208284031215612f1857600080fd5b81516fffffffffffffffffffffffffffffffff8116811461124957600080fd5b600060048810612f71577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b5060f89690961b86526001860194909452606092831b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116602187015291831b8216603586015290911b16604983015260801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016605d820152606d0190565b60008251613005818460208701612e01565b9190910192915050565b60006fffffffffffffffffffffffffffffffff831680613058577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b806fffffffffffffffffffffffffffffffff84160491505092915050565b6fffffffffffffffffffffffffffffffff8181168382160190811115611de457611de4612ec4565b8481528360208201526001600160a01b03831660408201526080606082015260006109ad6080830184612e2556fea2646970667358221220ec128f9cf1bec45afe6a7c1c8315eb30685d98113dfdcdaa462200fb8a039e8264736f6c634300081a0033000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f6278
Deployed Bytecode
0x6080604052600436106101c25760003560e01c80638dd14802116100f7578063c0c53b8b11610095578063d737d0c711610064578063d737d0c714610590578063e78cea92146105a5578063e80f94cf146105c5578063f2fde38b146105e557600080fd5b8063c0c53b8b146104db578063c3b6f939146104fb578063ce5494bb1461052f578063d18150611461054f57600080fd5b80639fd0506d116100d15780639fd0506d14610452578063ae06b7e414610467578063b3c2c2141461049b578063bad383a6146104bb57600080fd5b80638dd14802146103e75780638fd3ab80146104075780639ca029921461041c57600080fd5b8063515c494611610164578063715018a61161013e578063715018a6146103705780638456cb59146103855780638b2717181461039a5780638da5cb5b146103d257600080fd5b8063515c4946146102d95780635c60da1b146102f95780635c975abb1461032d57600080fd5b80632b20e397116101a05780632b20e3971461024557806337090dc7146102915780633e2786fc146102a45780633f4ba83a146102c457600080fd5b806304291b56146101c757806308d11ceb146101e957806326987b601461020f575b600080fd5b3480156101d357600080fd5b506101e76101e2366004612ac5565b610605565b005b6101fc6101f7366004612b5f565b61072b565b6040519081526020015b60405180910390f35b34801561021b57600080fd5b50610224610843565b6040516fffffffffffffffffffffffffffffffff9091168152602001610206565b34801561025157600080fd5b506102797f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c81565b6040516001600160a01b039091168152602001610206565b6101fc61029f366004612ba5565b610852565b3480156102b057600080fd5b506101fc6102bf366004612c0b565b6109b7565b3480156102d057600080fd5b506101e7610a8c565b3480156102e557600080fd5b506101e76102f4366004612c4f565b610b0b565b34801561030557600080fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54610279565b34801561033957600080fd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff165b6040519015158152602001610206565b34801561037c57600080fd5b506101e7610bae565b34801561039157600080fd5b506101e7610bc0565b3480156103a657600080fd5b506101fc6103b5366004612c85565b600360209081526000928352604080842090915290825290205481565b3480156103de57600080fd5b50610279610c03565b3480156103f357600080fd5b506101e7610402366004612cb1565b610c38565b34801561041357600080fd5b506101e7610ce8565b34801561042857600080fd5b50610279610437366004612ccc565b6002602052600090815260409020546001600160a01b031681565b34801561045e57600080fd5b50610279610cf2565b34801561047357600080fd5b506102797f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f627881565b3480156104a757600080fd5b506101e76104b6366004612cf3565b610d1b565b3480156104c757600080fd5b506101e76104d6366004612cb1565b610e76565b3480156104e757600080fd5b506101e76104f6366004612d42565b610eca565b34801561050757600080fd5b506102797f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b81565b34801561053b57600080fd5b506101e761054a366004612cb1565b61103a565b34801561055b57600080fd5b5061036061056a366004612d7c565b600160209081526000938452604080852082529284528284209052825290205460ff1681565b34801561059c57600080fd5b5061027961104b565b3480156105b157600080fd5b50600054610279906001600160a01b031681565b3480156105d157600080fd5b506101e76105e0366004612daf565b611055565b3480156105f157600080fd5b506101e7610600366004612cb1565b611155565b6000546001600160a01b03163314610649576040517f7fea9dc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061068a83838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506111a992505050565b905060008160038111156106a0576106a0612dd2565b036106eb576106e58484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061125092505050565b50505050565b6106e58184848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061134492505050565b60006107356113ae565b600061075f7f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a5490565b6001600160a01b03161461079f576040517f6f5ffb7e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107c7337f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a55565b6000848152600260205260409020546108109086907f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b9087906001600160a01b0316878761140a565b905061083b60007f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a55565b949350505050565b600061084d6118b3565b905090565b600061085c6113ae565b60006108867f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a5490565b6001600160a01b0316146108c6576040517f6f5ffb7e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108ee337f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a55565b6001600160a01b03808716600090815260016020908152604080832089845282528083209388168352929052205460ff16610974576040517ff05eff4d0000000000000000000000000000000000000000000000000000000081526001600160a01b03808816600483015260248201879052851660448201526064015b60405180910390fd5b61098287878787878761140a565b90506109ad60007f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a55565b9695505050505050565b6000828152600260205260408120546001600160a01b0316816109e4868333876109df6118b3565b611937565b60008054878252600360209081526040808420848052909152918290205491517fa66f84a90000000000000000000000000000000000000000000000000000000081529293506001600160a01b03169163a66f84a991610a4b918991908690600401612e6f565b602060405180830381865afa158015610a68573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ad9190612e8e565b33610a95610cf2565b6001600160a01b031614158015610abc575033610ab0610c03565b6001600160a01b031614155b15610b0157335b6040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015260240161096b565b610b0961196f565b565b610b136119ff565b80600360008581526020019081526020016000206000846003811115610b3b57610b3b612dd2565b6003811115610b4c57610b4c612dd2565b8152602081019190915260400160002055816003811115610b6f57610b6f612dd2565b837f1a5992a751b521ef246a1a59ba188f21a01ef4df77a46061eacc5604768157e283604051610ba191815260200190565b60405180910390a3505050565b610bb66119ff565b610b096000611a4a565b33610bc9610cf2565b6001600160a01b031614158015610bf0575033610be4610c03565b6001600160a01b031614155b15610bfb5733610ac3565b610b09611ad3565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b546001600160a01b031692915050565b610c406119ff565b6001600160a01b038116610c80576040517f361106cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917fc0634c245ce7b7b309744c30c030a783629555dc9f0c2c4cb54bdc9d9812d6209190a35050565b610b096000611b4c565b6000807f9ab2df69adadda616016eab34dbdcdbe8b11549e0ceb446652474b2cb1ced800610c28565b610d236119ff565b6001600160a01b038416610d63576040517f2dc2f38200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b468303610d9f576040517f202cb5130000000000000000000000000000000000000000000000000000000081526004810184905260240161096b565b6001600160a01b038216610ddf576040517f7c37399000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03848116600081815260016020908152604080832088845282528083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182528692917fb30eec013773a40f5bfc408b77c3eb479af144a816a0250387480ba905a06f95910160405180910390a450505050565b610e7e6119ff565b6001600160a01b038116610ebe576040517f042d717b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec781611d36565b50565b6000610ed4611dbf565b805490915060ff68010000000000000000820416159067ffffffffffffffff16600081158015610f015750825b905060008267ffffffffffffffff166001148015610f1e5750303b155b905081158015610f2c575080155b15610f63576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610fc45784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b610fcf888888611dea565b83156110305784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6110426119ff565b610ec781611b4c565b600061084d611e6d565b61105d6119ff565b468203611099576040517f202cb5130000000000000000000000000000000000000000000000000000000081526004810183905260240161096b565b6001600160a01b0381166110d9576040517fb01d5e2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526002602090815260409182902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038516908117909155915191825283917fe1f5ca8210e2b8950e4626ed9e65573e6a90daf4c4f5d098ad4b7665a08992cb910160405180910390a25050565b61115d6119ff565b6001600160a01b0381166111a0576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526000600482015260240161096b565b610ec781611a4a565b60006001825110156111ec5781516040517ff61df23200000000000000000000000000000000000000000000000000000000815260040161096b91815260200190565b6001820151600360ff82161115611234576040517f55791e9400000000000000000000000000000000000000000000000000000000815260ff8216600482015260240161096b565b8060ff16600381111561124957611249612dd2565b9392505050565b600080600080600061126186611e97565b94509450945094509450816001600160a01b0316836001600160a01b0316856001600160a01b03167f4dc9c05fa45102b9417bba8bc740e033a518560a8a91b3c3059d6124b381f2d28a89866040516112df9392919092835260208301919091526fffffffffffffffffffffffffffffffff16604082015260600190565b60405180910390a47f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b038082169086160361132c5761132788848885611ec6565b611030565b61133888308885611ec6565b6110308186858961204a565b600182600381111561135857611358612dd2565b0361136a576113668161239f565b5050565b600282600381111561137e5761137e612dd2565b0361138c57611366816124c6565b60038260038111156113a0576113a0612dd2565b0361136657611366816125af565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615610b09576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611415876126eb565b61141e82612725565b6001600160a01b03841661145e576040517f7c37399000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03831661149e576040517fd27b444300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611520573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115449190612e8e565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018b90529091506001600160a01b038916906323b872dd906064016020604051808303816000875af11580156115b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d79190612ea7565b50816001600160a01b0316886001600160a01b031614611740576040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f627881166004830152602482018b905289169063095ea7b3906044016020604051808303816000875af1158015611679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169d9190612ea7565b506040517f9e5e91f40000000000000000000000000000000000000000000000000000000081526001600160a01b038981166004830152602482018b90523060448301527f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f62781690639e5e91f490606401600060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b505050505b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009082906001600160a01b038516906370a0823190602401602060405180830381865afa1580156117a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c69190612e8e565b6117d09190612ef3565b9050808a11156117f7576117e2612765565b818b0311156117f7578099506117f78a6126eb565b611801888b6127a1565b600061180b6118b3565b9050600061181c8c8a338b86611937565b905061182b8a60008984612807565b604080518c81526001600160a01b038c811660208301529181018f90526fffffffffffffffffffffffffffffffff85166060820152608081018390529197508d91818b16913391908f16907f4c812797ac478127450f6a846f8ad0ae1ad2f055778469bcccc65d1db7a062039060a00160405180910390a45050505050509695505050505050565b60007f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b03166326987b606040518163ffffffff1660e01b8152600401602060405180830381865afa158015611913573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084d9190612f06565b60606000868686868660405160200161195596959493929190612f38565b604051602081830303815290604052905095945050505050565b6119776128cf565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b33611a08610c03565b6001600160a01b031614610b09576040517f118cdaa700000000000000000000000000000000000000000000000000000000815233600482015260240161096b565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080547fffffffffffffffffffffffff000000000000000000000000000000000000000081166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b611adb6113ae565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258336119e1565b6001600160a01b038116611b8c576040517f0d626a3200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611bd0576040517f8d1e7cf400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611bfa7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b90506000826001600160a01b0316604051600060405180830381855af49150503d8060008114611c46576040519150601f19603f3d011682016040523d82523d6000602084013e611c4b565b606091505b5050905080611c86576040517fa27bfda200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611cb07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b9050806001600160a01b0316836001600160a01b0316856001600160a01b03167fe1b831b0e6f3aa16b4b1a6bd526b5cdeab4940744ca6e0251f5fe5f8caf1c81a60405160405180910390a46040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250505050565b7f9ab2df69adadda616016eab34dbdcdbe8b11549e0ceb446652474b2cb1ced80080547fffffffffffffffffffffffff000000000000000000000000000000000000000081166001600160a01b03848116918217845560405192169182907f51c4874e0f23f262e04a38c51751336dde72126d67f53eb672aaff02996b3ef690600090a3505050565b6000807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005b92915050565b611df261292a565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038516908117909155611e5e576040517f361106cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611e688282612968565b505050565b600061084d7f0aedd6bde10e3aa2adec092b02a3e3e805795516cda41f27aa145b8f300af87a5490565b602181015160358201516049830151605d840151606d8086015190611ebc878261298a565b5091939590929450565b611ece6118b3565b6fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff161115611fb2576040517f499d10810000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490526fffffffffffffffffffffffffffffffff831660448301527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b169063499d1081906064015b600060405180830381600087803b158015611f9557600080fd5b505af1158015611fa9573d6000803e3d6000fd5b505050506106e5565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b16906340c10f19906044015b600060405180830381600087803b15801561203657600080fd5b505af1158015611030573d6000803e3d6000fd5b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f6278811660048301526024820183905285169063095ea7b3906044016020604051808303816000875af11580156120d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f69190612ea7565b506040516001600160a01b0384811660248301526044820183905283811660648301526000917f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f627890911690608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe274ffb800000000000000000000000000000000000000000000000000000000179052516121c59190612ff3565b6000604051808303816000865af19150503d8060008114612202576040519150601f19603f3d011682016040523d82523d6000602084013e612207565b606091505b505090508061239857826001600160a01b0316846001600160a01b03167f5e484dc77b9161908da1d2f0da5131cdaabac752ae7f0dd633ec8905627b51898460405161225591815260200190565b60405180910390a36040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f6278811660048301526000602483015286169063095ea7b3906044016020604051808303816000875af11580156122e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123099190612ea7565b506040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526024820184905286169063a9059cbb906044016020604051808303816000875af1158015612372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123969190612ea7565b505b5050505050565b60006123aa826129d1565b6040516fffffffffffffffffffffffffffffffff821681529091507f26eac4431e1be7751a56292f289f392a5dfffd40080f0980ae5305ece0b591f89060200160405180910390a16123fa6118b3565b6fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff161115611366576040517ffc387d5a0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff821660048201527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b03169063fc387d5a906024015b600060405180830381600087803b1580156124b257600080fd5b505af1158015612396573d6000803e3d6000fd5b6000806124d2836129e8565b91509150817f5e43f70ccc1c30e0a7e05c19edac5a078eeb1b68861d07f720d35e9320cc3d098260405161250891815260200190565b60405180910390a26040517f07a0033000000000000000000000000000000000000000000000000000000000815260048101839052602481018290527f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c6001600160a01b0316906307a0033090604401600060405180830381600087803b15801561259257600080fd5b505af11580156125a6573d6000803e3d6000fd5b50505050505050565b60008060006125bd84612a04565b925092509250816001600160a01b0316837fadc61adcfd899e8535ed93fa1cfde40cd26793bfdcc8787bab210378d8de9be083604051612601911515815260200190565b60405180910390a3801561267d576040517fb4d87a12000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0383811660248301527f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c169063b4d87a1290604401611f7b565b6040517fd48d8423000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0383811660248301527f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c169063d48d84239060440161201c565b80600003610ec7576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116610ec7576040517f66928bea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600064e8d4a510006127756118b3565b61277f919061300f565b61278a906001613076565b6fffffffffffffffffffffffffffffffff16905090565b6040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b0316906342966c6890602401612498565b6000805485825260036020819052604083206001600160a01b03909216916360c0c0ba913491899186908a9081111561284257612842612dd2565b600381111561285357612853612dd2565b81526020019081526020016000205487876040518663ffffffff1660e01b8152600401612883949392919061309e565b60206040518083038185885af11580156128a1573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906128c69190612e8e565b95945050505050565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610b09576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612932612a34565b610b09576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61297061292a565b61297982612a53565b612981612a5b565b61136681612a63565b808251146113665781516040517fab8b67c600000000000000000000000000000000000000000000000000000000815260048101919091526024810182905260440161096b565b601181810151906129e2838261298a565b50919050565b6021810151604180830151906129fe848261298a565b50915091565b602181015160358083015190600090612a1d8582612a6b565b9092509050612a2c858261298a565b509193909250565b6000612a3e611dbf565b5468010000000000000000900460ff16919050565b61115d61292a565b610b0961292a565b610e7e61292a565b600181830181015160009183019060fe811615612ab9576040517f63e37c1800000000000000000000000000000000000000000000000000000000815260ff8216600482015260240161096b565b60ff1694909350915050565b600080600060408486031215612ada57600080fd5b83359250602084013567ffffffffffffffff811115612af857600080fd5b8401601f81018613612b0957600080fd5b803567ffffffffffffffff811115612b2057600080fd5b866020828401011115612b3257600080fd5b939660209190910195509293505050565b80356001600160a01b0381168114612b5a57600080fd5b919050565b60008060008060808587031215612b7557600080fd5b8435935060208501359250612b8c60408601612b43565b9150612b9a60608601612b43565b905092959194509250565b60008060008060008060c08789031215612bbe57600080fd5b86359550612bce60208801612b43565b945060408701359350612be360608801612b43565b9250612bf160808801612b43565b9150612bff60a08801612b43565b90509295509295509295565b600080600060608486031215612c2057600080fd5b8335925060208401359150612c3760408501612b43565b90509250925092565b803560048110612b5a57600080fd5b600080600060608486031215612c6457600080fd5b83359250612c7460208501612c40565b929592945050506040919091013590565b60008060408385031215612c9857600080fd5b82359150612ca860208401612c40565b90509250929050565b600060208284031215612cc357600080fd5b61124982612b43565b600060208284031215612cde57600080fd5b5035919050565b8015158114610ec757600080fd5b60008060008060808587031215612d0957600080fd5b612d1285612b43565b935060208501359250612d2760408601612b43565b91506060850135612d3781612ce5565b939692955090935050565b600080600060608486031215612d5757600080fd5b612d6084612b43565b9250612d6e60208501612b43565b9150612c3760408501612b43565b600080600060608486031215612d9157600080fd5b612d9a84612b43565b925060208401359150612c3760408501612b43565b60008060408385031215612dc257600080fd5b82359150612ca860208401612b43565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60005b83811015612e1c578181015183820152602001612e04565b50506000910152565b60008151808452612e3d816020860160208601612e01565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8381528260208201526060604082015260006128c66060830184612e25565b600060208284031215612ea057600080fd5b5051919050565b600060208284031215612eb957600080fd5b815161124981612ce5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115611de457611de4612ec4565b600060208284031215612f1857600080fd5b81516fffffffffffffffffffffffffffffffff8116811461124957600080fd5b600060048810612f71577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b5060f89690961b86526001860194909452606092831b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116602187015291831b8216603586015290911b16604983015260801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016605d820152606d0190565b60008251613005818460208701612e01565b9190910192915050565b60006fffffffffffffffffffffffffffffffff831680613058577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b806fffffffffffffffffffffffffffffffff84160491505092915050565b6fffffffffffffffffffffffffffffffff8181168382160190811115611de457611de4612ec4565b8481528360208201526001600160a01b03831660408201526080606082015260006109ad6080830184612e2556fea2646970667358221220ec128f9cf1bec45afe6a7c1c8315eb30685d98113dfdcdaa462200fb8a039e8264736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f6278
-----Decoded View---------------
Arg [0] : mToken_ (address): 0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b
Arg [1] : registrar_ (address): 0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c
Arg [2] : swapFacility_ (address): 0xB6807116b3B1B321a390594e31ECD6e0076f6278
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b
Arg [1] : 000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c
Arg [2] : 000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f6278
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.