Latest 25 from a total of 9,581 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Direct Release | 4983732 | 14 hrs ago | IN | 0 M | 0.11623227 | ||||
| Direct Release | 4980925 | 19 hrs ago | IN | 0 M | 0.11623227 | ||||
| Direct Execute S... | 4980815 | 19 hrs ago | IN | 2,570 M | 0.09443074 | ||||
| Direct Execute S... | 4978993 | 23 hrs ago | IN | 1,750 M | 0.09441271 | ||||
| Direct Execute S... | 4976610 | 28 hrs ago | IN | 2,089 M | 0.09443074 | ||||
| Direct Release | 4976373 | 28 hrs ago | IN | 0 M | 0.11623227 | ||||
| Direct Release | 4975620 | 30 hrs ago | IN | 0 M | 0.11625029 | ||||
| Direct Release | 4971524 | 38 hrs ago | IN | 0 M | 0.11621424 | ||||
| Direct Execute S... | 4969037 | 42 hrs ago | IN | 2,098 M | 0.09445588 | ||||
| Direct Execute S... | 4966533 | 47 hrs ago | IN | 3.7 M | 0.09419793 | ||||
| Direct Execute S... | 4952244 | 3 days ago | IN | 3.7 M | 0.0941799 | ||||
| Direct Execute S... | 4937517 | 4 days ago | IN | 415.5 M | 0.09443785 | ||||
| Direct Release | 4929246 | 5 days ago | IN | 0 M | 0.11623227 | ||||
| Direct Release | 4919451 | 5 days ago | IN | 0 M | 0.11625029 | ||||
| Direct Release | 4913663 | 6 days ago | IN | 0 M | 0.11625029 | ||||
| Direct Execute S... | 4906147 | 6 days ago | IN | 24 M | 0.09419793 | ||||
| Direct Release | 4893023 | 7 days ago | IN | 0 M | 0.11621424 | ||||
| Direct Release | 4892825 | 7 days ago | IN | 0 M | 0.11625029 | ||||
| Direct Release | 4891583 | 8 days ago | IN | 0 M | 0.11623227 | ||||
| Direct Release | 4888781 | 8 days ago | IN | 0 M | 0.11621424 | ||||
| Direct Execute S... | 4881545 | 8 days ago | IN | 25,900 M | 0.09423397 | ||||
| Direct Release | 4877613 | 9 days ago | IN | 0 M | 0.11601748 | ||||
| Direct Release | 4877606 | 9 days ago | IN | 0 M | 0.1160355 | ||||
| Direct Release | 4877590 | 9 days ago | IN | 0 M | 0.1160355 | ||||
| Direct Execute S... | 4875361 | 9 days ago | IN | 2,197 M | 0.09443785 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 4983732 | 14 hrs ago | 5,892.434709 M | ||||
| 4980925 | 19 hrs ago | 2,564.86257 M | ||||
| 4976373 | 28 hrs ago | 4,794.556444 M | ||||
| 4975620 | 30 hrs ago | 4,593.417439 M | ||||
| 4971524 | 38 hrs ago | 2,995.284984 M | ||||
| 4929246 | 5 days ago | 792.266774 M | ||||
| 4919451 | 5 days ago | 8,900.389498 M | ||||
| 4913663 | 6 days ago | 4,798.224015 M | ||||
| 4893023 | 7 days ago | 2,995.29612 M | ||||
| 4892825 | 7 days ago | 4,494.461361 M | ||||
| 4891583 | 8 days ago | 3,495.672447 M | ||||
| 4888781 | 8 days ago | 2,895.18211 M | ||||
| 4877613 | 9 days ago | 39,960 M | ||||
| 4877606 | 9 days ago | 29,970 M | ||||
| 4877590 | 9 days ago | 29,970 M | ||||
| 4870831 | 9 days ago | 2,895.732828 M | ||||
| 4864734 | 10 days ago | 2,201.387556 M | ||||
| 4864732 | 10 days ago | 2,499.0984 M | ||||
| 4864689 | 10 days ago | 841.999074 M | ||||
| 4864432 | 10 days ago | 361.46439 M | ||||
| 4863017 | 10 days ago | 4,596.399 M | ||||
| 4862280 | 10 days ago | 5,894.349687 M | ||||
| 4861856 | 10 days ago | 3,596.329663 M | ||||
| 4848568 | 11 days ago | 5,892.885038 M | ||||
| 4844582 | 11 days ago | 5,693.619207 M |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ProxyToMeson
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 100 runs
Other Settings:
istanbul EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "./UpgradableMeson.sol";
contract ProxyToMeson is ERC1967Proxy {
bytes4 private constant INITIALIZE_SELECTOR = bytes4(keccak256("initialize(address,address)"));
constructor(address premiumManager) ERC1967Proxy(_deployImpl(), _encodeData(msg.sender, premiumManager)) {}
function _deployImpl() private returns (address) {
UpgradableMeson _impl = new UpgradableMeson();
return address(_impl);
}
function _encodeData(address owner, address premiumManager) private pure returns (bytes memory) {
return abi.encodeWithSelector(INITIALIZE_SELECTOR, owner, premiumManager);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822ProxiableUpgradeable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeaconUpgradeable {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967UpgradeUpgradeable is Initializable {
function __ERC1967Upgrade_init() internal onlyInitializing {
}
function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
}
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
_functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
_functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
}
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so 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.
*
* 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.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate that the this implementation remains valid after an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeTo(address newImplementation) external virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlotUpgradeable {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)
pragma solidity ^0.8.0;
import "../Proxy.sol";
import "./ERC1967Upgrade.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializing the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) payable {
_upgradeToAndCall(_logic, _data, false);
}
/**
* @dev Returns the current implementation address.
*/
function _implementation() internal view virtual override returns (address impl) {
return ERC1967Upgrade._getImplementation();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overridden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
/// @title Interface for depositWithBeneficiary
interface IDepositWithBeneficiary {
/// @notice Make a token transfer that the *signer* is paying tokens but benefits are given to the *beneficiary*
/// @param token The contract address of the transferring token
/// @param amount The amount of the transfer
/// @param beneficiary The address that will receive benefits of this transfer
/// @param data Extra data passed to the contract
/// @return Returns true for a successful transfer.
function depositWithBeneficiary(address token, uint256 amount, address beneficiary, uint64 data)
payable external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
/// @title Minimal ERC20 interface for Uniswap
/// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3
interface IERC20Minimal {
/// @notice Returns the balance of a token
/// @param account The account for which to look up the number of tokens it has, i.e. its balance
/// @return The number of tokens held by the account
function balanceOf(address account) external view returns (uint256);
/// @notice Transfers the amount of token from the `msg.sender` to the recipient
/// @param recipient The account that will receive the amount transferred
/// @param amount The number of tokens to send from the sender to the recipient
/// @return Returns true for a successful transfer, false for an unsuccessful transfer
function transfer(address recipient, uint256 amount) external returns (bool);
/// @notice Returns the current allowance given to a spender by an owner
/// @param owner The account of the token owner
/// @param spender The account of the token spender
/// @return The current allowance granted by `owner` to `spender`
function allowance(address owner, address spender) external view returns (uint256);
/// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount`
/// @param spender The account which will be allowed to spend a given amount of the owners tokens
/// @param amount The amount of tokens allowed to be used by `spender`
/// @return Returns true for a successful approval, false for unsuccessful
function approve(address spender, uint256 amount) external returns (bool);
/// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender`
/// @param sender The account from which the transfer will be initiated
/// @param recipient The recipient of the transfer
/// @param amount The amount of the transfer
/// @return Returns true for a successful transfer, false for unsuccessful
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`.
/// @param from The account from which the tokens were sent, i.e. the balance decreased
/// @param to The account to which the tokens were sent, i.e. the balance increased
/// @param value The amount of tokens that were transferred
event Transfer(address indexed from, address indexed to, uint256 value);
/// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes.
/// @param owner The account that approved spending of its tokens
/// @param spender The account for which the spending allowance was modified
/// @param value The new allowance from the owner to the spender
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./Swap/MesonSwap.sol";
import "./Pools/MesonPools.sol";
/// @title MesonManager
/// @notice The class to store data related to management permissions of Meson
contract MesonManager is MesonSwap, MesonPools {
/// @notice The admin of meson contract
/// The owner has the permission to upgrade meson contract. In future versions,
/// the management authority of meson contract will be decentralized.
address internal _owner;
/// @notice The manager to authorized fee waived swaps
/// Only the premium manager can authorize the execution to release for fee waived swaps.
/// This address is managed by Meson team.
address internal _premiumManager;
/// @dev This empty reserved space is put in place to allow future versions to
/// add new variables without shifting down storage in the inheritance chain.
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
uint256[50] private __gap;
event OwnerTransferred(address indexed prevOwner, address indexed newOwner);
event PremiumManagerTransferred(address indexed prevPremiumManager, address indexed newPremiumManager);
/// @notice The owner will also have the permission to add supported tokens
function addSupportToken(address token, uint8 index) external onlyOwner {
_addSupportToken(token, index);
}
/// @notice The owner will also have the permission to remove a supported tokens
function removeSupportToken(uint8 index) external onlyOwner {
_removeSupportToken(index);
}
/// @notice Add multiple tokens
function addMultipleSupportedTokens(address[] memory tokens, uint8[] memory indexes) external onlyOwner {
require(tokens.length == indexes.length, "Tokens and indexes should have the same length");
for (uint8 i = 0; i < tokens.length; i++) {
_addSupportToken(tokens[i], indexes[i]);
}
}
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
function transferPremiumManager(address newPremiumManager) public {
require(_isPremiumManager(), "Caller is not the premium manager");
_transferPremiumManager(newPremiumManager);
}
function withdrawServiceFee(uint8 tokenIndex, uint256 amount, uint40 toPoolIndex) external onlyOwner {
require(ownerOfPool[toPoolIndex] != address(0), "Pool index not registered");
_balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 0)] -= amount;
_balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, toPoolIndex)] += amount;
}
modifier onlyOwner() {
require(_owner == _msgSender(), "Caller is not the owner");
_;
}
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "New owner cannot be zero address");
address prevOwner = _owner;
_owner = newOwner;
emit OwnerTransferred(prevOwner, newOwner);
}
function _isPremiumManager() internal view override(MesonSwap, MesonPools) returns (bool) {
return _premiumManager == _msgSender();
}
function _transferPremiumManager(address newPremiumManager) internal {
require(newPremiumManager != address(0), "New premium manager be zero address");
address prevPremiumManager = _premiumManager;
_premiumManager = newPremiumManager;
emit PremiumManagerTransferred(prevPremiumManager, newPremiumManager);
}
function directSwap(uint256 encodedSwap, address recipient, bytes32 r, bytes32 yParityAndS)
external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap) forTargetChain(encodedSwap)
{
require(recipient != address(0), "Recipient cannot be zero address");
bytes32 digest = keccak256(abi.encodePacked(encodedSwap, recipient));
_checkSignature(digest, r, yParityAndS, _premiumManager);
uint256 amount = _amountFrom(encodedSwap);
uint8 inTokenIndex = _inTokenIndexFrom(encodedSwap);
uint256 releaseAmount = amount - _feeForLp(encodedSwap);
_balanceOfPoolToken[_poolTokenIndexFrom(inTokenIndex, 1)] += amount;
_balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, 1)] -= releaseAmount;
_unsafeDepositToken(inTokenIndex, _msgSender(), amount);
_release(encodedSwap, _outTokenIndexFrom(encodedSwap), _msgSender(), recipient, releaseAmount);
emit SwapReleased(encodedSwap);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
/// @title MesonPools Interface
interface IMesonPoolsEvents {
/// @notice Event when an LP pool is registered.
/// Emit at the end of `depositAndRegister()` calls.
/// @param poolIndex Pool index
/// @param owner Pool owner
event PoolRegistered(uint40 indexed poolIndex, address owner);
/// @notice Event when fund was deposited to an LP pool.
/// Emit at the end of `depositAndRegister()` and `deposit()` calls.
/// @param poolTokenIndex Concatenation of pool index & token index
/// @param amount The amount of tokens to be added to the pool
event PoolDeposited(uint48 indexed poolTokenIndex, uint256 amount);
/// @notice Event when fund was withdrawn from an LP pool.
/// Emit at the end of `withdraw()` calls.
/// @param poolTokenIndex Concatenation of pool index & token index
/// @param amount The amount of tokens to be removed from the pool
event PoolWithdrawn(uint48 indexed poolTokenIndex, uint256 amount);
/// @notice Event when an authorized address was added for an LP pool.
/// Emit at the end of `depositAndRegister()` calls.
/// @param poolIndex Pool index
/// @param addr Authorized address to be added
event PoolAuthorizedAddrAdded(uint40 indexed poolIndex, address addr);
/// @notice Event when an authorized address was removed for an LP pool.
/// Emit at the end of `depositAndRegister()` calls.
/// @param poolIndex Pool index
/// @param addr Authorized address to be removed
event PoolAuthorizedAddrRemoved(uint40 indexed poolIndex, address addr);
/// @notice Event when the ownership of a pool was transferred.
/// Emit at the end of `transferPoolOwner()` calls.
/// @param poolIndex Pool index
/// @param prevOwner Previous owner of the pool
/// @param newOwner New owner of the pool
event PoolOwnerTransferred(uint40 indexed poolIndex, address prevOwner, address newOwner);
/// @notice Event when a swap was locked.
/// Emit at the end of `lock()` and `lockSwap()` calls.
/// @param encodedSwap Encoded swap
event SwapLocked(uint256 indexed encodedSwap);
/// @notice Event when a swap was unlocked.
/// Emit at the end of `unlock()` calls.
/// @param encodedSwap Encoded swap
event SwapUnlocked(uint256 indexed encodedSwap);
/// @notice Event when a swap was released.
/// Emit at the end of `release()`, `directRelease()` calls.
/// @param encodedSwap Encoded swap
event SwapReleased(uint256 indexed encodedSwap);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./IMesonPoolsEvents.sol";
import "../utils/MesonStates.sol";
/// @title MesonPools
/// @notice The class to manage pools for LPs, and perform swap operations on the target
/// chain side.
/// Methods in this class will be executed when a user wants to swap into this chain.
/// LP pool operations are also provided in this class.
contract MesonPools is IMesonPoolsEvents, MesonStates {
/// @notice Locked Swaps
/// key: `swapId` is calculated from `encodedSwap` and `initiator`. See `_getSwapId` in `MesonHelpers.sol`
/// encodedSwap: see `MesonSwap.sol` for defination;
/// initiator: The user address who created and signed the swap request.
/// value: `lockedSwap` in format of `until:uint40|poolIndex:uint40`
/// until: The expiration time of this swap on the target chain. Need to `release` the swap fund before `until`;
/// poolIndex: The index of an LP pool. See `ownerOfPool` in `MesonStates.sol` for more information.
mapping(bytes32 => uint80) internal _lockedSwaps;
/// @dev This empty reserved space is put in place to allow future versions to
/// add new variables without shifting down storage in the inheritance chain.
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
uint256[50] private __gap;
/// @notice Initially deposit tokens into an LP pool and register a pool index.
/// This is the prerequisite for LPs if they want to participate in Meson swaps.
/// @dev Designed to be used by a new address who wants to be an LP and register a pool index
/// @param amount The amount of tokens to be added to the pool
/// @param poolTokenIndex In format of `tokenIndex:uint8|poolIndex:uint40`. See `_balanceOfPoolToken` in `MesonStates.sol` for more information.
function depositAndRegister(uint256 amount, uint48 poolTokenIndex) payable external {
require(amount > 0, "Amount must be positive");
address poolOwner = _msgSender();
uint40 poolIndex = _poolIndexFrom(poolTokenIndex);
require(poolIndex != 0, "Cannot use 0 as pool index"); // pool 0 is reserved for meson service fee
require(ownerOfPool[poolIndex] == address(0), "Pool index already registered");
require(poolOfAuthorizedAddr[poolOwner] == 0, "Signer address already registered");
ownerOfPool[poolIndex] = poolOwner;
poolOfAuthorizedAddr[poolOwner] = poolIndex;
_balanceOfPoolToken[poolTokenIndex] += amount;
uint8 tokenIndex = _tokenIndexFrom(poolTokenIndex);
_unsafeDepositToken(tokenIndex, poolOwner, amount);
emit PoolRegistered(poolIndex, poolOwner);
emit PoolDeposited(poolTokenIndex, amount);
}
/// @notice Deposit tokens into the liquidity pool.
/// The LP should be careful to make sure the `poolTokenIndex` is correct.
/// Make sure to call `depositAndRegister` first and register a pool index.
/// Otherwise, token may be deposited to others.
/// @dev Designed to be used by addresses authorized to a pool
/// @param amount The amount of tokens to be added to the pool
/// @param poolTokenIndex In format of `tokenIndex:uint8|poolIndex:uint40`. See `_balanceOfPoolToken` in `MesonStates.sol` for more information.
function deposit(uint256 amount, uint48 poolTokenIndex) payable external {
require(amount > 0, "Amount must be positive");
uint40 poolIndex = _poolIndexFrom(poolTokenIndex);
require(poolIndex != 0, "Cannot use 0 as pool index"); // pool 0 is reserved for meson service fee
require(poolIndex == poolOfAuthorizedAddr[_msgSender()], "Need an authorized address as the signer");
_balanceOfPoolToken[poolTokenIndex] += amount;
uint8 tokenIndex = _tokenIndexFrom(poolTokenIndex);
_unsafeDepositToken(tokenIndex, _msgSender(), amount);
emit PoolDeposited(poolTokenIndex, amount);
}
/// @notice Withdraw tokens from the liquidity pool.
/// @dev Designed to be used by LPs (pool owners) who have already registered a pool index
/// @param amount The amount to be removed from the pool
/// @param poolTokenIndex In format of `tokenIndex:uint8|poolIndex:uint40. See `_balanceOfPoolToken` in `MesonStates.sol` for more information.
function withdraw(uint256 amount, uint48 poolTokenIndex) external {
require(amount > 0, "Amount must be positive");
uint40 poolIndex = _poolIndexFrom(poolTokenIndex);
require(poolIndex != 0, "Cannot use 0 as pool index"); // pool 0 is reserved for meson service fee
require(ownerOfPool[poolIndex] == _msgSender(), "Need the pool owner as the signer");
_balanceOfPoolToken[poolTokenIndex] -= amount;
uint8 tokenIndex = _tokenIndexFrom(poolTokenIndex);
_safeTransfer(tokenIndex, _msgSender(), amount);
emit PoolWithdrawn(poolTokenIndex, amount);
}
/// @notice Add an authorized address to the pool
/// @dev Designed to be used by LPs (pool owners)
/// @param addr The address to be added
function addAuthorizedAddr(address addr) external {
require(poolOfAuthorizedAddr[addr] == 0, "Addr is authorized for another pool");
address poolOwner = _msgSender();
uint40 poolIndex = poolOfAuthorizedAddr[poolOwner];
require(poolIndex != 0, "The signer does not register a pool");
require(poolOwner == ownerOfPool[poolIndex], "Need the pool owner as the signer");
poolOfAuthorizedAddr[addr] = poolIndex;
emit PoolAuthorizedAddrAdded(poolIndex, addr);
}
/// @notice Remove an authorized address from the pool
/// @dev Designed to be used by LPs (pool owners)
/// @param addr The address to be removed
function removeAuthorizedAddr(address addr) external {
address poolOwner = _msgSender();
uint40 poolIndex = poolOfAuthorizedAddr[poolOwner];
require(poolIndex != 0, "The signer does not register a pool");
require(poolOwner == ownerOfPool[poolIndex], "Need the pool owner as the signer");
require(poolOfAuthorizedAddr[addr] == poolIndex, "Addr is not authorized for the signer's pool");
delete poolOfAuthorizedAddr[addr];
emit PoolAuthorizedAddrRemoved(poolIndex, addr);
}
/// @notice Transfer the ownership of a pool to another address
/// @dev Designed to be used by LPs (pool owners)
/// @param addr The new address to be the pool owner
function transferPoolOwner(address addr) external {
address poolOwner = _msgSender();
uint40 poolIndex = poolOfAuthorizedAddr[poolOwner];
require(poolIndex != 0, "The signer does not register a pool");
require(poolOwner == ownerOfPool[poolIndex], "Need the pool owner as the signer");
require(poolOfAuthorizedAddr[addr] == poolIndex, "Addr is not authorized for the signer's pool");
ownerOfPool[poolIndex] = addr;
emit PoolOwnerTransferred(poolIndex, poolOwner, addr);
}
function lock(uint256 encodedSwap, bytes32 r, bytes32 yParityAndS, address initiator) external {
// deprecated
lockSwap(encodedSwap, initiator);
}
/// @notice Lock funds to match a swap request. This is step 2️⃣ in a swap.
/// The authorized address of the bonding pool should call this method,
/// which will lock swapping fund on the target chain for `LOCK_TIME_PERIOD`
/// and wait for fund release and execution.
/// @dev Designed to be used by authorized addresses or pool owners
/// @param encodedSwap Encoded swap information
/// @param initiator The swap initiator who created and signed the swap request
function lockSwap(uint256 encodedSwap, address initiator)
public matchProtocolVersion(encodedSwap) forTargetChain(encodedSwap)
{
bytes32 swapId = _getSwapId(encodedSwap, initiator);
require(_lockedSwaps[swapId] == 0, "Swap already exists");
uint40 poolIndex = poolOfAuthorizedAddr[_msgSender()];
require(poolIndex != 0, "Caller not registered. Call depositAndRegister.");
uint256 until = block.timestamp + LOCK_TIME_PERIOD;
require(until < _expireTsFrom(encodedSwap) - 5 minutes, "Cannot lock because expireTs is soon.");
uint48 poolTokenIndex = _poolTokenIndexForOutToken(encodedSwap, poolIndex);
_balanceOfPoolToken[poolTokenIndex] -= _amountToLock(encodedSwap); // The service fee will be charged on release
uint256 coreAmount = _coreTokenAmount(encodedSwap);
if (coreAmount > 0) {
_balanceOfPoolToken[_poolTokenIndexFrom(indexOfToken[address(1)], poolIndex)] -= coreAmount;
}
_lockedSwaps[swapId] = _lockedSwapFrom(until, poolIndex);
emit SwapLocked(encodedSwap);
}
/// @notice If the locked swap is not released after `LOCK_TIME_PERIOD`,
/// the authorized address can call this method to unlock the swapping fund.
/// @dev Designed to be used by authorized addresses or pool owners
/// @param encodedSwap Encoded swap information
/// @param initiator The swap initiator who created and signed the swap request
function unlock(uint256 encodedSwap, address initiator) external {
bytes32 swapId = _getSwapId(encodedSwap, initiator);
uint80 lockedSwap = _lockedSwaps[swapId];
require(lockedSwap > 1, "Swap does not exist");
require(_untilFromLocked(lockedSwap) < block.timestamp, "Swap still in lock");
uint40 poolIndex = _poolIndexFromLocked(lockedSwap);
uint48 poolTokenIndex = _poolTokenIndexForOutToken(encodedSwap, poolIndex);
_balanceOfPoolToken[poolTokenIndex] += _amountToLock(encodedSwap);
uint256 coreAmount = _coreTokenAmount(encodedSwap);
if (coreAmount > 0) {
_balanceOfPoolToken[_poolTokenIndexFrom(indexOfToken[address(1)], poolIndex)] += coreAmount;
}
delete _lockedSwaps[swapId];
emit SwapUnlocked(encodedSwap);
}
/// @notice Release tokens to satisfy a locked swap. This is step 3️⃣ in a swap.
/// This method requires a release signature from the swap initiator,
/// but anyone (initiator herself, the LP, and other people) with the signature
/// can call this method to make sure the swapping fund is guaranteed to be released.
/// @dev Designed to be used by anyone
/// @param encodedSwap Encoded swap information
/// @param r Part of the release signature (same as in the `executeSwap` call)
/// @param yParityAndS Part of the release signature (same as in the `executeSwap` call)
/// @param initiator The swap initiator who created and signed the swap request
/// @param recipient The recipient address of the swap
function release(
uint256 encodedSwap,
bytes32 r,
bytes32 yParityAndS,
address initiator,
address recipient
) external {
require(_msgSender() == tx.origin, "Cannot be called through contracts");
require(_expireTsFrom(encodedSwap) > block.timestamp, "Cannot release because expired");
require(recipient != address(0), "Recipient cannot be zero address");
bool feeWaived = _feeWaived(encodedSwap);
if (feeWaived) {
// For swaps that service fee is waived, need the premium manager as the signer
require(_isPremiumManager(), "Caller is not the premium manager");
}
// For swaps that charge service fee, anyone can call
bytes32 swapId = _getSwapId(encodedSwap, initiator);
require(_lockedSwaps[swapId] > 1, "Swap does not exist");
_checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, initiator);
_lockedSwaps[swapId] = 1;
// LP fee will be subtracted from the swap amount
uint256 releaseAmount = _amountToLock(encodedSwap);
if (!feeWaived) { // If the swap should pay service fee (charged by Meson protocol)
uint256 serviceFee = _serviceFee(encodedSwap);
// Subtract service fee from the release amount
releaseAmount -= serviceFee;
// Collected service fee will be stored in `_balanceOfPoolToken` with `poolIndex = 0`.
// Currently, no one is capable to withdraw fund from pool 0. In the future, Meson protocol
// will specify the purpose of service fee and its usage permission, and upgrade the contract
// accordingly.
_balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, 0)] += serviceFee;
}
uint256 amountToShare = _amountToShare(encodedSwap);
if (amountToShare > 0) {
releaseAmount -= amountToShare;
_balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, _poolIndexToShare(encodedSwap))] += amountToShare;
}
uint256 coreAmount = _coreTokenAmount(encodedSwap);
if (coreAmount > 0) {
_transferCoreToken(recipient, coreAmount);
}
_release(encodedSwap, _outTokenIndexFrom(encodedSwap), initiator, recipient, releaseAmount);
emit SwapReleased(encodedSwap);
}
function directRelease(
uint256 encodedSwap,
bytes32 r,
bytes32 yParityAndS,
address initiator,
address recipient
) external matchProtocolVersion(encodedSwap) forTargetChain(encodedSwap) {
require(_msgSender() == tx.origin, "Cannot be called through contracts");
require(recipient != address(0), "Recipient cannot be zero address");
bool feeWaived = _feeWaived(encodedSwap);
if (feeWaived) {
require(_isPremiumManager(), "Caller is not the premium manager");
}
bytes32 swapId = _getSwapId(encodedSwap, initiator);
require(_lockedSwaps[swapId] == 0, "Swap already exists");
uint40 poolIndex = poolOfAuthorizedAddr[_msgSender()];
require(poolIndex != 0, "Caller not registered. Call depositAndRegister.");
if (r != bytes32(0x0)) {
require(_expireTsFrom(encodedSwap) > block.timestamp, "Cannot release because expired");
_checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, initiator);
} else if (!feeWaived) {
require(_isPremiumManager(), "Caller is not the premium manager");
}
_lockedSwaps[swapId] = 1;
uint256 releaseAmount = _amountToLock(encodedSwap);
_balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, poolIndex)] -= releaseAmount;
if (!feeWaived) {
uint256 serviceFee = _serviceFee(encodedSwap);
releaseAmount -= serviceFee;
_balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, 0)] += serviceFee;
}
uint256 amountToShare = _amountToShare(encodedSwap);
if (amountToShare > 0) {
releaseAmount -= amountToShare;
_balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, _poolIndexToShare(encodedSwap))] += amountToShare;
}
uint256 coreAmount = _coreTokenAmount(encodedSwap);
if (coreAmount > 0) {
_balanceOfPoolToken[_poolTokenIndexFrom(indexOfToken[address(1)], poolIndex)] -= coreAmount;
_transferCoreToken(recipient, coreAmount);
}
_release(encodedSwap, _outTokenIndexFrom(encodedSwap), initiator, recipient, releaseAmount);
emit SwapReleased(encodedSwap);
}
function _release(uint256 encodedSwap, uint8 tokenIndex, address initiator, address recipient, uint256 amount) internal {
if (_willTransferToContract(encodedSwap)) {
_transferToContract(tokenIndex, recipient, initiator, amount, _saltDataFrom(encodedSwap));
} else if (amount > 0) {
_safeTransfer(tokenIndex, recipient, amount);
if ((SHORT_COIN_TYPE == 0x9296 || SHORT_COIN_TYPE == 0xb4b1 || SHORT_COIN_TYPE == 0x6c62) && _swapForCoreToken(encodedSwap)) {
_callSkaleFaucet(recipient);
}
}
}
function _callSkaleFaucet(address recipient) private {
if (SHORT_COIN_TYPE == 0x9296) {
// SKALE Europa
bytes memory data = abi.encodeWithSelector(bytes4(0x6a627842), recipient);
(bool success, ) = address(0x2B267A3e49b351DEdac892400a530ABb2f899d23).call(data);
require(success, "Call faucet not successful");
} else if (SHORT_COIN_TYPE == 0xb4b1) {
// SKALE Nebula
bytes memory data = abi.encodeWithSelector(bytes4(0x0c11dedd), recipient);
(bool success, ) = address(0x5a6869ef5b81DCb58EBF51b8F893c31f5AFE3Fa8).call(data);
require(success, "Call faucet not successful");
} else if (SHORT_COIN_TYPE == 0x6c62) {
// SKALE Calypso
bytes memory data = abi.encodeWithSelector(bytes4(0x0c11dedd), recipient);
(bool success, ) = address(0x02891b34B7911A9C68e82C193cd7A6fBf0c3b30A).call(data);
require(success, "Call faucet not successful");
}
}
/// @notice Read information for a locked swap
function getLockedSwap(uint256 encodedSwap, address initiator) external view
returns (address poolOwner, uint40 until)
{
bytes32 swapId = _getSwapId(encodedSwap, initiator);
uint80 lockedSwap = _lockedSwaps[swapId];
if (lockedSwap == 1) {
poolOwner = address(1);
until = 0;
} else {
poolOwner = ownerOfPool[_poolIndexFromLocked(lockedSwap)];
until = uint40(_untilFromLocked(lockedSwap));
}
}
modifier forTargetChain(uint256 encodedSwap) {
require(_outChainFrom(encodedSwap) == SHORT_COIN_TYPE, "Swap not for this chain");
_;
}
function _isPremiumManager() internal view virtual returns (bool) {}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
/// @title MesonSwapEvents Interface
interface IMesonSwapEvents {
/// @notice Event when a swap request was posted.
/// Emit at the end of `postSwap()`, `postSwapFromInitiator()` and `postSwapFromContract()` calls.
/// @param encodedSwap Encoded swap
event SwapPosted(uint256 indexed encodedSwap);
/// @notice Event when a swap request was bonded.
/// Emit at the end of `bondSwap()` calls.
/// @param encodedSwap Encoded swap
event SwapBonded(uint256 indexed encodedSwap);
/// @notice Event when a swap request was cancelled.
/// Emit at the end of `cancelSwap()` calls.
/// @param encodedSwap Encoded swap
event SwapCancelled(uint256 indexed encodedSwap);
/// @notice Event when a swap request was executed.
/// Emit at the end of `executeSwap()`, `directExecuteSwap()` and `simpleExecuteSwap()` calls.
/// @param encodedSwap Encoded swap
event SwapExecuted(uint256 indexed encodedSwap);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./IMesonSwapEvents.sol";
import "../utils/MesonStates.sol";
/// @title MesonSwap
/// @notice The class to receive and process swap requests on the initial chain side.
/// Methods in this class will be executed by swap initiators or LPs
/// on the initial chain of swaps.
contract MesonSwap is IMesonSwapEvents, MesonStates {
/// @notice Posted Swaps
/// key: `encodedSwap` in format of `version:uint8|amount:uint40|salt:uint80|fee:uint40|expireTs:uint40|outChain:uint16|outToken:uint8|inChain:uint16|inToken:uint8`
/// version: Version of encoding
/// amount: The amount of tokens of this swap, always in decimal 6. The amount of a swap is capped at $100k so it can be safely encoded in uint48;
/// salt: The salt value of this swap, carrying some information below:
/// salt & 0x80000000000000000000 == true => will release to an EOA address, otherwise a smart contract;
/// salt & 0x40000000000000000000 == true => will waive *service fee*;
/// salt & 0x20000000000000000000 == true => meson.to;
/// salt & 0x10000000000000000000 == true => API;
/// salt & 0x08000000000000000000 == true => use *non-typed signing* (some wallets such as hardware wallets don't support EIP-712v1);
/// salt & 0x04000000000000000000 == true => swap for core token (n/a for releasing to contract);
/// salt & 0xfffff00000000000 => price for core token;
/// salt & 0x00000fff00000000 => amount for core token;
/// salt & 0x02000000000000000000 == true => share some release amount to partner;
/// salt & 0xffff000000000000 + 65536 => pool index to share;
/// salt & 0x0000ffff00000000 => amount to share;
/// salt & 0x01000000000000000000 == true => use points to waive service fee;
/// in reality, the salt header would be 0x41
/// salt & 0x0000ffffffffffffffff: customized data that can be passed to integrated 3rd-party smart contract;
/// fee: The fee given to LPs (liquidity providers). An extra service fee maybe charged afterwards;
/// expireTs: The expiration time of this swap on the initial chain. The LP should `executeSwap` and receive his funds before `expireTs`;
/// outChain: The target chain of a cross-chain swap (given by the last 2 bytes of SLIP-44);
/// outToken: The index of the token on the target chain. See `tokenForIndex` in `MesonToken.sol`;
/// inChain: The initial chain of a cross-chain swap (given by the last 2 bytes of SLIP-44);
/// inToken: The index of the token on the initial chain. See `tokenForIndex` in `MesonToken.sol`.
/// value: `postedSwap` in format of `initiator:address|poolIndex:uint40`
/// initiator: The swap initiator who created and signed the swap request (not necessarily the one who posted the swap);
// poolIndex: The index of an LP pool. See `ownerOfPool` in `MesonStates.sol` for more information.
mapping(uint256 => uint200) internal _postedSwaps;
/// @dev This empty reserved space is put in place to allow future versions to
/// add new variables without shifting down storage in the inheritance chain.
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
uint256[50] private __gap;
/// @notice Anyone can call this method to post a swap request. This is step 1️⃣ in a swap.
/// The r,s,v signature must be signed by the swap initiator. The initiator can call
/// this method directly, in which case `poolIndex` should be zero and wait for LPs
/// to call `bondSwap`. Initiators can also send the swap requests offchain (through the
/// meson relayer service). An LP (pool owner or authorized addresses) who receives requests through
/// the relayer can call this method to post and bond the swap in a single contract execution,
/// in which case he should give his own `poolIndex`.
///
/// The swap will last until `expireTs` and at most one LP pool can bond to it.
/// After the swap expires, the initiator can cancel the swap and withdraw funds.
///
/// Once a swap is posted and bonded, the bonding LP should call `lock` on the target chain.
///
/// @dev Designed to be used by both swap initiators, pool owner, or authorized addresses
/// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
/// @param r Part of the signature
/// @param yParityAndS Part of the signature
/// @param postingValue The value to be written to `_postedSwaps`. See `_postedSwaps` for encoding format
function postSwap(uint256 encodedSwap, bytes32 r, bytes32 yParityAndS, uint200 postingValue)
external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
{
address initiator = _initiatorFromPosted(postingValue);
uint40 poolIndex = _poolIndexFromPosted(postingValue);
if (poolIndex > 0 && _msgSender() != initiator) {
// If pool index is given, the signer should be the initiator or an authorized address
require(poolOfAuthorizedAddr[_msgSender()] == poolIndex, "Signer should be an authorized address of the given pool");
} // Otherwise, this is posted without bonding to a specific pool. Need to execute `bondSwap` later
_checkRequestSignature(encodedSwap, r, yParityAndS, initiator);
_postedSwaps[encodedSwap] = postingValue;
uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
_unsafeDepositToken(tokenIndex, initiator, _amountFrom(encodedSwap));
emit SwapPosted(encodedSwap);
}
function postSwapFromInitiator(uint256 encodedSwap, uint200 postingValue)
payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
{
address initiator = _initiatorFromPosted(postingValue);
require(_msgSender() == initiator, "Transaction should be sent from initiator");
_postedSwaps[encodedSwap] = postingValue;
uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
_unsafeDepositToken(tokenIndex, initiator, _amountFrom(encodedSwap));
emit SwapPosted(encodedSwap);
}
function postSwapFromContract(uint256 encodedSwap, uint200 postingValue, address contractAddress)
payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
{
address initiator = _initiatorFromPosted(postingValue);
require(_msgSender() == contractAddress, "Transaction should be sent from contractAddress");
_postedSwaps[encodedSwap] = postingValue;
uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
_unsafeDepositToken(tokenIndex, contractAddress, _amountFrom(encodedSwap));
emit SwapPosted(encodedSwap);
}
/// @notice If `postSwap` is called by the initiator of the swap and `poolIndex`
/// is zero, an LP (pool owner or authorized addresses) can call this to bond the swap to himself.
/// @dev Designed to be used by pool owner or authorized addresses
/// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
/// @param poolIndex The index of an LP pool. See `ownerOfPool` in `MesonStates.sol` for more information.
function bondSwap(uint256 encodedSwap, uint40 poolIndex) external {
uint200 postedSwap = _postedSwaps[encodedSwap];
require(postedSwap > 1, "Swap does not exist");
require(_poolIndexFromPosted(postedSwap) == 0, "Swap bonded to another pool");
require(poolOfAuthorizedAddr[_msgSender()] == poolIndex, "Signer should be an authorized address of the given pool");
_postedSwaps[encodedSwap] = postedSwap | poolIndex;
emit SwapBonded(encodedSwap);
}
/// @notice Cancel a swap. The swap initiator can call this method to withdraw funds
/// from an expired swap request.
/// @dev Designed to be used by swap initiators
/// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
function cancelSwap(uint256 encodedSwap) external {
uint200 postedSwap = _postedSwaps[encodedSwap];
require(postedSwap > 1, "Swap does not exist");
require(_expireTsFrom(encodedSwap) < block.timestamp, "Swap is still locked");
delete _postedSwaps[encodedSwap]; // Swap expired so the same one cannot be posted again
uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
_safeTransfer(tokenIndex, _initiatorFromPosted(postedSwap), _amountFrom(encodedSwap));
emit SwapCancelled(encodedSwap);
}
function cancelSwapTo(uint256 encodedSwap, address recipient, bytes32 r, bytes32 yParityAndS) external {
uint200 postedSwap = _postedSwaps[encodedSwap];
require(postedSwap > 1, "Swap does not exist");
require(_expireTsFrom(encodedSwap) < block.timestamp, "Swap is still locked");
bytes32 digest = keccak256(abi.encodePacked(encodedSwap, recipient));
_checkSignature(digest, r, yParityAndS, _initiatorFromPosted(postedSwap));
delete _postedSwaps[encodedSwap]; // Swap expired so the same one cannot be posted again
uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
_safeTransfer(tokenIndex, recipient, _amountFrom(encodedSwap));
emit SwapCancelled(encodedSwap);
}
/// @notice Execute the swap by providing a release signature. This is step 4️⃣ in a swap.
/// Once the signature is verified, the current bonding pool will receive funds deposited
/// by the swap initiator.
/// @dev Designed to be used by pool owner or authorized addresses of the current bonding pool
/// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
/// @param r Part of the release signature (same as in the `release` call)
/// @param yParityAndS Part of the release signature (same as in the `release` call)
/// @param recipient The recipient address of the swap
/// @param depositToPool Whether to deposit funds to the pool (will save gas)
function executeSwap(
uint256 encodedSwap,
bytes32 r,
bytes32 yParityAndS,
address recipient,
bool depositToPool
) external {
uint200 postedSwap = _postedSwaps[encodedSwap];
require(postedSwap > 1, "Swap does not exist");
// Swap expiredTs < current + MIN_BOND_TIME_PERIOD
if (_expireTsFrom(encodedSwap) < block.timestamp + MIN_BOND_TIME_PERIOD) {
// The swap cannot be posted again and therefore safe to remove it.
// LPs who execute in this mode can save ~5000 gas.
delete _postedSwaps[encodedSwap];
} else {
// The same swap information can be posted again, so set `_postedSwaps` value to 1 to prevent that.
_postedSwaps[encodedSwap] = 1;
}
_checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, _initiatorFromPosted(postedSwap));
uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
uint40 poolIndex = _poolIndexFromPosted(postedSwap);
if (depositToPool) {
_balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, poolIndex)] += _amountFrom(encodedSwap);
} else {
_safeTransfer(tokenIndex, ownerOfPool[poolIndex], _amountFrom(encodedSwap));
}
emit SwapExecuted(encodedSwap);
}
function directExecuteSwap(
uint256 encodedSwap,
bytes32 r,
bytes32 yParityAndS,
address initiator,
address recipient
) payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap) {
_checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, initiator);
_postedSwaps[encodedSwap] = 1;
uint256 amount = _amountFrom(encodedSwap);
uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
_balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 1)] += amount;
_unsafeDepositToken(tokenIndex, initiator, amount);
emit SwapExecuted(encodedSwap);
}
function simpleExecuteSwap(uint256 encodedSwap)
payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
{
uint256 amount = _amountFrom(encodedSwap);
uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
_balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 1)] += amount;
_unsafeDepositToken(tokenIndex, _msgSender(), amount);
emit SwapExecuted(encodedSwap);
}
/// @notice Read information for a posted swap
function getPostedSwap(uint256 encodedSwap) external view
returns (address initiator, address poolOwner, bool exist)
{
uint200 postedSwap = _postedSwaps[encodedSwap];
initiator = _initiatorFromPosted(postedSwap);
exist = postedSwap > 0;
if (initiator == address(0)) {
poolOwner = address(0);
} else {
poolOwner = ownerOfPool[_poolIndexFromPosted(postedSwap)];
}
}
modifier verifyEncodedSwap(uint256 encodedSwap) {
require(_inChainFrom(encodedSwap) == SHORT_COIN_TYPE, "Swap not for this chain");
require(
_tokenType(_inTokenIndexFrom(encodedSwap)) == _tokenType(_outTokenIndexFrom(encodedSwap)),
"In & out token types do not match"
);
require(_postedSwaps[encodedSwap] == 0, "Swap already exists");
require(_amountFrom(encodedSwap) <= MAX_SWAP_AMOUNT, "For security reason, amount cannot be greater than 100k");
uint256 delta = _expireTsFrom(encodedSwap) - block.timestamp;
require(delta > MIN_BOND_TIME_PERIOD, "Expire ts too early");
require(delta < MAX_BOND_TIME_PERIOD, "Expire ts too late");
_;
}
function _isPremiumManager() internal view virtual returns (bool) {}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "./MesonManager.sol";
contract UpgradableMeson is UUPSUpgradeable, MesonManager {
function initialize(address owner, address premiumManager) external initializer {
_transferOwnership(owner);
_transferPremiumManager(premiumManager);
}
function _authorizeUpgrade(address) internal override onlyOwner {}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
/// @notice Parameters of the Meson contract
/// for MemeCore
contract MesonConfig {
uint8 constant MESON_PROTOCOL_VERSION = 1;
// Ref https://github.com/satoshilabs/slips/blob/master/slip-0044.md
uint16 constant SHORT_COIN_TYPE = 0x1100;
uint256 constant MAX_SWAP_AMOUNT = 1e11; // 100,000.000000 = 100k
uint256 constant SERVICE_FEE_RATE = 5; // service fee = 5 / 10000 = 0.05%
uint256 constant SERVICE_FEE_MINIMUM = 500_000; // min $0.5
uint256 constant SERVICE_FEE_MINIMUM_ETH = 500; // min 0.0005 ETH (or SOL)
uint256 constant SERVICE_FEE_MINIMUM_BNB = 5000; // min 0.005 BNB
uint256 constant SERVICE_FEE_MINIMUM_BTC = 10; // min 0.00001 BTC
uint256 constant MIN_BOND_TIME_PERIOD = 1 hours;
uint256 constant MAX_BOND_TIME_PERIOD = 2 hours;
uint256 constant LOCK_TIME_PERIOD = 20 minutes;
bytes28 constant ETH_SIGN_HEADER = bytes28("\x19Ethereum Signed Message:\n32");
bytes28 constant ETH_SIGN_HEADER_52 = bytes28("\x19Ethereum Signed Message:\n52");
bytes25 constant TRON_SIGN_HEADER = bytes25("\x19TRON Signed Message:\n32\n");
bytes25 constant TRON_SIGN_HEADER_33 = bytes25("\x19TRON Signed Message:\n33\n");
bytes25 constant TRON_SIGN_HEADER_53 = bytes25("\x19TRON Signed Message:\n53\n");
bytes32 constant REQUEST_TYPE_HASH = keccak256("bytes32 Sign to request a swap on Meson");
bytes32 constant RELEASE_TYPE_HASH = keccak256("bytes32 Sign to release a swap on Mesonaddress Recipient");
bytes32 constant RELEASE_TO_TRON_TYPE_HASH = keccak256("bytes32 Sign to release a swap on Mesonaddress Recipient (tron address in hex format)");
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "@openzeppelin/contracts/utils/Context.sol";
import "./MesonConfig.sol";
/// @title MesonHelpers
/// @notice The class that provides helper functions for Meson protocol
contract MesonHelpers is MesonConfig, Context {
modifier matchProtocolVersion(uint256 encodedSwap) {
require(_versionFrom(encodedSwap) == MESON_PROTOCOL_VERSION, "Incorrect encoding version");
_;
}
function getShortCoinType() external pure returns (bytes2) {
return bytes2(SHORT_COIN_TYPE);
}
/// @notice Calculate `swapId` from `encodedSwap`, `initiator`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _getSwapId(uint256 encodedSwap, address initiator) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(encodedSwap, initiator));
}
/// @notice Decode `version` from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _versionFrom(uint256 encodedSwap) internal pure returns (uint8) {
return uint8(encodedSwap >> 248);
}
/// @notice Decode `amount` from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _amountFrom(uint256 encodedSwap) internal pure returns (uint256) {
return (encodedSwap >> 208) & 0xFFFFFFFFFF;
}
function _amountToLock(uint256 encodedSwap) internal pure returns (uint256) {
return _amountFrom(encodedSwap) - _feeForLp(encodedSwap) - _amountForCoreTokenFrom(encodedSwap);
}
/// @notice Calculate the service fee from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _serviceFee(uint256 encodedSwap) internal pure returns (uint256) {
uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
uint256 minFee;
if (tokenIndex >= 252) {
minFee = SERVICE_FEE_MINIMUM_ETH;
} else if (tokenIndex >= 248) {
minFee = SERVICE_FEE_MINIMUM_BNB;
} else if (tokenIndex >= 244) {
minFee = SERVICE_FEE_MINIMUM_ETH;
} else if (tokenIndex >= 240) {
minFee = SERVICE_FEE_MINIMUM_BTC;
} else {
minFee = SERVICE_FEE_MINIMUM;
}
// Default to `serviceFee` = 0.05% * `amount`
uint256 fee = _amountFrom(encodedSwap) * SERVICE_FEE_RATE / 10000;
return fee > minFee ? fee : minFee;
}
/// @notice Decode `fee` (the fee for LPs) from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _feeForLp(uint256 encodedSwap) internal pure returns (uint256) {
return (encodedSwap >> 88) & 0xFFFFFFFFFF;
}
/// @notice Decode `salt` from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _saltFrom(uint256 encodedSwap) internal pure returns (uint80) {
return uint80(encodedSwap >> 128);
}
/// @notice Decode data from `salt`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _saltDataFrom(uint256 encodedSwap) internal pure returns (uint64) {
return uint64(encodedSwap >> 128);
}
/// @notice Whether the swap should release to a 3rd-party integrated dapp contract
/// See method `release` in `MesonPools.sol` for more details
function _willTransferToContract(uint256 encodedSwap) internal pure returns (bool) {
return (encodedSwap & 0x8000000000000000000000000000000000000000000000000000) == 0;
}
/// @notice Whether the swap needs to pay service fee
/// See method `release` in `MesonPools.sol` for more details about the service fee
function _feeWaived(uint256 encodedSwap) internal pure returns (bool) {
return (encodedSwap & 0x4000000000000000000000000000000000000000000000000000) > 0;
}
/// @notice Whether the swap was signed in the non-typed manner (usually by hardware wallets)
function _signNonTyped(uint256 encodedSwap) internal pure returns (bool) {
return (encodedSwap & 0x0800000000000000000000000000000000000000000000000000) > 0;
}
function _swapForCoreToken(uint256 encodedSwap) internal pure returns (bool) {
return (_outTokenIndexFrom(encodedSwap) < 191) &&
((encodedSwap & 0x8410000000000000000000000000000000000000000000000000) == 0x8410000000000000000000000000000000000000000000000000);
}
function _amountForCoreTokenFrom(uint256 encodedSwap) internal pure returns (uint256) {
if (_swapForCoreToken(encodedSwap)) {
uint256 d = (encodedSwap >> 160) & 0xFFFF;
if (d == 0xFFFF) {
return _amountFrom(encodedSwap) - _feeForLp(encodedSwap) - (_feeWaived(encodedSwap) ? 0 : _serviceFee(encodedSwap));
}
return _decompressFixedPrecision(d) * 1e3;
}
return 0;
}
function _coreTokenAmount(uint256 encodedSwap) internal pure returns (uint256) {
uint256 amountForCore = _amountForCoreTokenFrom(encodedSwap);
if (amountForCore > 0) {
return amountForCore * 1e4 / _decompressFixedPrecision((encodedSwap >> 176) & 0xFFFF);
}
return 0;
}
function _shareWithPartner(uint256 encodedSwap) internal pure returns (bool) {
return !_willTransferToContract(encodedSwap)
&& ((encodedSwap & 0x0600000000000000000000000000000000000000000000000000) == 0x0200000000000000000000000000000000000000000000000000);
}
function _amountToShare(uint256 encodedSwap) internal pure returns (uint256) {
if (_shareWithPartner(encodedSwap)) {
return _decompressFixedPrecision((encodedSwap >> 160) & 0xFFFF);
}
return 0;
}
function _decompressFixedPrecision(uint256 d) internal pure returns (uint256) {
if (d <= 1000) {
return d;
}
return ((d - 1000) % 9000 + 1000) * 10 ** ((d - 1000) / 9000);
}
function _poolIndexToShare(uint256 encodedSwap) internal pure returns (uint40) {
if (_shareWithPartner(encodedSwap)) {
return (uint40(encodedSwap >> 176) & 0xFFFF) + 65536;
}
return 0;
}
/// @notice Decode `expireTs` from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _expireTsFrom(uint256 encodedSwap) internal pure returns (uint256) {
return (encodedSwap >> 48) & 0xFFFFFFFFFF;
// [Suggestion]: return uint40(encodedSwap >> 48);
}
/// @notice Decode the initial chain (`inChain`) from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _inChainFrom(uint256 encodedSwap) internal pure returns (uint16) {
return uint16(encodedSwap >> 8);
}
/// @notice Decode the token index of initial chain (`inToken`) from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _inTokenIndexFrom(uint256 encodedSwap) internal pure returns (uint8) {
return uint8(encodedSwap);
}
/// @notice Decode the target chain (`outChain`) from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _outChainFrom(uint256 encodedSwap) internal pure returns (uint16) {
return uint16(encodedSwap >> 32);
}
/// @notice Decode the token index of target chain (`outToken`) from `encodedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
function _outTokenIndexFrom(uint256 encodedSwap) internal pure returns (uint8) {
return uint8(encodedSwap >> 24);
}
function _tokenType(uint8 tokenIndex) internal pure returns (uint8) {
if (tokenIndex >= 192) {
// Non stablecoins [192, 255] -> [48, 63]
return tokenIndex / 4;
} else if (tokenIndex <= 64) {
// Stablecoins [1, 64] -> 0
return 0;
} else if (tokenIndex <= 112) {
// 3rd party tokens [65, 112] -> [1, 24]
return (tokenIndex + 1) / 2 - 32;
} else if (tokenIndex <= 128) {
// 3rd party tokens [113, 128] -> [33, 48]
return tokenIndex - 80;
}
revert("Token index not allowed for swapping");
}
/// @notice Decode `outToken` from `encodedSwap`, and encode it with `poolIndex` to `poolTokenIndex`.
/// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
function _poolTokenIndexForOutToken(uint256 encodedSwap, uint40 poolIndex) internal pure returns (uint48) {
return uint48((encodedSwap & 0xFF000000) << 16) | poolIndex;
}
/// @notice Decode `initiator` from `postedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `postedSwap`
function _initiatorFromPosted(uint200 postedSwap) internal pure returns (address) {
return address(uint160(postedSwap >> 40));
}
/// @notice Decode `poolIndex` from `postedSwap`
/// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `postedSwap`
function _poolIndexFromPosted(uint200 postedSwap) internal pure returns (uint40) {
return uint40(postedSwap);
}
/// @notice Encode `lockedSwap` from `until` and `poolIndex`
/// See variable `_lockedSwaps` in `MesonPools.sol` for the defination of `lockedSwap`
function _lockedSwapFrom(uint256 until, uint40 poolIndex) internal pure returns (uint80) {
return (uint80(until) << 40) | poolIndex;
}
/// @notice Decode `poolIndex` from `lockedSwap`
/// See variable `_lockedSwaps` in `MesonPools.sol` for the defination of `lockedSwap`
function _poolIndexFromLocked(uint80 lockedSwap) internal pure returns (uint40) {
return uint40(lockedSwap);
}
/// @notice Decode `until` from `lockedSwap`
/// See variable `_lockedSwaps` in `MesonPools.sol` for the defination of `lockedSwap`
function _untilFromLocked(uint80 lockedSwap) internal pure returns (uint256) {
return uint256(lockedSwap >> 40);
}
/// @notice Encode `poolTokenIndex` from `tokenIndex` and `poolIndex`
/// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
function _poolTokenIndexFrom(uint8 tokenIndex, uint40 poolIndex) internal pure returns (uint48) {
return (uint48(tokenIndex) << 40) | poolIndex;
}
/// @notice Decode `tokenIndex` from `poolTokenIndex`
/// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
function _tokenIndexFrom(uint48 poolTokenIndex) internal pure returns (uint8) {
return uint8(poolTokenIndex >> 40);
}
/// @notice Decode `poolIndex` from `poolTokenIndex`
/// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
function _poolIndexFrom(uint48 poolTokenIndex) internal pure returns (uint40) {
return uint40(poolTokenIndex);
}
/// @notice Check the initiator's signature for a swap request
/// Signatures are constructed with the package `mesonfi/sdk`. Go to `packages/sdk/src/SwapSigner.ts` and
/// see how to generate a signautre in class `EthersWalletSwapSigner` method `signSwapRequest`
/// @param encodedSwap Encoded swap information. See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
/// @param r Part of the signature
/// @param yParityAndS Part of the signature
/// @param signer The signer for the swap request which is the `initiator`
function _checkRequestSignature(
uint256 encodedSwap,
bytes32 r,
bytes32 yParityAndS,
address signer
) internal pure {
require(signer != address(0), "Signer cannot be empty address");
bytes32 s = yParityAndS & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(yParityAndS) >> 255) + 27);
require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature");
bool nonTyped = _signNonTyped(encodedSwap);
bytes32 digest;
if (_inChainFrom(encodedSwap) == 0x00c3) {
digest = keccak256(abi.encodePacked(nonTyped ? TRON_SIGN_HEADER_33 : TRON_SIGN_HEADER, encodedSwap));
} else if (nonTyped) {
digest = keccak256(abi.encodePacked(ETH_SIGN_HEADER, encodedSwap));
} else {
bytes32 typehash = REQUEST_TYPE_HASH;
assembly {
mstore(0, encodedSwap)
mstore(32, keccak256(0, 32))
mstore(0, typehash)
digest := keccak256(0, 64)
}
}
require(signer == ecrecover(digest, v, r, s), "Invalid signature");
}
/// @notice Check the initiator's signature for the release request
/// Signatures are constructed with the package `mesonfi/sdk`. Go to `packages/sdk/src/SwapSigner.ts` and
/// see how to generate a signautre in class `EthersWalletSwapSigner` method `signSwapRelease`
/// @param encodedSwap Encoded swap information. See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
/// @param recipient The recipient address of the swap
/// @param r Part of the signature
/// @param yParityAndS Part of the signature
/// @param signer The signer for the swap request which is the `initiator`
function _checkReleaseSignature(
uint256 encodedSwap,
address recipient,
bytes32 r,
bytes32 yParityAndS,
address signer
) internal pure {
require(signer != address(0), "Signer cannot be empty address");
bytes32 s = yParityAndS & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(yParityAndS) >> 255) + 27);
require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature");
bool nonTyped = _signNonTyped(encodedSwap);
bytes32 digest;
if (_inChainFrom(encodedSwap) == 0x00c3) {
digest = keccak256(abi.encodePacked(nonTyped ? TRON_SIGN_HEADER_53 : TRON_SIGN_HEADER, encodedSwap, recipient));
} else if (nonTyped) {
digest = keccak256(abi.encodePacked(ETH_SIGN_HEADER_52, encodedSwap, recipient));
} else {
bytes32 typehash = _outChainFrom(encodedSwap) == 0x00c3 ? RELEASE_TO_TRON_TYPE_HASH : RELEASE_TYPE_HASH;
assembly {
mstore(20, recipient)
mstore(0, encodedSwap)
mstore(32, keccak256(0, 52))
mstore(0, typehash)
digest := keccak256(0, 64)
}
}
require(signer == ecrecover(digest, v, r, s), "Invalid signature");
}
function _checkSignature(bytes32 digest, bytes32 r, bytes32 yParityAndS, address signer) internal pure {
require(signer != address(0), "Signer cannot be empty address");
bytes32 s = yParityAndS & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(yParityAndS) >> 255) + 27);
require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature");
require(signer == ecrecover(digest, v, r, s), "Invalid signature");
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "@openzeppelin/contracts/utils/Address.sol";
import "../interfaces/IERC20Minimal.sol";
import "../interfaces/IDepositWithBeneficiary.sol";
import "./MesonTokens.sol";
import "./MesonHelpers.sol";
/// @title MesonStates
/// @notice The class that keeps track of LP pool states
contract MesonStates is MesonTokens, MesonHelpers {
bytes4 private constant ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
bytes4 private constant ERC20_TRANSFER_FROM_SELECTOR = bytes4(keccak256("transferFrom(address,address,uint256)"));
/// @notice The mapping from *authorized addresses* to LP pool indexes.
/// See `ownerOfPool` to understand how pool index is defined and used.
///
/// This mapping records the relation between *authorized addresses* and pool indexes, where
/// authorized addresses are those who have the permision to match and complete a swap with funds
/// in a pool with specific index. For example, for an LP pool with index `i` there could be multiple
/// addresses that `poolOfAuthorizedAddr[address] = i`, which means these addresses can all sign to match
/// (call `bondSwap`, `lock`) a swap and complete it (call `release`) with funds in pool `i`. That helps
/// an LP to give other addresses the permission to perform daily swap transactions. However, authorized
/// addresses cannot withdraw funds from the LP pool, unless it's given in `ownerOfPool` which records
/// the *owner* address for each pool.
///
/// The pool index 0 is reserved for use by Meson
mapping(address => uint40) public poolOfAuthorizedAddr;
/// @notice The mapping from LP pool indexes to their owner addresses.
/// Each LP pool in Meson has a uint40 index `i` and each LP needs to register an pool index at
/// initial deposit by calling `depositAndRegister`. The balance for each LP pool is tracked by its
/// pool index and token index (see `_balanceOfPoolToken`).
///
/// This mapping records the *owner* address for each LP pool. Only the owner address can withdraw funds
/// from its corresponding LP pool.
///
/// The pool index 0 is reserved for use by Meson
mapping(uint40 => address) public ownerOfPool;
/// @notice Balance for each token in LP pool, tracked by the `poolTokenIndex`.
/// See `ownerOfPool` to understand how pool index is defined and used.
///
/// The balance of a token in an LP pool is `_balanceOfPoolToken[poolTokenIndex]` in which
/// the `poolTokenIndex` is in format of `tokenIndex:uint8|poolIndex:uint40`. `tokenIndex`
/// is the index of supported tokens given by `tokenForIndex` (see definition in `MesonTokens.sol`).
/// The balances are always store as tokens have decimal 6, which is the case for USDC/USDT on most chains
/// except BNB Smart Chain & Conflux. In the exceptional cases, the value of token amount will be converted
/// on deposit and withdrawal (see `_safeTransfer` and `_unsafeDepositToken` in `MesonHelpers.sol`).
///
/// The pool index 0 is reserved for use by Meson to store service fees
mapping(uint48 => uint256) internal _balanceOfPoolToken;
/// @dev This empty reserved space is put in place to allow future versions to
/// add new variables without shifting down storage in the inheritance chain.
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
uint256[50] private __gap;
function poolTokenBalance(address token, address addr) external view returns (uint256) {
uint8 tokenIndex = indexOfToken[token];
uint40 poolIndex = poolOfAuthorizedAddr[addr];
if (poolIndex == 0 || tokenIndex == 0) {
return 0;
}
return _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, poolIndex)];
}
/// @notice The collected service fee of a specific token.
/// @param tokenIndex The index of a supported token. See `tokenForIndex` in `MesonTokens.sol`
function serviceFeeCollected(uint8 tokenIndex) external view returns (uint256) {
return _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 0)];
}
/// @notice Help the senders to transfer their assets to the Meson contract
/// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
/// @param sender The sender of the transfer
/// @param amount The value of the transfer (always in decimal 6)
function _unsafeDepositToken(
uint8 tokenIndex,
address sender,
uint256 amount
) internal {
require(amount > 0, "Amount must be greater than zero");
if (_isCoreToken(tokenIndex)) {
// Core tokens (e.g. ETH or BNB)
require(amount * 1e12 == msg.value, "msg.value does not match the amount");
} else {
// Stablecoins
address token = tokenForIndex[tokenIndex];
require(token != address(0), "Token not supported");
require(Address.isContract(token), "The given token address is not a contract");
amount *= _amountFactor(tokenIndex);
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(
ERC20_TRANSFER_FROM_SELECTOR,
sender,
address(this),
amount
));
require(success && (data.length == 0 || abi.decode(data, (bool))), "transferFrom failed");
}
}
/// @notice Safe transfers tokens from Meson contract to a recipient
/// for interacting with ERC20 tokens that do not consistently return true/false
/// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
/// @param recipient The recipient of the transfer
/// @param amount The value of the transfer (always in decimal 6)
function _safeTransfer(
uint8 tokenIndex,
address recipient,
uint256 amount
) internal {
if (_isCoreToken(tokenIndex)) {
// Core tokens (e.g. ETH or BNB)
_transferCoreToken(recipient, amount);
} else {
// Stablecoins
address token = tokenForIndex[tokenIndex];
require(Address.isContract(token), "The given token address is not a contract");
amount *= _amountFactor(tokenIndex);
if (SHORT_COIN_TYPE == 0x00c3) {
IERC20Minimal(token).transfer(recipient, amount);
} else {
// This doesn't works on Tron
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(
ERC20_TRANSFER_SELECTOR,
recipient,
amount
));
require(success && (data.length == 0 || abi.decode(data, (bool))), "transfer failed");
}
}
}
function _transferCoreToken(address recipient, uint256 amount) internal {
(bool success, ) = recipient.call{value: amount * 1e12}("");
require(success, "Transfer failed");
}
/// @notice Transfer tokens to a contract using `depositWithBeneficiary`
/// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
/// @param contractAddr The smart contract address that will receive transferring tokens
/// @param beneficiary The beneficiary of `depositWithBeneficiary`
/// @param amount The value of the transfer (always in decimal 6)
/// @param data Extra data passed to the contract
function _transferToContract(
uint8 tokenIndex,
address contractAddr,
address beneficiary,
uint256 amount,
uint64 data
) internal {
require(Address.isContract(contractAddr), "The given recipient address is not a contract");
amount *= _amountFactor(tokenIndex);
if (_isCoreToken(tokenIndex)) {
// Core tokens (e.g. ETH or BNB)
IDepositWithBeneficiary(contractAddr).depositWithBeneficiary{value: amount}(
address(0),
amount,
beneficiary,
data
);
} else {
// Stablecoins
address token = tokenForIndex[tokenIndex];
require(Address.isContract(token), "The given token address is not a contract");
IERC20Minimal(token).approve(contractAddr, amount);
IDepositWithBeneficiary(contractAddr).depositWithBeneficiary(
token,
amount,
beneficiary,
data
);
}
}
/// @notice Determine if token has decimal 18 and therefore need to adjust amount
/// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
function _amountFactor(uint8 tokenIndex) private pure returns (uint256) {
if (tokenIndex <= 32) {
return 1;
} else if (tokenIndex == 242 && SHORT_COIN_TYPE != 0x02ca && SHORT_COIN_TYPE != 0x1771) {
return 100;
} else if (tokenIndex > 112 && tokenIndex <= 123) {
return 100;
} else if (tokenIndex > 123 && tokenIndex <= 128) {
return 1000;
}
return 1e12;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
/// @title MesonTokens
/// @notice The class that stores the information of Meson's supported tokens
contract MesonTokens {
/// @notice The whitelist of supported tokens in Meson
/// Meson use a whitelist for supported stablecoins, which is specified on first deployment
/// or added through `_addSupportToken` Only modify this mapping through `_addSupportToken`.
/// key: `tokenIndex` in range of 1-255
/// 0: unsupported
/// 1-32: stablecoins with decimals 6
/// 1, 9: USDC, USDC.e
/// 2, 10: USDT, USDT.e
/// 3: BUSD
/// 6: CUSD (Viction/Tomo)
/// 17: PoD USDC
/// 18: PoD USDT
/// 19: PoD BUSD
/// 32: PoD
/// 33-48: stablecoins with decimals 18
/// 33: USDC
/// 34: USDT
/// 35: BUSD
/// 36: (reserved for DAI)
/// 37: cUSD (Celo)
/// 39: USDB (Blast)
/// 40: FDUSD
/// 41: BBUSD
/// 48: USD1
/// 49-64: stablecoins as core (decimals 18)
/// 49: USDC
/// 52: DAI
/// 65-112: 3rd party tokens (decimals 18)
/// 65: iUSD (iZUMi Bond USD)
/// 67: M-BTC (Merlin BTC)
/// 69: MERL
/// 71: STONE
/// 73: SolvBTC.m
/// 75: SolvBTC
/// 77: SolvBTC.a
/// 79: uBTC
/// 81: xSolvBTC
/// 83: SolvBTC.ENA
/// 85: SolvBTC.JUP
/// 87: PUMP
/// 89: B2
/// 113-123: 3rd party tokens (decimals 8)
/// 113: pumpBTC
/// 114: uniBTC
/// 115: cbBTC
/// 124-128: 3rd party tokens (decimals 9)
/// 124: DUCK
/// 129-190: (Unspecified)
/// 191: No-swap core
/// 192-235: (Unspecified)
/// 236-239: MATIC & MATIC equivalent
/// 236: PoD MATIC
/// 238: ERC20 MATIC
/// 239: MATIC as core
/// 240-243: BTC & BTC equivalent
/// 240: PoD BTC
/// 241: ERC20 BTC (decimals 18)
/// 242: ERC20 BTC (decimals 8 except BNB Smart Chain & BounceBit)
/// 243: BTC as core
/// 244-247: SOL & SOL equivalent
/// 244: PoD SOL
/// 246: ERC20 SOL
/// 247: SOL as core
/// 248-251: BNB & BNB equivalent
/// 248: PoD BNB
/// 250: (reserved for ERC20 BNB)
/// 251: BNB as core
/// 252-255: ETH & ETH equivalent
/// 252: PoD ETH
/// 254: Wrapped ETH
/// 255: ETH as core
/// value: the supported token's contract address
mapping(uint8 => address) public tokenForIndex;
/// @notice The mapping to get `tokenIndex` from a supported token's address
/// Only modify this mapping through `_addSupportToken`.
/// key: the supported token's contract address
/// value: `tokenIndex` in range of 1-255
mapping(address => uint8) public indexOfToken;
/// @dev This empty reserved space is put in place to allow future versions to
/// add new variables without shifting down storage in the inheritance chain.
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
uint256[50] private __gap;
function _isCoreToken(uint8 tokenIndex) internal returns (bool) {
return (tokenIndex >= 49 && tokenIndex <= 64) || ((tokenIndex > 190) && ((tokenIndex % 4) == 3));
}
/// @notice Return all supported token addresses in an array ordered by `tokenIndex`
/// This method will only return tokens with consecutive token indexes.
function getSupportedTokens() external view returns (address[] memory tokens, uint8[] memory indexes) {
uint8 i;
uint8 num;
for (i = 0; i < 255; i++) {
if (tokenForIndex[i+1] != address(0)) {
num++;
}
}
tokens = new address[](num);
indexes = new uint8[](num);
uint8 j = 0;
for (i = 0; i < 255; i++) {
if (tokenForIndex[i+1] != address(0)) {
tokens[j] = tokenForIndex[i+1];
indexes[j] = i+1;
j++;
}
}
}
function _addSupportToken(address token, uint8 index) internal {
require(index != 0, "Cannot use 0 as token index");
require(token != address(0), "Cannot use zero address");
require(indexOfToken[token] == 0, "Token has been added before");
require(tokenForIndex[index] == address(0), "Index has been used");
if (_isCoreToken(index)) {
require(token == address(0x1), "Core token requires adddress(0x1)");
}
indexOfToken[token] = index;
tokenForIndex[index] = token;
}
function _removeSupportToken(uint8 index) internal {
require(index != 0, "Cannot use 0 as token index");
address token = tokenForIndex[index];
require(token != address(0), "Token for the index does not exist");
delete indexOfToken[token];
delete tokenForIndex[index];
}
}{
"optimizer": {
"enabled": true,
"runs": 100
},
"evmVersion": "istanbul",
"viaIR": true,
"metadata": {
"bytecodeHash": "none"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"premiumManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040818152346102df5781615293803803809161001e82856102e4565b83396020938491810103126102df57516001600160a01b0392838216918290036102df578251614e68808201956001600160401b03929091838811828910176102c95761042b823980600097039087f080156102bf57168451938385019063485cc95560e01b825233602487015260448601526044855260808501858110848211176102ab57808752823b1561025457507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191683179055855194827fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8988a280511580159061024d575b610125575b865160a890816103838239f35b6060860186811085821117610239578752602786527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c85870152660819985a5b195960ca1b87870152823b156101e6575187928392905af4903d156101d5573d9081116101c15784956101b49551916101a785601f19601f84011601846102e4565b825281933d92013e610307565b5080388080808080610118565b634e487b7160e01b86526041600452602486fd5b5090506101b4929350606090610307565b865162461bcd60e51b815260048101869052602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608490fd5b634e487b7160e01b89526041600452602489fd5b5087610113565b62461bcd60e51b81526084868101869052602d60a48801527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60c48801526c1bdd08184818dbdb9d1c9858dd609a1b60e488015290fd5b634e487b7160e01b88526041600452602488fd5b85513d88823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b600080fd5b601f909101601f19168101906001600160401b038211908210176102c957604052565b90919015610313575090565b8151156103235750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b828510610369575050604492506000838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935061034656fe608060405236156054577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e156050573d90f35b3d90fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e156050573d90f3fea164736f6c6343000810000a60a080604052346100315730608052614e31908161003782396080518181816108d301528181610efa01526129b10152f35b600080fdfe60806040526004361015610013575b600080fd5b60003560e01c8063051119f5146103475780631e2a60751461033e5780632335093c14610335578063264849e71461032c57806330f00f3a1461032357806335eff30f1461031a5780633659cfe61461031157806337b90a4f14610308578063485cc955146102ff5780634f1ef286146102f6578063515147ab146102ed57806352d1902d146102e457806354d6a2b7146102db57806358d9b4e1146102d257806360a2da98146102c957806360b068be146102c05780637234cd95146102b7578063741c8e2d146102ae5780637fe0282b146102a5578063827c87cc1461029c57806389a734c0146102935780638b0a77651461028a5780638f487dc9146102815780639fa1027914610278578063a5c9c66c1461026f578063ab115fd814610266578063b805f3211461025d578063c11d9ecb14610254578063c5d7ca001461024b578063c8173c4414610242578063cb4f999b14610239578063ce7f79b914610230578063d3c7c2c714610227578063d3e95ea41461021e578063d4f8232214610215578063decf2a481461020c578063eba7fb7714610203578063f1d2ec1d146101fa578063f2fde38b146101f1578063ff22f272146101e85763ff378719146101e057600080fd5b61000e6125b1565b5061000e6124af565b5061000e612477565b5061000e61234c565b5061000e61232b565b5061000e61228f565b5061000e612249565b5061000e612214565b5061000e6120f8565b5061000e611fcd565b5061000e611eda565b5061000e611e49565b5061000e611da0565b5061000e611cf6565b5061000e611c2e565b5061000e6119fd565b5061000e61182f565b5061000e611737565b5061000e6115f6565b5061000e6115bb565b5061000e611577565b5061000e6113ed565b5061000e6113a1565b5061000e61130b565b5061000e611204565b5061000e611150565b5061000e611086565b5061000e611061565b5061000e610fab565b5061000e610ee6565b5061000e610d2c565b5061000e610cb4565b5061000e610b1d565b5061000e610a26565b5061000e6108af565b5061000e610798565b5061000e61067a565b5061000e610595565b5061000e610557565b5061000e6104b7565b5061000e6103bc565b600435906001600160a01b038216820361000e57565b602435906001600160a01b038216820361000e57565b606435906001600160a01b038216820361000e57565b604435906001600160a01b038216820361000e57565b35906001600160a01b038216820361000e57565b503461000e57602036600319011261000e576103d6610350565b3360005260996020527f475b83c893df40ee19fd0783cf26478cdb58478dff65bb62560e1e7c36e0f22f6104b264ffffffffff604060002054169261041c8415156133c8565b6000848152609a602052604090205461045090610449906001600160a01b03165b6001600160a01b031690565b3314613372565b61047e8461047861046e6104638561053d565b5464ffffffffff1690565b64ffffffffff1690565b14613420565b61049861048a8261053d565b805464ffffffffff19169055565b6040516001600160a01b0390911681529081906020820190565b0390a2005b503461000e57602036600319011261000e57606060406000600435815260ce602052205460018060a01b0390818160281c169182156000146105135760005b60405193845216602083015260018060c81b031615156040820152f35b8061053664ffffffffff841664ffffffffff16600052609a602052604060002090565b54166104f6565b6001600160a01b0316600090815260996020526040902090565b503461000e57602036600319011261000e576001600160a01b03610579610350565b166000526066602052602060ff60406000205416604051908152f35b50602036600319011261000e576106786004356105b760018260f81c14612ebd565b6105cb61110061ffff8360081c1614612f09565b6105fb6105da60ff83166141be565b60ff6105f36105ed828660181c166141be565b60ff1690565b911614612f4f565b600081815260ce6020526040902061062f906001600160c81b0390610628905b546001600160c81b031690565b1615612fa5565b610673611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b42908560301c16612d38565b61066d610e108211613053565b10613095565b613d69565b005b503461000e57602036600319011261000e57610694610350565b3360005260996020527fc94089e0c0b1b79fdecc6e64fb759cdd390590a15c7e50d281e681ea8273261c6104b264ffffffffff60406000205416926106da8415156133c8565b6000848152609a60205260409020546106ff90610449906001600160a01b031661043d565b6107128461047861046e6104638561053d565b610750816107318664ffffffffff16600052609a602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b604080513381526001600160a01b03909216602083015290918291820190565b6024359064ffffffffff8216820361000e57565b6044359064ffffffffff8216820361000e57565b503461000e57604036600319011261000e576004356107b5610770565b600082815260ce60205260409020546001600160c81b0381169291906107dd6001851161353f565b64ffffffffff80911661086a5760009361080c61084093836108016104633361053d565b91169316831461386b565b176108218360005260ce602052604060002090565b80546001600160c81b0319166001600160c81b03909216919091179055565b604051907f60a99b51ae498c44acbbe11031aed2a06a32be66d2122e6e2a7a16c087865cc98383a2f35b60405162461bcd60e51b815260206004820152601b60248201527f5377617020626f6e64656420746f20616e6f7468657220706f6f6c00000000006044820152606490fd5b503461000e57602036600319011261000e576108c9610350565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169190610902308414156125ee565b61091f600080516020614e0583398151915293828554161461264f565b61092f8161013454163314612b37565b6040519061093c82610c26565b600082527f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156109765750506106789150612779565b6020600491604094939451928380926352d1902d60e01b825286165afa600091816109d1575b506109be5760405162461bcd60e51b8152806109ba6004820161272a565b0390fd5b610678936109cc91146126cc565b612809565b6109f391925060203d81116109fa575b6109eb8183610c69565b8101906126b0565b903861099c565b503d6109e1565b604090600319011261000e576004359060243565ffffffffffff8116810361000e5790565b50610a3036610a01565b610a3b82151561323e565b64ffffffffff80821690610a50821515613284565b3360005260996020526040600020541603610ac75765ffffffffffff81610a977f7d7d1df74ef3a6434d8d63dc0a25d13d5fa94dbe738c38a3cce26e6f892e2a7693612d08565b610aa2858254612d71565b9055610ab5843360ff8460281c166147c2565b604051938452169180602081016104b2565b60405162461bcd60e51b815260206004820152602860248201527f4e65656420616e20617574686f72697a65642061646472657373206173207468604482015267329039b4b3b732b960c11b6064820152608490fd5b503461000e57604036600319011261000e57610b37610350565b610b83610b42610366565b60005492610b6760ff8560081c161580958196610c01575b8115610be1575b50613db7565b83610b7a600160ff196000541617600055565b610bc857613e1a565b610b8957005b610b9961ff001960005416600055565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a1005b610bdc61010061ff00196000541617600055565b613e1a565b303b15915081610bf3575b5038610b61565b6001915060ff161438610bec565b600160ff8216109150610b5a565b50634e487b7160e01b600052604160045260246000fd5b602081019081106001600160401b03821117610c4157604052565b610c49610c0f565b604052565b606081019081106001600160401b03821117610c4157604052565b90601f801991011681019081106001600160401b03821117610c4157604052565b6020906001600160401b038111610ca7575b601f01601f19160190565b610caf610c0f565b610c9c565b50604036600319011261000e57610cc9610350565b602435906001600160401b03821161000e573660238301121561000e57816004013590610cf582610c8a565b91610d036040519384610c69565b808352366024828601011161000e576020816000926024610678970183870137840101526129a7565b503461000e57608036600319011261000e576000600435610e68610d7a610d5161037c565b610d6060018560f81c14612ebd565b610d7461110061ffff8660201c1614612f09565b83613e27565b610daa6001600160501b03610628610d9d84600052610101602052604060002090565b546001600160501b031690565b610e4d610db96104633361053d565b69ffffffffff000000000064ffffffffff80831692610dd9841515613481565b610dfa610df3610de842612d45565b938a60301c16612d20565b83106134e5565b610e0388613e46565b610e22610e1a8660ff60281b8c60101b1617612d08565b918254612d38565b9055610e2d88614039565b9081610e92575b505060281b161791600052610101602052604060002090565b906001600160501b03166001600160501b0319825416179055565b604051907fbfb879c34323c5601fafe832c3a8a1e31e12c288695838726ddeada86034edb48383a2f35b60016000526066602052610edd90610e1a90610ed890610ec2600080516020614de58339815191525b5460ff1690565b60281b60ff60281b1664ffffffffff9091161790565b612d08565b90553880610e34565b503461000e57600036600319011261000e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003610f4557604051600080516020614e058339815191528152602090f35b0390f35b60405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608490fd5b503461000e57602036600319011261000e57600435600081815260ce602052604081205490919061103790610feb60016001600160c81b0383161161353f565b64ffffffffff61100142828660301c1610613c81565b83855260ce6020526040852080546001600160c81b031916905560d084901c169060281c6001600160a01b031660ff8416614907565b604051907ff6b6b4f7a13f02512c1b3aa8dcc4a07d7775a6a4becbd439efcbd37c5408e67f8383a2f35b503461000e57604036600319011261000e576000600435610e68610d7a610d51610366565b503461000e57604036600319011261000e576110a0610366565b6110ae600091600435613e27565b81526101016020526040812054906001600160501b0382166001036110f857505060016000905b604080516001600160a01b0392909216825264ffffffffff929092166020820152f35b64ffffffffff8281168252609a60205260409091205460289290921c16906001600160a01b03166110d5565b602435906001600160c81b038216820361000e57565b606435906001600160c81b038216820361000e57565b50606036600319011261000e5761067860043561116b611124565b611173610392565b9161118360018260f81c14612ebd565b61119761110061ffff8360081c1614612f09565b6111a66105da60ff83166141be565b600081815260ce602052604090206111ca906001600160c81b03906106289061061b565b6111ef611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b613be2565b6004359060ff8216820361000e57565b503461000e57606036600319011261000e5761121e6111f4565b6024359061122a610784565b610134546001600160a01b03929164ffffffffff9161124c9085163314612b37565b169182600052609a602052604060002054161561129c576112989160ff60281b6112909260281b1661127d81612d08565b611288868254612d38565b905517612d08565b918254612d71565b9055005b60405162461bcd60e51b8152602060048201526019602482015278141bdbdb081a5b99195e081b9bdd081c9959da5cdd195c9959603a1b6044820152606490fd5b608090600319011261000e57600435906024356001600160a01b038116810361000e57906044359060643590565b503461000e5761067861131d366112dd565b9261133060018260f89594951c14612ebd565b61134461110061ffff8360081c1614612f09565b6113536105da60ff83166141be565b600081815260ce60205260409020611377906001600160c81b03906106289061061b565b61139c611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b6130d6565b503461000e57602036600319011261000e576001600160a01b036113c3610350565b166000526099602052602064ffffffffff60406000205416604051908152f35b8015150361000e57565b503461000e5760a036600319011261000e57600060043561140c61037c565b608435611418816113e3565b61142f61061b8460005260ce602052604060002090565b61144460016001600160c81b0383161161353f565b61144d42612d54565b906114ab64ffffffffff948593848860301c161088146115485761148e61147e8860005260ce602052604060002090565b80546001600160c81b0319169055565b602883901c6001600160a01b0316906044359060243590896142f7565b16908414611504576114ca6114d79160ff60281b8560281b1617612d08565b918360d01c168254612d71565b90555b604051907f8d92c805c252261fcfff21ee60740eb8a38922469a7e6ee396976d57c22fc1c98383a2f35b906115336115266115439364ffffffffff16600052609a602052604060002090565b546001600160a01b031690565b908360d01c169060ff8416614907565b6114da565b61157261155f8860005260ce602052604060002090565b80546001600160c81b0319166001179055565b61148e565b503461000e57602036600319011261000e5760043564ffffffffff811680910361000e57600052609a602052602060018060a01b0360406000205416604051908152f35b503461000e57602036600319011261000e5760ff60281b6115da6111f4565b60281b16600052609b6020526020604060002054604051908152f35b5065ffffffffffff7f7d7d1df74ef3a6434d8d63dc0a25d13d5fa94dbe738c38a3cce26e6f892e2a7661162836610a01565b611635829492151561323e565b64ffffffffff8116611648811515613284565b61167760018060a01b036116706115268464ffffffffff16600052609a602052604060002090565b16156132d0565b61168f61168961046e6104633361053d565b1561331c565b6116ae336107318364ffffffffff16600052609a602052604060002090565b6116d2816116bb3361053d565b9064ffffffffff1664ffffffffff19825416179055565b6116db82612d08565b6116e6868254612d71565b90556116f9853360ff8560281c166147c2565b6040513381527fb8d9c35a714d4e29eaf036b9bf8183a093c5573ac809453b4e8434e25c9126d290602090a2604051938452169180602081016104b2565b503461000e5760006117cc61103761174e366112dd565b83875260ce6020526040872054939592939192919061177860016001600160c81b0384161161353f565b64ffffffffff9361178f42868a60301c1610613c81565b60405160208101906117b4816117a68a8d86613220565b03601f198101835282610c69565b51902060289390931c6001600160a01b031692614509565b6117e361147e8560005260ce602052604060002090565b8360d01c169060ff8416614907565b60a090600319011261000e576004359060243590604435906001600160a01b0390606435828116810361000e5791608435908116810361000e5790565b503461000e5760006118fc6119386118e6611849366117f2565b93969194909261185a3233146135c2565b61186f4264ffffffffff8a60301c1611613619565b6118836001600160a01b03861615156131d5565b6118d584600160ce1b8a16159788156119e0575b6118a1828c613e27565b936118ce60016001600160501b036118c7610d9d89600052610101602052604060002090565b161161353f565b888c6142f7565b600052610101602052604060002090565b805469ffffffffffffffffffff19166001179055565b61190585613e46565b926119b0575b611914856140a4565b80611972575b5061192485614039565b80611962575b5060ff8560181c1685613665565b604051907ffa628b578e095243f0544bfad9255f49d79d03a5bbf6c85875d05a215e247ad28383a2f35b61196c90836149e1565b3861192a565b928361197d91612d38565b926119a8611290610ed861199089614158565b899064ffffffffff60ff60281b91169160101b161790565b90553861191a565b6119c36119bc86613ef4565b8094612d38565b926119d961129060ff60281b8860101b16612d08565b905561190b565b610135546119f8906001600160a01b03163314612cb2565b611897565b503461000e576000611938611a11366117f2565b91611a2460018660f89897981c14612ebd565b611a3861110061ffff8860201c1614612f09565b611a433233146135c2565b611a576001600160a01b03841615156131d5565b85611ae26118e6600160ce1b831615968715611c11575b611a788685613e27565b90611a9c6001600160501b03610628610d9d85600052610101602052604060002090565b86611aa96104633361053d565b9664ffffffffff928a848a1698611ac18a1515613481565b8d8315611be85750611add6118d59642908360301c1611613619565b6142f7565b611aeb87613e46565b94611b0160ff60281b8960101b16928317612d08565b611b0c878254612d38565b9055611bc7575b50611b1d866140a4565b80611b89575b50611b2d86614039565b80611b42575b505060ff8560181c1685613665565b60016000526066602052611b8291611b6f90610ed890610ec2600080516020614de5833981519152610ebb565b611b7a828254612d38565b9055836149e1565b3880611b33565b9384611b9491612d38565b93611bbf611290610ed8611ba78a614158565b8a9064ffffffffff60ff60281b91169160101b161790565b905538611b23565b93611be0611290611bda6119bc8a613ef4565b96612d08565b905538611b13565b95505050505050156118d55761013554611c0c906001600160a01b03163314612cb2565b6118d5565b61013554611c29906001600160a01b03163314612cb2565b611a6e565b503461000e57602036600319011261000e57610678611c4b610350565b61013554611c63906001600160a01b03163314612cb2565b612e17565b6020906001600160401b038111611c81575b60051b0190565b611c89610c0f565b611c7a565b81601f8201121561000e57803591611ca583611c68565b92611cb36040519485610c69565b808452602092838086019260051b82010192831161000e578301905b828210611cdd575050505090565b813560ff8116810361000e578152908301908301611ccf565b503461000e57604036600319011261000e576001600160401b0360043581811161000e573660238201121561000e578060040135611d3381611c68565b91611d416040519384610c69565b81835260209160248385019160051b8301019136831161000e57602401905b828210611d89576024358587821161000e57611d83610678923690600401611c8e565b90612b7d565b838091611d95846103a8565b815201910190611d60565b503461000e57608036600319011261000e57610678600435611dc061113a565b90611dd060018260f81c14612ebd565b611de461110061ffff8360081c1614612f09565b611df36105da60ff83166141be565b600081815260ce60205260409020611e17906001600160c81b03906106289061061b565b611e3c611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b60443590602435906138d8565b50610678611e56366117f2565b93611e6960018260f89694961c14612ebd565b611e7d61110061ffff8360081c1614612f09565b611e8c6105da60ff83166141be565b600081815260ce60205260409020611eb0906001600160c81b03906106289061061b565b611ed5611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b613cc4565b503461000e57602036600319011261000e57611ef46111f4565b610134546001600160a01b0390611f0e9082163314612b37565b60ff8216611f1d811515614bb3565b6000526065602052604060002054168015611f7d576001600160a01b03166000908152606660205260409020805460ff1916905561067890611f6d905b60ff166000526065602052604060002090565b80546001600160a01b0319169055565b60405162461bcd60e51b815260206004820152602260248201527f546f6b656e20666f722074686520696e64657820646f6573206e6f74206578696044820152611cdd60f21b6064820152608490fd5b503461000e5765ffffffffffff7f34c3d1c46f89307d63d8818fcc5c2a9c07a5f7a01ea4319bfba1899f40c6f40061200436610a01565b612011829492151561323e565b64ffffffffff8116612024811515613284565b600052609a60205261204460018060a01b03604060002054163314613372565b61204d81612d08565b80549085820391821161206d575b55610ab5843360ff8460281c16614907565b612075612c53565b61205b565b6040810190604081528251809252606081019160208094019060005b8181106120db575050508281830391015281808451928381520193019160005b8281106120c4575050505090565b835160ff16855293810193928101926001016120b6565b82516001600160a01b031685529385019391850191600101612096565b503461000e576000806003193601126122115780805b60ff80821610156121535761212b61043d611526611f5a846141ac565b61213e575b61213990612c6a565b61210e565b9161214b61213991612c6a565b929050612130565b5060ff8092169061216c61216683614b81565b92614b81565b92815b818082161061218a57505050610f416040519283928361207a565b61219c61043d611526611f5a846141ac565b6121af575b6121aa90612c6a565b61216f565b916122096121aa916122046121c9611526611f5a886141ac565b6121e9868416916121da838b612c88565b6001600160a01b039091169052565b6121fc6121f5886141ac565b918a612c88565b9060ff169052565b612c6a565b9290506121a1565b80fd5b503461000e57604036600319011261000e576020612241612233610350565b61223b610366565b906145c3565b604051908152f35b503461000e57604036600319011261000e57612263610350565b60243560ff8116810361000e576106789161228a60018060a01b0361013454163314612b37565b614ce3565b50604036600319011261000e576106786004356122aa611124565b906122ba60018260f81c14612ebd565b6122ce61110061ffff8360081c1614612f09565b6122dd6105da60ff83166141be565b600081815260ce60205260409020612301906001600160c81b03906106289061061b565b612326611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b613b44565b503461000e57600036600319011261000e57604051601160f81b8152602090f35b503461000e57604036600319011261000e57600060043561241761240461237a612374610366565b84613e27565b612392610d9d82600052610101602052604060002090565b6123a760016001600160501b0383161161353f565b64ffffffffff906123be42838360281c1610613581565b166123c885613e46565b6123df6112908360ff60281b8960101b1617612d08565b90556123ea85614039565b9081612441575b5050600052610101602052604060002090565b805469ffffffffffffffffffff19169055565b604051907fac7d23c4f0137a4cc35b0e4b4bc8061ea6cb65805e87ceb0a77ca0c85814858c8383a2f35b6001600052606660205261246e9061129090610ed890610ec2600080516020614de5833981519152610ebb565b905538806123f1565b503461000e57602036600319011261000e57610678612494610350565b6124aa60018060a01b0361013454163314612b37565b612d7e565b503461000e57602036600319011261000e576124c9610350565b6001600160a01b03811660009081526099602052604090205464ffffffffff91908216612560576104b27fd49cde4f679ccef3d23ff07aae4f6845e1c661e23e9fe6a54da26f0723fb695f916104986125246104633361053d565b948516946125338615156133c8565b61255761044961043d6115268464ffffffffff16600052609a602052604060002090565b6116bb8361053d565b60405162461bcd60e51b815260206004820152602360248201527f4164647220697320617574686f72697a656420666f7220616e6f7468657220706044820152621bdbdb60ea1b6064820152608490fd5b503461000e57602036600319011261000e5760ff6125cd6111f4565b166000526065602052602060018060a01b0360406000205416604051908152f35b156125f557565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1561265657565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b9081602091031261000e575190565b506040513d6000823e3d90fd5b156126d357565b60405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b60809060208152602e60208201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960408201526d6f6e206973206e6f74205555505360901b60608201520190565b803b156127ae57600080516020614e0583398151915280546001600160a01b0319166001600160a01b03909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b61281281612779565b6040516001600160a01b0382167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600083a2825115801590612919575b61285857505050565b813b156128c85750600082819260206128c595519201905af4612879612977565b6040519161288683610c4e565b602783527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c6020840152660819985a5b195960ca1b6040840152612abc565b50565b62461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608490fd5b50600061284f565b61292a81612779565b6040516001600160a01b0382167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600083a282511580159061296f5761285857505050565b50600161284f565b3d156129a2573d9061298882610c8a565b916129966040519384610c69565b82523d6000602084013e565b606090565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811692906129e0308514156125ee565b6129fd600080516020614e0583398151915294828654161461264f565b612a0d8161013454163314612b37565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612a45575050612a439150612779565b565b6020600491604094939451928380926352d1902d60e01b825286165afa60009181612a9c575b50612a895760405162461bcd60e51b8152806109ba6004820161272a565b612a4393612a9791146126cc565b612921565b612ab591925060203d81116109fa576109eb8183610c69565b9038612a6b565b90919015612ac8575090565b815115612ad85750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b828510612b1e575050604492506000838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350612afb565b15612b3e57565b60405162461bcd60e51b815260206004820152601760248201527621b0b63632b91034b9903737ba103a34329037bbb732b960491b6044820152606490fd5b9091612b9560018060a01b0361013454163314612b37565b8151835103612bf75760005b825160ff821690811015612bf0579061220482612be5612bde612bd7612bca612beb978a612c88565b516001600160a01b031690565b9289612c88565b5160ff1690565b90614ce3565b612ba1565b5050915050565b60405162461bcd60e51b815260206004820152602e60248201527f546f6b656e7320616e6420696e64657865732073686f756c642068617665207460448201526d0d0ca40e6c2daca40d8cadccee8d60931b6064820152608490fd5b50634e487b7160e01b600052601160045260246000fd5b60ff6001911660ff8114612c7c570190565b612c84612c53565b0190565b8051821015612c9c5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b15612cb957565b60405162461bcd60e51b815260206004820152602160248201527f43616c6c6572206973206e6f7420746865207072656d69756d206d616e6167656044820152603960f91b6064820152608490fd5b65ffffffffffff16600052609b602052604060002090565b61012b19810191908211612d3057565b612a43612c53565b91908203918211612d3057565b906104b08201809211612d3057565b90610e108201809211612d3057565b90601b8201809211612d3057565b91908201809211612d3057565b6001600160a01b03908116908115612dd35761013480546001600160a01b0319811684179091556040519116907f8934ce4adea8d9ce0d714d2c22b86790e41b7731c84b926fbbdc1d40ff6533c990600090a3565b606460405162461bcd60e51b815260206004820152602060248201527f4e6577206f776e65722063616e6e6f74206265207a65726f20616464726573736044820152fd5b6001600160a01b03908116908115612e6c5761013580546001600160a01b0319811684179091556040519116907f4798f31ad3d0ccde6359edf35fc39b882e4e1cff2968ca749b72074d373db27a90600090a3565b60405162461bcd60e51b815260206004820152602360248201527f4e6577207072656d69756d206d616e61676572206265207a65726f206164647260448201526265737360e81b6064820152608490fd5b15612ec457565b60405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420656e636f64696e672076657273696f6e0000000000006044820152606490fd5b15612f1057565b60405162461bcd60e51b815260206004820152601760248201527629bbb0b8103737ba103337b9103a3434b99031b430b4b760491b6044820152606490fd5b15612f5657565b60405162461bcd60e51b815260206004820152602160248201527f496e2026206f757420746f6b656e20747970657320646f206e6f74206d6174636044820152600d60fb1b6064820152608490fd5b15612fac57565b60405162461bcd60e51b81526020600482015260136024820152725377617020616c72656164792065786973747360681b6044820152606490fd5b15612fee57565b60405162461bcd60e51b815260206004820152603760248201527f466f7220736563757269747920726561736f6e2c20616d6f756e742063616e6e6044820152766f742062652067726561746572207468616e203130306b60481b6064820152608490fd5b1561305a57565b60405162461bcd60e51b815260206004820152601360248201527245787069726520747320746f6f206561726c7960681b6044820152606490fd5b1561309c57565b60405162461bcd60e51b815260206004820152601260248201527145787069726520747320746f6f206c61746560701b6044820152606490fd5b926131ac92613135916130f361110061ffff8860201c1614612f09565b6131076001600160a01b03851615156131d5565b604051602081019061311e816117a6888b86613220565b519020610135546001600160a01b03169290614509565b64ffffffffff9061319e613154838660d01c16938660581c1684612d38565b92613187600160ff60281b61316f82828b60281b1617612d08565b61317a858254612d71565b90558860101b1617612d08565b613192858254612d38565b90553360ff87166147c2565b3360ff8560181c1685613665565b7ffa628b578e095243f0544bfad9255f49d79d03a5bbf6c85875d05a215e247ad26000604051a2565b156131dc57565b606460405162461bcd60e51b815260206004820152602060248201527f526563697069656e742063616e6e6f74206265207a65726f20616464726573736044820152fd5b90815260609190911b6001600160601b031916602082015260340190565b1561324557565b60405162461bcd60e51b8152602060048201526017602482015276416d6f756e74206d75737420626520706f73697469766560481b6044820152606490fd5b1561328b57565b60405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f7420757365203020617320706f6f6c20696e6465780000000000006044820152606490fd5b156132d757565b60405162461bcd60e51b815260206004820152601d60248201527f506f6f6c20696e64657820616c726561647920726567697374657265640000006044820152606490fd5b1561332357565b60405162461bcd60e51b815260206004820152602160248201527f5369676e6572206164647265737320616c7265616479207265676973746572656044820152601960fa1b6064820152608490fd5b1561337957565b60405162461bcd60e51b815260206004820152602160248201527f4e6565642074686520706f6f6c206f776e657220617320746865207369676e656044820152603960f91b6064820152608490fd5b156133cf57565b60405162461bcd60e51b815260206004820152602360248201527f546865207369676e657220646f6573206e6f74207265676973746572206120706044820152621bdbdb60ea1b6064820152608490fd5b1561342757565b60405162461bcd60e51b815260206004820152602c60248201527f41646472206973206e6f7420617574686f72697a656420666f7220746865207360448201526b1a59db995c89dcc81c1bdbdb60a21b6064820152608490fd5b1561348857565b60405162461bcd60e51b815260206004820152602f60248201527f43616c6c6572206e6f7420726567697374657265642e2043616c6c206465706f60448201526e39b4ba20b7322932b3b4b9ba32b91760891b6064820152608490fd5b156134ec57565b60405162461bcd60e51b815260206004820152602560248201527f43616e6e6f74206c6f636b20626563617573652065787069726554732069732060448201526439b7b7b71760d91b6064820152608490fd5b1561354657565b60405162461bcd60e51b815260206004820152601360248201527214ddd85c08191bd95cc81b9bdd08195e1a5cdd606a1b6044820152606490fd5b1561358857565b60405162461bcd60e51b815260206004820152601260248201527153776170207374696c6c20696e206c6f636b60701b6044820152606490fd5b156135c957565b60405162461bcd60e51b815260206004820152602260248201527f43616e6e6f742062652063616c6c6564207468726f75676820636f6e74726163604482015261747360f01b6064820152608490fd5b1561362057565b60405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f742072656c656173652062656361757365206578706972656400006044820152606490fd5b9093929190600160cf1b8116613856576001600160401b036136a19160801c1693613692843b1515614a58565b61369b86614aba565b90613ee1565b936136ab81614b41565b15613740575060405163bff4163f60e01b815260006004820152602481018590526001600160a01b0391821660448201526001600160401b039390931660648401529192602092849260849284929091165af18015613733575b61370c5750565b6128c59060203d811161372c575b6137248183610c69565b810190614713565b503d61371a565b61373b6126bf565b613705565b61152661375a9160ff166000526065602052604060002090565b91613767833b15156146b5565b60405163095ea7b360e01b81526001600160a01b038281166004830152602482018790526020968795909260009291908781604481878688165af18015613849575b61382c575b5060405163bff4163f60e01b81526001600160a01b03918216600482015260248101949094529490941660448301526001600160401b03959095166064820152938492608492849291165af1801561381f575b613809575050565b816128c592903d1061372c576137248183610c69565b6138276126bf565b613801565b61384290883d8a1161372c576137248183610c69565b50386137ae565b6138516126bf565b6137a9565b50508161386257505050565b612a4392614907565b1561387257565b60405162461bcd60e51b815260206004820152603860248201527f5369676e65722073686f756c6420626520616e20617574686f72697a6564206160448201527719191c995cdcc81bd9881d1a194819da5d995b881c1bdbdb60421b6064820152608490fd5b9290613a2b613a3a93926020600060018060a01b038360281c169564ffffffffff9586851680151580613b3a575b613b1e575b5061391788151561426b565b6001600160ff1b038216916139f190613936906105ed9060ff1c612d63565b926139596fa2a8918ca85bafe22016d0b997e4df60600160ff1b038211156142b7565b600160cb1b8c1615158560088e901c61ffff1660c3148114613a9957508514613a7057780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519998560391b6117a66139c68e5b6040519283918b83019586909160399266ffffffffffffff1916825260198201520190565b519020925b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15613a63575b600051613a17906001600160a01b031685146142b7565b6108218660005260ce602052604060002090565b8360d01c169060ff84166147c2565b7f5ce4019f772fda6cb703b26bce3ec3006eb36b73f1d3a0eb441213317d9f5e9d6000604051a2565b613a6b6126bf565b613a00565b780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519990560391b6117a66139c68e6139a1565b908614613ae957508b604051613ae0816117a68a82019485603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b519020926139cb565b808d6040925287812088527f9862d877599564bcd97c37305a7b0fdbe621d9c2a125026f2ad601f754a75abc815220926139cb565b613b349088613b2c3361053d565b54161461386b565b3861390b565b5088331415613906565b90602881901c6001600160a01b031633819003613b8b57613b76613a3a926108218560005260ce602052604060002090565b64ffffffffff8360d01c169060ff84166147c2565b60405162461bcd60e51b815260206004820152602960248201527f5472616e73616374696f6e2073686f756c642062652073656e742066726f6d2060448201526834b734ba34b0ba37b960b91b6064820152608490fd5b916001600160a01b0381163303613c2457613b76613a3a928460005260ce60205260406000209060018060c81b031666ffffffffffffff60c81b825416179055565b60405162461bcd60e51b815260206004820152602f60248201527f5472616e73616374696f6e2073686f756c642062652073656e742066726f6d2060448201526e636f6e74726163744164647265737360881b6064820152608490fd5b15613c8857565b60405162461bcd60e51b815260206004820152601460248201527314ddd85c081a5cc81cdd1a5b1b081b1bd8dad95960621b6044820152606490fd5b93928092613cd692613d3395876142f7565b600083815260ce6020526040902080546001600160c81b031916600117905564ffffffffff8360d01c1690600160ff60281b8560281b1617600052609b6020526040600020805490838201809211613d5c575b5560ff84166147c2565b7f8d92c805c252261fcfff21ee60740eb8a38922469a7e6ee396976d57c22fc1c96000604051a2565b613d64612c53565b613d29565b613d3364ffffffffff8260d01c16600160ff60281b8460281b1617600052609b6020526040600020805490828201809211613daa575b553360ff84166147c2565b613db2612c53565b613d9f565b15613dbe57565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b90611c63612a4392612d7e565b90613e406117a691604051928391602083019586613220565b51902090565b613e6a64ffffffffff91828160d01c16928160581c168303928311613e8157613fa2565b8103908111613e765790565b613e7e612c53565b90565b613e89612c53565b613fa2565b6005908060001904821181151516613ea4570290565b613eac612c53565b0290565b6103e8908060001904821181151516613ea4570290565b64e8d4a51000908060001904821181151516613ea4570290565b8060001904821181151516613ea4570290565b60ff811660fc8110613f355750613f23613f1b64ffffffffff6101f4935b60d01c16613e8e565b612710900490565b9080821115613f30575090565b905090565b60f88110613f535750613f23613f1b64ffffffffff61138893613f12565b60f48110613f715750613f23613f1b64ffffffffff6101f493613f12565b60f011613f8c57613f23613f1b64ffffffffff600a93613f12565b613f23613f1b64ffffffffff6207a12093613f12565b60bf60ff8260181c161080614029575b613fbc5750600090565b61ffff90818160a01c16918214613fdf5750613fda613e7e916140eb565b613eb0565b905064ffffffffff90818160d01c16918160581c16820391821161401c575b600160ce1b81161561400e575090565b61401790613ef4565b613e6a565b614024612c53565b613ffe565b5061084160c41b81811614613fb2565b61404281613fa2565b90811515908161405457505050600090565b61ffff61407591612710938560001904851116614097575b60b01c166140eb565b91821561408157020490565b634e487b7160e01b600052601260045260246000fd5b61409f612c53565b61406c565b6140ad816140c7565b6140b75750600090565b61ffff613e7e9160a01c166140eb565b600160cf1b8116151590816140da575090565b600360c91b16600160c91b14919050565b6103e88082111561415457613e7e916103e7198101908111614147575b6123289081810692830180931161413a575b04604d811161412d575b600a0a90613ee1565b614135612c53565b614124565b614142612c53565b61411a565b61414f612c53565b614108565b5090565b614161816140c7565b61416b5750600090565b60b01c61ffff16620100000164ffffffffff8111613e765790565b60ff604f199116019060ff8211612d3057565b60ff601f199116019060ff8211612d3057565b60ff60019116019060ff8211612d3057565b60ff811660c081106141d4575060021c603f1690565b604081116141e3575050600090565b6070811161420957506142046141fb613e7e926141ac565b60011c607f1690565b614199565b608010156142625760405162461bcd60e51b8152602060048201526024808201527f546f6b656e20696e646578206e6f7420616c6c6f77656420666f72207377617060448201526370696e6760e01b6064820152608490fd5b613e7e90614186565b1561427257565b60405162461bcd60e51b815260206004820152601e60248201527f5369676e65722063616e6e6f7420626520656d707479206164647265737300006044820152606490fd5b156142be57565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b612a43946001600160a01b0316936020936000939290916143e39161431d88151561426b565b6001600160ff1b03821691614338906105ed9060ff1c612d63565b9461435b6fa2a8918ca85bafe22016d0b997e4df60600160ff1b038411156142b7565b600160cb1b8216151561ffff88600885901c821660c3148114614438575050871461441157780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d051a998560391b916139c6905b6117a66040519384928c8401968791604d939166ffffffffffffff1916835260198301526bffffffffffffffffffffffff199060601b1660398201520190565b838052039060015afa15614404575b6000516001600160a01b0316146142b7565b61440c6126bf565b6143f2565b780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519990560391b916139c6906143a3565b90939291891461449a57506040517f19457468657265756d205369676e6564204d6573736167653a0a3532000000008a8201908152601c81019390935260609190911b6001600160601b031916603c830152909150613ae081605084016117a6565b9160c3604094828c1c161489146144e2577f28cf5b919ed55db2b14d9e8b261a523eafb98bab117d3a8a56e559791415d17c915b6014528252603482208952815220926139cb565b7f743e50106a7f059b52151dd4ba27a5f6c87b925ddfbdcf1c332e800da4b3df92916144ce565b600060ff602092614590612a4397959660018060a01b038097169761452f89151561426b565b600180861b03821691851c93601b85018095116145b6575b6145686fa2a8918ca85bafe22016d0b997e4df606001881b038411156142b7565b6040519586951690859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156145a9575b60005116146142b7565b6145b16126bf565b61459f565b6145be612c53565b614547565b60018060a01b0380911660005260666020526040600020549116600052609960205264ffffffffff604060002054168015801561461d575b6146165760ff60281b6146129260281b1617612d08565b5490565b5050600090565b5060ff8216156145fb565b1561462f57565b606460405162461bcd60e51b815260206004820152602060248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152fd5b1561467a57565b60405162461bcd60e51b8152602060048201526013602482015272151bdad95b881b9bdd081cdd5c1c1bdc9d1959606a1b6044820152606490fd5b156146bc57565b60405162461bcd60e51b815260206004820152602960248201527f54686520676976656e20746f6b656e2061646472657373206973206e6f7420616044820152680818dbdb9d1c9858dd60ba1b6064820152608490fd5b9081602091031261000e5751613e7e816113e3565b1561472f57565b60405162461bcd60e51b81526020600482015260136024820152721d1c985b9cd9995c919c9bdb4819985a5b1959606a1b6044820152606490fd5b1561477157565b60405162461bcd60e51b815260206004820152602360248201527f6d73672e76616c756520646f6573206e6f74206d617463682074686520616d6f6044820152621d5b9d60ea1b6064820152608490fd5b906147ce831515614628565b6147d782614b41565b156147f15750506147ea612a4391613ec7565b341461476a565b8160009291836117a6614882614848612a439861369b614822611526879a60ff166000526065602052604060002090565b976148376001600160a01b038a161515614673565b614843893b15156146b5565b614aba565b6040516323b872dd60e01b602082019081526001600160a01b03909616602482015230604482015260648101919091529182906084820190565b51925af161488e612977565b8161489a575b50614728565b80518015925082156148af575b505038614894565b6148c29250602080918301019101614713565b38806148a7565b156148d057565b60405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b91909161491381614b41565b156149225750612a43916149e1565b60009190612a4393836117a661499a614966839661369b60018060a01b036149578960ff166000526065602052604060002090565b541697614843893b15156146b5565b60405163a9059cbb60e01b602082019081526001600160a01b03909616602482015260448101919091529182906064820190565b51925af16149a6612977565b816149b2575b506148c9565b80518015925082156149c7575b5050386149ac565b6149da9250602080918301019101614713565b38806149bf565b60008092819264e8d4a5100082841904811183151516614a4b575b6040519202905af1614a0c612977565b5015614a1457565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b614a53612c53565b6149fc565b15614a5f57565b60405162461bcd60e51b815260206004820152602d60248201527f54686520676976656e20726563697069656e742061646472657373206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b60ff1660208111614acb5750600190565b60f2811480614b39575b80614b31575b15614ae65750606490565b6070811180614b26575b15614afb5750606490565b607b81119081614b1a575b50614b145764e8d4a5100090565b6103e890565b60809150111538614b06565b50607b811115614af0565b506001614adb565b506001614ad5565b60ff81169060318210159182614b75575b8215614b5d57505090565b60be10915081614b6b575090565b6003915081161490565b60408111159250614b52565b90614b8b82611c68565b614b986040519182610c69565b8281528092614ba9601f1991611c68565b0190602036910137565b15614bba57565b60405162461bcd60e51b815260206004820152601b60248201527f43616e6e6f7420757365203020617320746f6b656e20696e64657800000000006044820152606490fd5b15614c0657565b60405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20686173206265656e206164646564206265666f726500000000006044820152606490fd5b15614c5257565b60405162461bcd60e51b8152602060048201526013602482015272125b99195e081a185cc81899595b881d5cd959606a1b6044820152606490fd5b15614c9457565b60405162461bcd60e51b815260206004820152602160248201527f436f726520746f6b656e207265717569726573206164646472657373283078316044820152602960f81b6064820152608490fd5b614cf160ff83161515614bb3565b6001600160a01b0381168015614da557612a439261073191614d34614d2e6105ed610ebb8760018060a01b03166000526066602052604060002090565b15614bff565b614d5a614d5461043d6115268560ff166000526065602052604060002090565b15614c4b565b614d6382614b41565b614d93575b506001600160a01b0383166000908152606660205260409020805460ff191660ff8316179055611f5a565b6001614d9f9114614c8d565b38614d68565b60405162461bcd60e51b815260206004820152601760248201527643616e6e6f7420757365207a65726f206164647265737360481b6044820152606490fdfee34b8b74e1cdcaa1b90aa77af7dd89e496ad9a4ae4a4d4759712101c7da2dce6360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca164736f6c6343000810000a000000000000000000000000666d6b8a44d226150ca9058beebafe0e3ac065a2
Deployed Bytecode
0x608060405236156054577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e156050573d90f35b3d90fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e156050573d90f3fea164736f6c6343000810000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000666d6b8a44d226150ca9058beebafe0e3ac065a2
-----Decoded View---------------
Arg [0] : premiumManager (address): 0x666d6b8a44d226150ca9058bEEbafe0e3aC065A2
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000666d6b8a44d226150ca9058beebafe0e3ac065a2
Loading...
Loading
OVERVIEW
This is a contract on ArbLoading...
Loading
Net Worth in USD
$3,153,601.31
Net Worth in M
Token Allocations
M
28.55%
MEME
20.58%
WBTC
8.62%
Others
42.26%
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| BSC | 28.55% | $1.54 | 584,599.1726 | $900,282.73 | |
| BSC | 2.93% | $68,129.69 | 1.3556 | $92,355.31 | |
| BSC | 2.45% | $76,284 | 1.0147 | $77,408.12 | |
| BSC | 1.51% | $1 | 47,744.479 | $47,747.15 | |
| BSC | 1.22% | $0.999917 | 38,401.8016 | $38,398.61 | |
| BSC | 1.14% | $0.060532 | 594,231.9971 | $35,970.05 | |
| BSC | 0.87% | $76,043 | 0.3589 | $27,293.96 | |
| BSC | 0.42% | $1.86 | 7,097.6692 | $13,230.44 | |
| BSC | 0.18% | $0.999443 | 5,705.8181 | $5,702.64 | |
| BSC | 0.08% | $623.12 | 3.826 | $2,384.05 | |
| BSC | 0.04% | $0.998581 | 1,346.7658 | $1,344.85 | |
| BSC | <0.01% | $1 | 67.8102 | $67.82 | |
| BSC | <0.01% | $0.700001 | 11 | $7.7 | |
| BSC | <0.01% | $0.00213 | 300 | $0.6388 | |
| MEMECORE | 20.58% | $1.54 | 422,633.2644 | $648,937.78 | |
| MEMECORE | 0.10% | $0.9999 | 3,097.8314 | $3,097.52 | |
| ETH | 7.05% | $2,133.21 | 104.1517 | $222,177.4 | |
| ETH | 2.89% | $76,149 | 1.1958 | $91,062.4 | |
| ETH | 1.93% | $0.999874 | 60,916.0602 | $60,908.38 | |
| ETH | 1.22% | $0.999903 | 38,487.3884 | $38,483.66 | |
| ETH | 1.17% | $2,017.61 | 18.3125 | $36,947.37 | |
| ETH | 0.36% | $76,043 | 0.1494 | $11,363.03 | |
| ETH | 0.28% | $0.999464 | 8,696.6276 | $8,691.97 | |
| ETH | 0.22% | $0.99985 | 6,864.3905 | $6,863.36 | |
| ETH | 0.19% | $0.060447 | 99,081.7728 | $5,989.2 | |
| ETH | 0.19% | $76,212 | 0.0781 | $5,952.84 | |
| ETH | 0.19% | $67,011.17 | 0.088 | $5,895.58 | |
| ETH | 0.18% | $76,077 | 0.0761 | $5,789.23 | |
| ETH | 0.01% | $75,557 | 0.005541 | $418.66 | |
| ETH | 0.01% | $76,340 | 0.004974 | $379.72 | |
| ETH | <0.01% | $11.89 | 0.0154 | $0.1833 | |
| ARB | 4.66% | $76,177 | 1.9286 | $146,917.32 | |
| ARB | 1.31% | $2,017.26 | 20.5384 | $41,431.35 | |
| ARB | 0.95% | $0.998438 | 30,162.9594 | $30,115.84 | |
| ARB | 0.95% | $76,043 | 0.3932 | $29,896.99 | |
| ARB | 0.78% | $0.999903 | 24,655.6011 | $24,653.21 | |
| ARB | 0.17% | $0.002741 | 2,000,000 | $5,481.05 | |
| ARB | 0.17% | $76,284 | 0.0692 | $5,276.41 | |
| ARB | <0.01% | $29.91 | 0.9907 | $29.63 | |
| ARB | <0.01% | $0.113685 | 85.1747 | $9.68 | |
| BASE | 1.76% | $76,077 | 0.7296 | $55,505.93 | |
| BASE | 0.75% | $0.999903 | 23,596.4422 | $23,594.15 | |
| BASE | 0.74% | $2,017.2 | 11.5804 | $23,359.97 | |
| BASE | <0.01% | $0.000234 | 500 | $0.1172 | |
| AVAX | 0.80% | $76,284 | 0.3306 | $25,222.92 | |
| AVAX | 0.67% | $76,043 | 0.2765 | $21,027.94 | |
| AVAX | 0.65% | $0.999586 | 20,401.3877 | $20,392.94 | |
| AVAX | 0.55% | $1 | 17,378.7558 | $17,379.73 | |
| OP | 1.26% | $2,017.56 | 19.7278 | $39,801.84 | |
| OP | 0.65% | $0.99955 | 20,653.1755 | $20,643.88 | |
| OP | 0.38% | $0.999948 | 11,836.8998 | $11,836.28 | |
| POL | 1.04% | $76,114 | 0.4328 | $32,944.96 | |
| POL | 0.66% | $0.998295 | 20,777.749 | $20,742.32 | |
| POL | 0.36% | $0.999903 | 11,216.5674 | $11,215.48 | |
| POL | 0.07% | $0.110637 | 21,310.6504 | $2,357.76 | |
| SEI | 0.60% | $76,275 | 0.2498 | $19,055.55 | |
| SEI | 0.17% | $1 | 5,385.5828 | $5,385.88 | |
| SCROLL | 0.30% | $2,017.61 | 4.7036 | $9,489.94 | |
| SCROLL | 0.15% | $0.999482 | 4,846.8847 | $4,844.37 | |
| SCROLL | 0.11% | $0.999948 | 3,544.3026 | $3,544.12 | |
| LINEA | 0.24% | $0.999948 | 7,486.312 | $7,485.92 | |
| LINEA | 0.23% | $2,017.61 | 3.5826 | $7,228.28 | |
| LINEA | 0.10% | $0.99955 | 3,116.9422 | $3,115.54 | |
| TAIKO | 0.35% | $76,212 | 0.1453 | $11,075.97 | |
| TAIKO | 0.09% | $0.997143 | 2,925.076 | $2,916.72 | |
| TAIKO | 0.03% | $2,017.93 | 0.4564 | $920.96 | |
| TAIKO | 0.02% | $76,131 | 0.01 | $761.31 | |
| UNI | 0.23% | $2,017.43 | 3.6185 | $7,300.09 | |
| UNI | 0.14% | $0.998295 | 4,494.2417 | $4,486.58 | |
| UNI | 0.12% | $0.999903 | 3,886.4388 | $3,886.06 | |
| OPBNB | 0.25% | $623.15 | 12.4161 | $7,737.03 | |
| OPBNB | 0.05% | $0.998017 | 1,673.2261 | $1,669.91 | |
| BLAST | 0.13% | $0.994464 | 4,129.0007 | $4,106.14 | |
| BLAST | 0.12% | $2,017.26 | 1.8882 | $3,809.02 | |
| GLMR | 0.21% | $1 | 6,651.3596 | $6,658.01 | |
| MANTLE | 0.12% | $0.994042 | 3,735.2162 | $3,712.96 | |
| MANTLE | 0.06% | $1 | 1,987.3128 | $1,987.31 | |
| MANTLE | <0.01% | $0.634431 | 0.00001301 | $0.000008 | |
| SONIC | 0.16% | $0.9999 | 5,059.8389 | $5,059.33 | |
| SONIC | <0.01% | $0.048598 | 856.7828 | $41.64 | |
| HYPEREVM | 0.16% | $0.998849 | 4,943.301 | $4,937.61 | |
| HYPEREVM | <0.01% | $29.48 | 2.5 | $73.7 | |
| PLASMA | 0.16% | $0.998295 | 4,902.1096 | $4,893.75 | |
| PLASMA | <0.01% | $0.098467 | 33 | $3.25 | |
| BERA | 0.08% | $1.01 | 2,607.2132 | $2,625.46 | |
| BERA | 0.05% | $0.998314 | 1,500 | $1,497.47 | |
| STABLE | 0.13% | $0.999419 | 3,947.6069 | $3,945.31 | |
| MONAD | 0.06% | $0.999903 | 1,805.8802 | $1,805.71 | |
| GNO | 0.05% | $0.999871 | 1,502.9555 | $1,502.76 | |
| CELO | 0.03% | $0.999473 | 1,048.0742 | $1,047.52 | |
| APE | <0.01% | $0.127815 | 0.2406 | $0.030758 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.