Source Code
Latest 25 from a total of 4,118 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Claim Manta | 13150228 | 91 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim Manta | 13150190 | 91 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim Manta | 13150150 | 91 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim Manta | 13150099 | 91 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim V Manta | 13134027 | 92 days ago | IN | 5 GLMR | 0.03650681 | ||||
| Claim V Manta | 13133398 | 92 days ago | IN | 5 GLMR | 0.03650681 | ||||
| Claim V Manta | 13123568 | 93 days ago | IN | 5 GLMR | 0.03650681 | ||||
| Claim V Manta | 13103333 | 94 days ago | IN | 5 GLMR | 0.03650681 | ||||
| Claim Manta | 13098003 | 95 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim Manta | 13087739 | 96 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim Manta | 13083303 | 96 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim Manta | 13082346 | 96 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim V Manta | 13072643 | 97 days ago | IN | 5 GLMR | 0.03650681 | ||||
| Claim Manta | 13071493 | 97 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim V Manta | 13070700 | 97 days ago | IN | 5 GLMR | 0.03650681 | ||||
| Claim Manta | 13064584 | 98 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim Manta | 13064447 | 98 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim Manta | 13060447 | 98 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim Manta | 13060361 | 98 days ago | IN | 5 GLMR | 0.00141424 | ||||
| Claim Manta | 13060361 | 98 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim V Manta | 13059236 | 98 days ago | IN | 5 GLMR | 0.03650681 | ||||
| Claim V Manta | 13059052 | 98 days ago | IN | 5 GLMR | 0.03650681 | ||||
| Claim Manta | 13056786 | 98 days ago | IN | 5 GLMR | 0.03660035 | ||||
| Claim V Manta | 13046474 | 99 days ago | IN | 5 GLMR | 0.03650681 | ||||
| Claim V Manta | 13038805 | 100 days ago | IN | 5 GLMR | 0.03650681 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 13150228 | 91 days ago | 2.5495528 GLMR | ||||
| 13150228 | 91 days ago | 2.45044719 GLMR | ||||
| 13150190 | 91 days ago | 2.5495528 GLMR | ||||
| 13150190 | 91 days ago | 2.45044719 GLMR | ||||
| 13150150 | 91 days ago | 2.5495528 GLMR | ||||
| 13150150 | 91 days ago | 2.45044719 GLMR | ||||
| 13150099 | 91 days ago | 2.5495528 GLMR | ||||
| 13150099 | 91 days ago | 2.45044719 GLMR | ||||
| 13134027 | 92 days ago | 2.5495528 GLMR | ||||
| 13134027 | 92 days ago | 2.45044719 GLMR | ||||
| 13133398 | 92 days ago | 2.5495528 GLMR | ||||
| 13133398 | 92 days ago | 2.45044719 GLMR | ||||
| 13133359 | 92 days ago | Contract Creation | 0 GLMR | |||
| 13123568 | 93 days ago | 2.5495528 GLMR | ||||
| 13123568 | 93 days ago | 2.45044719 GLMR | ||||
| 13123542 | 93 days ago | Contract Creation | 0 GLMR | |||
| 13114771 | 93 days ago | Contract Creation | 0 GLMR | |||
| 13103333 | 94 days ago | 2.5495528 GLMR | ||||
| 13103333 | 94 days ago | 2.45044719 GLMR | ||||
| 13103273 | 94 days ago | Contract Creation | 0 GLMR | |||
| 13098003 | 95 days ago | 2.5495528 GLMR | ||||
| 13098003 | 95 days ago | 2.45044719 GLMR | ||||
| 13087739 | 96 days ago | 2.6274995 GLMR | ||||
| 13087739 | 96 days ago | 2.37250049 GLMR | ||||
| 13087705 | 96 days ago | Contract Creation | 0 GLMR |
Cross-Chain Transactions
Loading...
Loading
This contract contains unverified libraries: BuildCallData
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
MoonbeamReceiver
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Create2.sol";
import "./interfaces/IOFTReceiverV2.sol";
import "./interfaces/IOFTV2.sol";
import "./interfaces/ISlpx.sol";
import "./DerivativeContract.sol";
import "./MoonbeamSlpx.sol";
import "./utils/BuildCallData.sol";
import "./utils/AddressToAccount.sol";
import "./interfaces/Xtokens.sol";
import "./interfaces/XcmTransactorV2.sol";
contract MoonbeamReceiver is Ownable, IOFTReceiverV2 {
uint16 public constant destChainId = 217;
address public constant VMANTA = 0xFFfFFfFfdA2a05FB50e7ae99275F4341AEd43379;
address public constant MANTA = 0xfFFffFFf7D3875460d4509eb8d0362c611B4E841;
address public constant BNC = 0xFFffffFf7cC06abdF7201b350A1265c62C8601d2;
bytes2 private constant MANTA_CURRENCY_ID = 0x0808;
bytes2 private constant VMANTA_CURRENCY_ID = 0x0908;
bytes1 private constant MOONBEAM_CHAIN_TYPE = 0x01;
address public constant slpx = 0xF1d4797E51a4640a76769A50b57abE7479ADd3d8;
address public constant mantaOFT =
0x17313cE6e47D796E61fDeAc34Ab1F58e3e089082;
address public constant vMantaProxyOFT =
0xDeBBb9309d95DaBbFb82411a9C6Daa3909B164A4;
address internal constant XTOKENS =
0x0000000000000000000000000000000000000804;
address internal constant XCM_TRANSACTORV2_ADDRESS =
0x000000000000000000000000000000000000080D;
address public mantaPacificSlpx;
uint256 public layerZeroFee;
address public scriptTrigger;
mapping(address => address) public callerToDerivativeAddress;
event SetDerivativeAddress(
address indexed caller,
address indexed derivativeAddress
);
event SetLayerZeroFee(
address indexed scriptTrigger,
uint256 indexed layerZeroFee
);
event SetScriptTrigger(address indexed scriptTrigger);
function xcmTransferAsset(
address assetAddress,
address to,
uint256 amount
) internal {
require(assetAddress != address(0), "Invalid assetAddress");
bytes32 publicKey = AddressToAccount.AddressToSubstrateAccount(to);
Xtokens.Multilocation memory dest_account = getXtokensDestination(
publicKey
);
Xtokens(XTOKENS).transfer(
assetAddress,
amount,
dest_account,
type(uint64).max
);
}
function getXtokensDestination(
bytes32 publicKey
) internal pure returns (Xtokens.Multilocation memory) {
bytes[] memory interior = new bytes[](2);
interior[0] = bytes.concat(hex"00", bytes4(uint32(2030)));
interior[1] = bytes.concat(hex"01", publicKey, hex"00");
Xtokens.Multilocation memory dest = Xtokens.Multilocation({
parents: 1,
interior: interior
});
return dest;
}
function getXcmTransactorDestination()
internal
pure
returns (XcmTransactorV2.Multilocation memory)
{
bytes[] memory interior = new bytes[](1);
interior[0] = bytes.concat(hex"00", bytes4(uint32(2030)));
XcmTransactorV2.Multilocation
memory xcmTransactorDestination = XcmTransactorV2.Multilocation({
parents: 1,
interior: interior
});
return xcmTransactorDestination;
}
function create_order(
address caller,
address assetAddress,
bytes2 token,
uint128 amount,
address receiver,
uint32 channel_id
) internal {
require(amount > 0, "amount must be greater than 0");
xcmTransferAsset(assetAddress, caller, uint256(amount));
// Build bifrost slpx create order call data
bytes memory callData = BuildCallData.buildCreateOrderCallBytes(
caller,
block.chainid,
block.number,
token,
amount,
abi.encodePacked(MOONBEAM_CHAIN_TYPE, receiver),
"MantaPacificV2",
channel_id
);
// XCM Transact
(
uint64 transactRequiredWeightAtMost,
uint256 feeAmount,
uint64 overallWeight
) = MoonbeamSlpx(slpx).operationToFeeInfo(MoonbeamSlpx.Operation.Mint);
XcmTransactorV2(XCM_TRANSACTORV2_ADDRESS).transactThroughSigned(
getXcmTransactorDestination(),
BNC,
transactRequiredWeightAtMost,
callData,
feeAmount,
overallWeight
);
}
function setRemoteContract(address _mantaPacificSlpx) public onlyOwner {
require(_mantaPacificSlpx != address(0), "Invalid mantaPacificSlpx");
mantaPacificSlpx = _mantaPacificSlpx;
}
function onOFTReceived(
uint16 srcChainId,
bytes calldata,
uint64,
bytes32 from,
uint amount,
bytes calldata payload
) external override {
require(
srcChainId == destChainId,
"only receive msg from manta pacific"
);
require(
_msgSender() == mantaOFT || _msgSender() == vMantaProxyOFT,
"only native oft can call"
);
require(
address(uint160(uint(from))) == mantaPacificSlpx,
"only receive msg from mantaPacificSlpx"
);
(address caller, uint32 channel_id) = abi.decode(
payload,
(address, uint32)
);
if (callerToDerivativeAddress[caller] == address(0)) {
setDerivativeAddress(caller);
}
// vManta:
// msg.sender = vMantaProxyOFT, from = mantaPacificSlpx,
// Manta:
// msg.sender = mantaOFT, from = mantaPacificSlpx
address asset_address;
if (_msgSender() == mantaOFT) {
bool success = IERC20(MANTA).transfer(scriptTrigger, layerZeroFee);
require(success, "failed to charge");
asset_address = MANTA;
} else if (_msgSender() == vMantaProxyOFT) {
bool success = IERC20(VMANTA).transfer(scriptTrigger, layerZeroFee);
require(success, "failed to charge");
asset_address = VMANTA;
} else {
revert("invalid msg.sender");
}
create_order(
caller,
asset_address,
asset_address == MANTA ? MANTA_CURRENCY_ID : VMANTA_CURRENCY_ID,
uint128(amount - layerZeroFee),
callerToDerivativeAddress[caller],
channel_id
);
}
function claimVManta(
address addr,
bytes calldata _adapterParams
) external payable {
require(_msgSender() == scriptTrigger, "must be scriptTrigger");
address derivativeAddress = callerToDerivativeAddress[addr];
require(derivativeAddress != address(0), "invalid address");
uint256 amount = DerivativeContract(derivativeAddress)
.withdrawErc20Token(VMANTA);
IERC20(VMANTA).approve(vMantaProxyOFT, amount);
ICommonOFT.LzCallParams memory callParams = ICommonOFT.LzCallParams(
payable(_msgSender()),
address(0),
_adapterParams
);
bytes32 toAddress = bytes32(uint256(uint160(addr)));
(uint256 estimateFee, ) = IOFTV2(vMantaProxyOFT).estimateSendFee(
destChainId,
toAddress,
amount,
false,
_adapterParams
);
require(msg.value >= estimateFee, "too small fee");
if (msg.value != estimateFee) {
uint256 refundAmount = msg.value - estimateFee;
(bool success, ) = _msgSender().call{value: refundAmount}("");
require(success, "failed to refund");
}
IOFTV2(vMantaProxyOFT).sendFrom{value: estimateFee}(
address(this),
destChainId,
toAddress,
amount,
callParams
);
}
function claimManta(
address addr,
bytes calldata _adapterParams
) external payable {
require(_msgSender() == scriptTrigger, "must be scriptTrigger");
address derivativeAddress = callerToDerivativeAddress[addr];
require(derivativeAddress != address(0), "invalid address");
uint256 amount = DerivativeContract(derivativeAddress)
.withdrawErc20Token(MANTA);
IERC20(MANTA).approve(mantaOFT, amount);
ICommonOFT.LzCallParams memory callParams = ICommonOFT.LzCallParams(
payable(_msgSender()),
address(0),
_adapterParams
);
bytes32 toAddress = bytes32(uint256(uint160(addr)));
(uint256 estimateFee, ) = IOFTV2(mantaOFT).estimateSendFee(
destChainId,
toAddress,
amount,
false,
_adapterParams
);
require(msg.value >= estimateFee, "too small fee");
if (msg.value != estimateFee) {
uint256 refundAmount = msg.value - estimateFee;
(bool success, ) = _msgSender().call{value: refundAmount}("");
require(success, "failed to refund");
}
IOFTV2(mantaOFT).sendFrom{value: estimateFee}(
address(this),
destChainId,
toAddress,
amount,
callParams
);
}
function setDerivativeAddress(address addr) public {
require(
callerToDerivativeAddress[addr] == address(0),
"already set derivativeAddress"
);
bytes memory bytecode = type(DerivativeContract).creationCode;
bytes32 salt = bytes32(uint256(uint160(addr)));
address derivativeAddress = Create2.deploy(0, salt, bytecode);
callerToDerivativeAddress[addr] = derivativeAddress;
emit SetDerivativeAddress(addr, derivativeAddress);
}
function setLayerZeroFee(uint256 _layerZeroFee) external {
require(_msgSender() == scriptTrigger, "must be scriptTrigger");
layerZeroFee = _layerZeroFee;
emit SetLayerZeroFee(scriptTrigger, _layerZeroFee);
}
function setScriptTrigger(address _scriptTrigger) external onlyOwner {
require(_scriptTrigger != address(0), "invalid address");
scriptTrigger = _scriptTrigger;
emit SetScriptTrigger(_scriptTrigger);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @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[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev 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.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
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.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
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.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @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[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or 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 {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// 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.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
/**
* @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.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Create2.sol)
pragma solidity ^0.8.0;
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
require(address(this).balance >= amount, "Create2: insufficient balance");
require(bytecode.length != 0, "Create2: bytecode length is zero");
/// @solidity memory-safe-assembly
assembly {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
}
require(addr != address(0), "Create2: Failed on deploy");
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40) // Get free memory pointer
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := keccak256(start, 85)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract DerivativeContract is ReentrancyGuard {
address public receiver;
event Withdraw(address caller, address to, address token, uint256 amount);
constructor() {
receiver = msg.sender;
}
function withdrawErc20Token(
address _erc20
) external nonReentrant returns (uint256) {
require(msg.sender == receiver, "forbidden");
require(_erc20 != address(0), "invalid erc20");
uint256 balance = IERC20(_erc20).balanceOf(address(this));
require(balance != 0, "balance to low");
IERC20(_erc20).transfer(receiver, balance);
emit Withdraw(msg.sender, receiver, _erc20, balance);
return balance;
}
function withdrawNativeToken(uint256 _amount) external nonReentrant {
require(msg.sender == receiver, "forbidden");
require(_amount != 0, "balance to low");
(bool success, ) = receiver.call{value: _amount}("");
require(success, "failed to withdrawNativeToken");
emit Withdraw(msg.sender, receiver, address(0), _amount);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @dev Interface of the IOFT core standard
*/
interface ICommonOFT is IERC165 {
struct LzCallParams {
address payable refundAddress;
address zroPaymentAddress;
bytes adapterParams;
}
/**
* @dev estimate send token `_tokenId` to (`_dstChainId`, `_toAddress`)
* _dstChainId - L0 defined chain id to send tokens too
* _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain
* _amount - amount of the tokens to transfer
* _useZro - indicates to use zro to pay L0 fees
* _adapterParam - flexible bytes array to indicate messaging adapter services in L0
*/
function estimateSendFee(
uint16 _dstChainId,
bytes32 _toAddress,
uint _amount,
bool _useZro,
bytes calldata _adapterParams
) external view returns (uint nativeFee, uint zroFee);
function estimateSendAndCallFee(
uint16 _dstChainId,
bytes32 _toAddress,
uint _amount,
bytes calldata _payload,
uint64 _dstGasForCall,
bool _useZro,
bytes calldata _adapterParams
) external view returns (uint nativeFee, uint zroFee);
/**
* @dev returns the circulating amount of tokens on current chain
*/
function circulatingSupply() external view returns (uint);
/**
* @dev returns the address of the ERC20 token
*/
function token() external view returns (address);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
interface IOFTReceiverV2 {
/**
* @dev Called by the OFT contract when tokens are received from source chain.
* @param _srcChainId The chain id of the source chain.
* @param _srcAddress The address of the OFT token contract on the source chain.
* @param _nonce The nonce of the transaction on the source chain.
* @param _from The address of the account who calls the sendAndCall() on the source chain.
* @param _amount The amount of tokens to transfer.
* @param _payload Additional data with no specified format.
*/
function onOFTReceived(
uint16 _srcChainId,
bytes calldata _srcAddress,
uint64 _nonce,
bytes32 _from,
uint _amount,
bytes calldata _payload
) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "./ICommonOFT.sol";
/**
* @dev Interface of the IOFT core standard
*/
interface IOFTV2 is ICommonOFT {
/**
* @dev send `_amount` amount of token to (`_dstChainId`, `_toAddress`) from `_from`
* `_from` the owner of token
* `_dstChainId` the destination chain identifier
* `_toAddress` can be any size depending on the `dstChainId`.
* `_amount` the quantity of tokens in wei
* `_refundAddress` the address LayerZero refunds if too much message fee is sent
* `_zroPaymentAddress` set to address(0x0) if not paying in ZRO (LayerZero Token)
* `_adapterParams` is a flexible bytes array to indicate messaging adapter services
*/
function sendFrom(
address _from,
uint16 _dstChainId,
bytes32 _toAddress,
uint _amount,
LzCallParams calldata _callParams
) external payable;
function sendAndCall(
address _from,
uint16 _dstChainId,
bytes32 _toAddress,
uint _amount,
bytes calldata _payload,
uint64 _dstGasForCall,
LzCallParams calldata _callParams
) external payable;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
interface ISlpx {
event Mint(
address minter,
address assetAddress,
uint256 amount,
address receiver,
bytes callcode,
string remark
);
event Redeem(
address redeemer,
address assetAddress,
uint256 amount,
address receiver,
bytes callcode
);
event CreateOrder(
address assetAddress,
uint128 amount,
uint64 dest_chain_id,
bytes receiver,
string remark,
uint32 channel_id
);
/// Minted vNative assets such as vASTR, vGLMR, vMOVR
function mintVNativeAsset(
address receiver,
string memory remark
) external payable;
/// Minted vAssets
function mintVAsset(
address assetAddress,
uint256 amount,
address receiver,
string memory remark
) external;
/// Minted vNative assets such as vASTR, vGLMR, vMOVR
function mintVNativeAssetWithChannelId(
address receiver,
string memory remark,
uint32 channel_id
) external payable;
/// Minted vAssets
function mintVAssetWithChannelId(
address assetAddress,
uint256 amount,
address receiver,
string memory remark,
uint32 channel_id
) external;
/// Redeem assets
function redeemAsset(
address vAssetAddress,
uint256 amount,
address receiver
) external;
/**
* @dev Create order to mint vAsset or redeem vAsset on bifrost chain
* @param assetAddress The address of the asset to mint or redeem
* @param amount The amount of the asset to mint or redeem
* @param dest_chain_id When order is executed on Bifrost, Asset/vAsset will be transferred to this chain
* @param receiver The receiver address on the destination chain, 20 bytes for EVM, 32 bytes for Substrate
* @param remark The remark of the order, less than 32 bytes. For example, "OmniLS"
* @param channel_id The channel id of the order, you can set it. Bifrost chain will use it to share reward.
**/
function create_order(
address assetAddress,
uint128 amount,
uint64 dest_chain_id,
bytes memory receiver,
string memory remark,
uint32 channel_id
) external payable;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
/// @dev The XcmTransactorV2 contract's address.
address constant XCM_TRANSACTOR_V2_ADDRESS = 0x000000000000000000000000000000000000080D;
/// @dev The XcmTransactorV2 contract's instance.
XcmTransactorV2 constant XCM_TRANSACTOR_V2_CONTRACT = XcmTransactorV2(
XCM_TRANSACTOR_V2_ADDRESS
);
/// @author The Moonbeam Team
/// @title Xcm Transactor Interface
/// The interface through which solidity contracts will interact with xcm transactor pallet
/// @custom:address 0x000000000000000000000000000000000000080D
interface XcmTransactorV2 {
// A multilocation is defined by its number of parents and the encoded junctions (interior)
struct Multilocation {
uint8 parents;
bytes[] interior;
}
/// Get index of an account in xcm transactor
/// @custom:selector 3fdc4f36
/// @param index The index of which we want to retrieve the account
/// @return owner The owner of the derivative index
///
function indexToAccount(uint16 index) external view returns (address owner);
/// Get transact info of a multilocation
/// @custom:selector b689e20c
/// @param multilocation The location for which we want to know the transact info
/// @return transactExtraWeight The extra weight involved in the XCM message of using derivative
/// @return transactExtraWeightSigned The extra weight involved in the XCM message of using signed
/// @return maxWeight Maximum allowed weight for a single message in dest
///
function transactInfoWithSigned(
Multilocation memory multilocation
)
external
view
returns (
uint64 transactExtraWeight,
uint64 transactExtraWeightSigned,
uint64 maxWeight
);
/// Get fee per second charged in its reserve chain for an asset
/// @custom:selector 906c9990
/// @param multilocation The asset location for which we want to know the fee per second value
/// @return feePerSecond The fee per second that the reserve chain charges for this asset
///
function feePerSecond(
Multilocation memory multilocation
) external view returns (uint256 feePerSecond);
/// Transact through XCM using fee based on its multilocation
/// @custom:selector fe430475
/// @dev The token transfer burns/transfers the corresponding amount before sending
/// @param transactor The transactor to be used
/// @param index The index to be used
/// @param feeAsset The asset in which we want to pay fees.
/// It has to be a reserve of the destination chain
/// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain
/// @param innerCall The inner call to be executed in the destination chain
/// @param feeAmount Amount to be used as fee.
/// @param overallWeight Overall weight to be used for the xcm message.
///
function transactThroughDerivativeMultilocation(
uint8 transactor,
uint16 index,
Multilocation memory feeAsset,
uint64 transactRequiredWeightAtMost,
bytes memory innerCall,
uint256 feeAmount,
uint64 overallWeight
) external;
/// Transact through XCM using fee based on its currency_id
/// @custom:selector 185de2ae
/// @dev The token transfer burns/transfers the corresponding amount before sending
/// @param transactor The transactor to be used
/// @param index The index to be used
/// @param currencyId Address of the currencyId of the asset to be used for fees
/// It has to be a reserve of the destination chain
/// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain
/// @param innerCall The inner call to be executed in the destination chain
/// @param feeAmount Amount to be used as fee.
/// @param overallWeight Overall weight to be used for the xcm message.
function transactThroughDerivative(
uint8 transactor,
uint16 index,
address currencyId,
uint64 transactRequiredWeightAtMost,
bytes memory innerCall,
uint256 feeAmount,
uint64 overallWeight
) external;
/// Transact through XCM using fee based on its multilocation through signed origins
/// @custom:selector d7ab340c
/// @dev No token is burnt before sending the message. The caller must ensure the destination
/// is able to undertand the DescendOrigin message, and create a unique account from which
/// dispatch the call
/// @param dest The destination chain (as multilocation) where to send the message
/// @param feeLocation The asset multilocation that indentifies the fee payment currency
/// It has to be a reserve of the destination chain
/// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain for the call to be made
/// @param call The call to be executed in the destination chain
/// @param feeAmount Amount to be used as fee.
/// @param overallWeight Overall weight to be used for the xcm message.
function transactThroughSignedMultilocation(
Multilocation memory dest,
Multilocation memory feeLocation,
uint64 transactRequiredWeightAtMost,
bytes memory call,
uint256 feeAmount,
uint64 overallWeight
) external;
/// Transact through XCM using fee based on its erc20 address through signed origins
/// @custom:selector b648f3fe
/// @dev No token is burnt before sending the message. The caller must ensure the destination
/// is able to undertand the DescendOrigin message, and create a unique account from which
/// dispatch the call
/// @param dest The destination chain (as multilocation) where to send the message
/// @param feeLocationAddress The ERC20 address of the token we want to use to pay for fees
/// only callable if such an asset has been BRIDGED to our chain
/// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain for the call to be made
/// @param call The call to be executed in the destination chain
/// @param feeAmount Amount to be used as fee.
/// @param overallWeight Overall weight to be used for the xcm message.
function transactThroughSigned(
Multilocation memory dest,
address feeLocationAddress,
uint64 transactRequiredWeightAtMost,
bytes memory call,
uint256 feeAmount,
uint64 overallWeight
) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
/// @dev The Xtokens contract's address.
address constant XTOKENS_ADDRESS = 0x0000000000000000000000000000000000000804;
/// @dev The Xtokens contract's instance.
Xtokens constant XTOKENS_CONTRACT = Xtokens(XTOKENS_ADDRESS);
/// @author The Moonbeam Team
/// @title Xtokens Interface
/// @dev The interface through which solidity contracts will interact with xtokens pallet
/// @custom:address 0x0000000000000000000000000000000000000804
interface Xtokens {
// A multilocation is defined by its number of parents and the encoded junctions (interior)
struct Multilocation {
uint8 parents;
bytes[] interior;
}
// A MultiAsset is defined by a multilocation and an amount
struct MultiAsset {
Multilocation location;
uint256 amount;
}
// A Currency is defined by address and the amount to be transferred
struct Currency {
address currencyAddress;
uint256 amount;
}
/// Transfer a token through XCM based on its currencyId
///
/// @dev The token transfer burns/transfers the corresponding amount before sending
/// @param currencyAddress The ERC20 address of the currency we want to transfer
/// @param amount The amount of tokens we want to transfer
/// @param destination The Multilocation to which we want to send the tokens
/// @param destination The weight we want to buy in the destination chain
/// @custom:selector b9f813ff
function transfer(
address currencyAddress,
uint256 amount,
Multilocation memory destination,
uint64 weight
) external;
/// Transfer a token through XCM based on its currencyId specifying fee
///
/// @dev The token transfer burns/transfers the corresponding amount before sending
/// @param currencyAddress The ERC20 address of the currency we want to transfer
/// @param amount The amount of tokens we want to transfer
/// @param destination The Multilocation to which we want to send the tokens
/// @param destination The weight we want to buy in the destination chain
/// @custom:selector 3e506ef0
function transferWithFee(
address currencyAddress,
uint256 amount,
uint256 fee,
Multilocation memory destination,
uint64 weight
) external;
/// Transfer a token through XCM based on its MultiLocation
///
/// @dev The token transfer burns/transfers the corresponding amount before sending
/// @param asset The asset we want to transfer, defined by its multilocation.
/// Currently only Concrete Fungible assets
/// @param amount The amount of tokens we want to transfer
/// @param destination The Multilocation to which we want to send the tokens
/// @param destination The weight we want to buy in the destination chain
/// @custom:selector b4f76f96
function transferMultiasset(
Multilocation memory asset,
uint256 amount,
Multilocation memory destination,
uint64 weight
) external;
/// Transfer a token through XCM based on its MultiLocation specifying fee
///
/// @dev The token transfer burns/transfers the corresponding amount before sending
/// @param asset The asset we want to transfer, defined by its multilocation.
/// Currently only Concrete Fungible assets
/// @param amount The amount of tokens we want to transfer
/// @param destination The Multilocation to which we want to send the tokens
/// @param destination The weight we want to buy in the destination chain
/// @custom:selector 150c016a
function transferMultiassetWithFee(
Multilocation memory asset,
uint256 amount,
uint256 fee,
Multilocation memory destination,
uint64 weight
) external;
/// Transfer several tokens at once through XCM based on its address specifying fee
///
/// @dev The token transfer burns/transfers the corresponding amount before sending
/// @param currencies The currencies we want to transfer, defined by their address and amount.
/// @param feeItem Which of the currencies to be used as fee
/// @param destination The Multilocation to which we want to send the tokens
/// @param weight The weight we want to buy in the destination chain
/// @custom:selector ab946323
function transferMultiCurrencies(
Currency[] memory currencies,
uint32 feeItem,
Multilocation memory destination,
uint64 weight
) external;
/// Transfer several tokens at once through XCM based on its location specifying fee
///
/// @dev The token transfer burns/transfers the corresponding amount before sending
/// @param assets The assets we want to transfer, defined by their location and amount.
/// @param feeItem Which of the currencies to be used as fee
/// @param destination The Multilocation to which we want to send the tokens
/// @param weight The weight we want to buy in the destination chain
/// @custom:selector 797b45fd
function transferMultiAssets(
MultiAsset[] memory assets,
uint32 feeItem,
Multilocation memory destination,
uint64 weight
) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "./interfaces/XcmTransactorV2.sol";
import "./interfaces/Xtokens.sol";
import "./interfaces/ISlpx.sol";
import "./utils/AddressToAccount.sol";
import "./utils/BuildCallData.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
contract MoonbeamSlpx is ISlpx, OwnableUpgradeable, PausableUpgradeable {
address internal constant NATIVE_ASSET_ADDRESS =
0x0000000000000000000000000000000000000802;
address internal constant XCM_TRANSACTORV2_ADDRESS =
0x000000000000000000000000000000000000080D;
address internal constant XTOKENS =
0x0000000000000000000000000000000000000804;
bytes1 internal constant MOONBEAM_CHAIN = 0x01;
XcmTransactorV2.Multilocation internal xcmTransactorDestination;
address public BNCAddress;
uint32 public bifrostParaId;
enum Operation {
Mint,
Redeem,
ZenlinkSwap,
StableSwap
}
struct AssetInfo {
bytes2 currencyId;
uint256 operationalMin;
}
struct FeeInfo {
uint64 transactRequiredWeightAtMost;
uint256 feeAmount;
uint64 overallWeight;
}
mapping(address => AssetInfo) public addressToAssetInfo;
mapping(Operation => FeeInfo) public operationToFeeInfo;
struct DestChainInfo {
bool is_evm;
bool is_substrate;
bytes1 raw_chain_index;
}
mapping(uint64 => DestChainInfo) public destChainInfo;
function checkAssetIsExist(
address assetAddress
) internal view returns (bytes2) {
AssetInfo memory assetInfo = addressToAssetInfo[assetAddress];
require(assetInfo.operationalMin > 0, "Asset is not exist");
require(assetInfo.currencyId != bytes2(0), "Invalid asset");
return assetInfo.currencyId;
}
function checkFeeInfo(
Operation operation
) internal view returns (FeeInfo memory) {
FeeInfo memory feeInfo = operationToFeeInfo[operation];
require(
feeInfo.transactRequiredWeightAtMost > 0,
"Invalid transactRequiredWeightAtMost"
);
require(feeInfo.feeAmount > 0, "Invalid feeAmount");
require(feeInfo.overallWeight > 0, "Invalid overallWeight");
return feeInfo;
}
function initialize(
address _BNCAddress,
uint32 _bifrostParaId,
bytes2 _nativeCurrencyId
) public initializer {
__Ownable_init();
__Pausable_init();
require(_BNCAddress != address(0), "Invalid address");
require(
_bifrostParaId == 2001 || _bifrostParaId == 2030,
"Invalid bifrostParaId"
);
require(
_nativeCurrencyId == 0x020a || _nativeCurrencyId == 0x0801,
"Invalid nativeCurrencyId"
);
setAssetAddressInfo(_BNCAddress, 0x0001, 1_000_000_000_000);
setAssetAddressInfo(
NATIVE_ASSET_ADDRESS,
_nativeCurrencyId,
1_000_000_000_000_000_000
);
BNCAddress = _BNCAddress;
bifrostParaId = _bifrostParaId;
// Init xcmTransactorDestination
bytes[] memory interior = new bytes[](1);
// Parachain: 2001/2030
interior[0] = bytes.concat(hex"00", bytes4(_bifrostParaId));
xcmTransactorDestination = XcmTransactorV2.Multilocation({
parents: 1,
interior: interior
});
}
function setOperationToFeeInfo(
Operation _operation,
uint64 _transactRequiredWeightAtMost,
uint64 _overallWeight,
uint256 _feeAmount
) public onlyOwner {
operationToFeeInfo[_operation] = FeeInfo(
_transactRequiredWeightAtMost,
_feeAmount,
_overallWeight
);
}
function setAssetAddressInfo(
address assetAddress,
bytes2 currencyId,
uint256 minimumValue
) public onlyOwner {
require(assetAddress != address(0), "Invalid assetAddress");
require(minimumValue != 0, "Invalid minimumValue");
require(currencyId != bytes2(0), "Invalid currencyId");
AssetInfo storage assetInfo = addressToAssetInfo[assetAddress];
assetInfo.currencyId = currencyId;
assetInfo.operationalMin = minimumValue;
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
function xcmTransferAsset(address assetAddress, uint256 amount) internal {
require(assetAddress != address(0), "Invalid assetAddress");
require(
amount >= addressToAssetInfo[assetAddress].operationalMin,
"Less than MinimumValue"
);
bytes32 publicKey = AddressToAccount.AddressToSubstrateAccount(
_msgSender()
);
Xtokens.Multilocation memory dest_account = getXtokensDestination(
publicKey
);
IERC20 asset = IERC20(assetAddress);
asset.transferFrom(_msgSender(), address(this), amount);
Xtokens(XTOKENS).transfer(
assetAddress,
amount,
dest_account,
type(uint64).max
);
}
function xcmTransferNativeAsset(uint256 amount) internal {
require(
amount >= addressToAssetInfo[NATIVE_ASSET_ADDRESS].operationalMin,
"Less than MinimumValue"
);
bytes32 publicKey = AddressToAccount.AddressToSubstrateAccount(
_msgSender()
);
Xtokens.Multilocation memory dest_account = getXtokensDestination(
publicKey
);
Xtokens(XTOKENS).transfer(
NATIVE_ASSET_ADDRESS,
amount,
dest_account,
type(uint64).max
);
}
function mintVNativeAsset(
address receiver,
string memory remark
) external payable override whenNotPaused {
require(bytes(remark).length <= 32, "remark too long");
bytes2 nativeToken = checkAssetIsExist(NATIVE_ASSET_ADDRESS);
// xtokens call
xcmTransferNativeAsset(msg.value);
// Build bifrost xcm-action mint call data
bytes memory targetChain = abi.encodePacked(MOONBEAM_CHAIN, receiver);
bytes memory callData = BuildCallData.buildMintCallBytes(
_msgSender(),
nativeToken,
targetChain,
remark
);
// XCM Transact
FeeInfo memory feeInfo = checkFeeInfo(Operation.Mint);
XcmTransactorV2(XCM_TRANSACTORV2_ADDRESS).transactThroughSigned(
xcmTransactorDestination,
BNCAddress,
feeInfo.transactRequiredWeightAtMost,
callData,
feeInfo.feeAmount,
feeInfo.overallWeight
);
emit Mint(
_msgSender(),
NATIVE_ASSET_ADDRESS,
msg.value,
receiver,
callData,
remark
);
}
function mintVAsset(
address assetAddress,
uint256 amount,
address receiver,
string memory remark
) external override whenNotPaused {
require(bytes(remark).length <= 32, "remark too long");
bytes2 token = checkAssetIsExist(assetAddress);
// xtokens call
xcmTransferAsset(assetAddress, amount);
// Build bifrost xcm-action mint call data
bytes memory targetChain = abi.encodePacked(MOONBEAM_CHAIN, receiver);
bytes memory callData = BuildCallData.buildMintCallBytes(
_msgSender(),
token,
targetChain,
remark
);
// XCM Transact
FeeInfo memory feeInfo = checkFeeInfo(Operation.Mint);
XcmTransactorV2(XCM_TRANSACTORV2_ADDRESS).transactThroughSigned(
xcmTransactorDestination,
BNCAddress,
feeInfo.transactRequiredWeightAtMost,
callData,
feeInfo.feeAmount,
feeInfo.overallWeight
);
emit Mint(
_msgSender(),
assetAddress,
amount,
receiver,
callData,
remark
);
}
function mintVNativeAssetWithChannelId(
address receiver,
string memory remark,
uint32 channel_id
) external payable override whenNotPaused {
require(bytes(remark).length <= 32, "remark too long");
bytes2 nativeToken = checkAssetIsExist(NATIVE_ASSET_ADDRESS);
// xtokens call
xcmTransferNativeAsset(msg.value);
// Build bifrost xcm-action mint call data
bytes memory targetChain = abi.encodePacked(MOONBEAM_CHAIN, receiver);
bytes memory callData = BuildCallData.buildMintWithChannelIdCallBytes(
_msgSender(),
nativeToken,
targetChain,
remark,
channel_id
);
// XCM Transact
FeeInfo memory feeInfo = checkFeeInfo(Operation.Mint);
XcmTransactorV2(XCM_TRANSACTORV2_ADDRESS).transactThroughSigned(
xcmTransactorDestination,
BNCAddress,
feeInfo.transactRequiredWeightAtMost,
callData,
feeInfo.feeAmount,
feeInfo.overallWeight
);
emit Mint(
_msgSender(),
NATIVE_ASSET_ADDRESS,
msg.value,
receiver,
callData,
remark
);
}
function mintVAssetWithChannelId(
address assetAddress,
uint256 amount,
address receiver,
string memory remark,
uint32 channel_id
) external override whenNotPaused {
require(bytes(remark).length <= 32, "remark too long");
bytes2 token = checkAssetIsExist(assetAddress);
// xtokens call
xcmTransferAsset(assetAddress, amount);
// Build bifrost xcm-action mint call data
bytes memory targetChain = abi.encodePacked(MOONBEAM_CHAIN, receiver);
bytes memory callData = BuildCallData.buildMintWithChannelIdCallBytes(
_msgSender(),
token,
targetChain,
remark,
channel_id
);
// XCM Transact
FeeInfo memory feeInfo = checkFeeInfo(Operation.Mint);
XcmTransactorV2(XCM_TRANSACTORV2_ADDRESS).transactThroughSigned(
xcmTransactorDestination,
BNCAddress,
feeInfo.transactRequiredWeightAtMost,
callData,
feeInfo.feeAmount,
feeInfo.overallWeight
);
emit Mint(
_msgSender(),
assetAddress,
amount,
receiver,
callData,
remark
);
}
function redeemAsset(
address vAssetAddress,
uint256 amount,
address receiver
) external override whenNotPaused {
bytes2 vtoken = checkAssetIsExist(vAssetAddress);
// xtokens call
xcmTransferAsset(vAssetAddress, amount);
// xcm transactor call
bytes memory targetChain = abi.encodePacked(MOONBEAM_CHAIN, receiver);
bytes memory callData = BuildCallData.buildRedeemCallBytes(
_msgSender(),
vtoken,
targetChain
);
FeeInfo memory feeInfo = checkFeeInfo(Operation.Redeem);
XcmTransactorV2(XCM_TRANSACTORV2_ADDRESS).transactThroughSigned(
xcmTransactorDestination,
BNCAddress,
feeInfo.transactRequiredWeightAtMost,
callData,
feeInfo.feeAmount,
feeInfo.overallWeight
);
emit Redeem(_msgSender(), vAssetAddress, amount, receiver, callData);
}
function getXtokensDestination(
bytes32 publicKey
) internal view returns (Xtokens.Multilocation memory) {
bytes[] memory interior = new bytes[](2);
// Parachain: 2001/2030
interior[0] = bytes.concat(hex"00", bytes4(bifrostParaId));
// AccountId32: { id: public_key , network: any }
interior[1] = bytes.concat(hex"01", publicKey, hex"00");
Xtokens.Multilocation memory dest = Xtokens.Multilocation({
parents: 1,
interior: interior
});
return dest;
}
function setDestChainInfo(
uint64 dest_chain_id,
bool is_evm,
bool is_substrate,
bytes1 raw_chain_index
) public onlyOwner {
require(!(is_evm && is_substrate), "Both is_evm and is_substrate cannot be true");
DestChainInfo storage chainInfo = destChainInfo[dest_chain_id];
chainInfo.is_evm = is_evm;
chainInfo.is_substrate = is_substrate;
chainInfo.raw_chain_index = raw_chain_index;
}
/**
* @dev Create order to mint vAsset or redeem vAsset on bifrost chain
* @param assetAddress The address of the asset to mint or redeem
* @param amount The amount of the asset to mint or redeem
* @param dest_chain_id When order is executed, Asset/vAsset will be transferred to this chain
* @param receiver The receiver address on the destination chain, 20 bytes for EVM, 32 bytes for Substrate
* @param remark The remark of the order, less than 32 bytes. For example, "OmniLS"
* @param channel_id The channel id of the order, you can set it. Bifrost chain will use it to share reward.
**/
function create_order(
address assetAddress,
uint128 amount,
uint64 dest_chain_id,
bytes memory receiver,
string memory remark,
uint32 channel_id
) external override payable {
require(bytes(remark).length > 0 && bytes(remark).length <= 32, "remark must be less than 32 bytes and not empty");
require(amount > 0, "amount must be greater than 0");
DestChainInfo memory chainInfo = destChainInfo[dest_chain_id];
if(chainInfo.is_evm) {
require(receiver.length == 20, "evm address must be 20 bytes");
} else if(chainInfo.is_substrate) {
require(receiver.length == 32, "substrate public key must be 32 bytes");
} else {
revert("Destination chain is not supported");
}
bytes2 token = checkAssetIsExist(assetAddress);
// Transfer asset to bifrost chain
if (assetAddress == NATIVE_ASSET_ADDRESS) {
amount = uint128(msg.value);
xcmTransferNativeAsset(uint256(amount));
} else {
xcmTransferAsset(assetAddress, uint256(amount));
}
// Build bifrost slpx create order call data
bytes memory callData = BuildCallData.buildCreateOrderCallBytes(
_msgSender(),
block.chainid,
block.number,
token,
amount,
abi.encodePacked(chainInfo.raw_chain_index, receiver),
remark,
channel_id
);
// XCM Transact
FeeInfo memory feeInfo = checkFeeInfo(Operation.Mint);
XcmTransactorV2(XCM_TRANSACTORV2_ADDRESS).transactThroughSigned(
xcmTransactorDestination,
BNCAddress,
feeInfo.transactRequiredWeightAtMost,
callData,
feeInfo.feeAmount,
feeInfo.overallWeight
);
emit CreateOrder(
assetAddress,
amount,
dest_chain_id,
receiver,
remark,
channel_id
);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
import "./Blake2b.sol";
library AddressToAccount {
using Blake2b for Blake2b.Instance;
function blake2bHash(bytes memory src) public view returns (bytes32 des) {
Blake2b.Instance memory instance = Blake2b.init(hex"", 32);
return abi.decode(instance.finalize(src), (bytes32));
}
function AddressToSubstrateAccount(
address addr
) public view returns (bytes32 account) {
bytes memory prefix = bytes("evm:");
bytes memory addrBytes = abi.encodePacked(addr);
bytes memory data = abi.encodePacked(prefix, addrBytes);
return blake2bHash(data);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
library Blake2b {
struct Instance {
// This is a bit misleadingly called state as it not only includes the Blake2 state,
// but every field needed for the "blake2 f function precompile".
//
// This is a tightly packed buffer of:
// - rounds: 32-bit BE
// - h: 8 x 64-bit LE
// - m: 16 x 64-bit LE
// - t: 2 x 64-bit LE
// - f: 8-bit
bytes state;
// Expected output hash length. (Used in `finalize`.)
uint out_len;
// Data passed to "function F".
// NOTE: this is limited to 24 bits.
uint input_counter;
}
// Initialise the state with a given `key` and required `out_len` hash length.
function init(
bytes memory key,
uint out_len
) internal view returns (Instance memory instance) {
require(key.length == 0, "Invalid key");
require(out_len == 32, "Invalid out_len");
reset(instance, key, out_len);
}
// Initialise the state with a given `key` and required `out_len` hash length.
function reset(
Instance memory instance,
bytes memory key,
uint out_len
) internal view {
instance.out_len = out_len;
instance.input_counter = 0;
// This is entire state transmitted to the precompile.
// It is byteswapped for the encoding requirements, additionally
// the IV has the initial parameter block 0 XOR constant applied, but
// not the key and output length.
instance
.state = hex"0000000c08c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
bytes memory state = instance.state;
// Update parameter block 0 with key length and output length.
uint key_len = key.length;
assembly {
let ptr := add(state, 36)
let tmp := mload(ptr)
let p0 := or(shl(240, key_len), shl(248, out_len))
tmp := xor(tmp, p0)
mstore(ptr, tmp)
}
// TODO: support salt and personalization
if (key_len > 0) {
require(key_len == 64);
// FIXME: the key must be zero padded
assert(key.length == 128);
update(instance, key, key_len);
}
}
// This calls the blake2 precompile ("function F of the spec").
// It expects the state was updated with the next block. Upon returning the state will be updated,
// but the supplied block data will not be cleared.
function call_function_f(Instance memory instance) private view {
bytes memory state = instance.state;
assembly {
let state_ptr := add(state, 32)
if iszero(
staticcall(
not(0),
0x09,
state_ptr,
0xd5,
add(state_ptr, 4),
0x40
)
) {
revert(0, 0)
}
}
}
// This function will split blocks correctly and repeatedly call the precompile.
// NOTE: this is dumb right now and expects `data` to be 128 bytes long and padded with zeroes,
// hence the real length is indicated with `data_len`
function update_loop(
Instance memory instance,
bytes memory data,
uint data_len,
bool last_block
) private view {
bytes memory state = instance.state;
uint input_counter = instance.input_counter;
// This is the memory location where the "data block" starts for the precompile.
uint state_ptr;
assembly {
// The `rounds` field is 4 bytes long and the `h` field is 64-bytes long.
// Also adjust for the size of the bytes type.
state_ptr := add(state, 100)
}
// This is the memory location where the input data resides.
uint data_ptr;
assembly {
data_ptr := add(data, 32)
}
uint len = data.length;
while (len > 0) {
if (len >= 128) {
assembly {
mstore(state_ptr, mload(data_ptr))
data_ptr := add(data_ptr, 32)
mstore(add(state_ptr, 32), mload(data_ptr))
data_ptr := add(data_ptr, 32)
mstore(add(state_ptr, 64), mload(data_ptr))
data_ptr := add(data_ptr, 32)
mstore(add(state_ptr, 96), mload(data_ptr))
data_ptr := add(data_ptr, 32)
}
len -= 128;
// FIXME: remove this once implemented proper padding
if (data_len < 128) {
input_counter += data_len;
} else {
data_len -= 128;
input_counter += 128;
}
} else {
// FIXME: implement support for smaller than 128 byte blocks
revert();
}
// Set length field (little-endian) for maximum of 24-bits.
assembly {
mstore8(add(state, 228), and(input_counter, 0xff))
mstore8(add(state, 229), and(shr(8, input_counter), 0xff))
mstore8(add(state, 230), and(shr(16, input_counter), 0xff))
}
// Set the last block indicator.
// Only if we've processed all input.
if (len == 0) {
assembly {
// Writing byte 212 here.
mstore8(add(state, 244), last_block)
}
}
// Call the precompile
call_function_f(instance);
}
instance.input_counter = input_counter;
}
// Update the state with a non-final block.
// NOTE: the input must be complete blocks.
function update(
Instance memory instance,
bytes memory data,
uint data_len
) internal view {
require((data.length % 128) == 0);
update_loop(instance, data, data_len, false);
}
// Update the state with a final block and return the hash.
function finalize(
Instance memory instance,
bytes memory data
) internal view returns (bytes memory output) {
// FIXME: support incomplete blocks (zero pad them)
uint input_length = data.length;
if (input_length == 0 || (input_length % 128) != 0) {
data = abi.encodePacked(
data,
new bytes(128 - (input_length % 128))
);
}
assert((data.length % 128) == 0);
update_loop(instance, data, input_length, true);
// FIXME: support other lengths
// assert(instance.out_len == 64);
bytes memory state = instance.state;
output = new bytes(instance.out_len);
if (instance.out_len == 16) {
assembly {
mstore(add(output, 16), mload(add(state, 20)))
mstore(output, 16)
}
} else if (instance.out_len == 32) {
assembly {
mstore(add(output, 32), mload(add(state, 36)))
}
} else {
assembly {
mstore(add(output, 32), mload(add(state, 36)))
mstore(add(output, 64), mload(add(state, 68)))
}
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;
library BuildCallData {
uint8 public constant PALLET_INDEX = 125;
uint8 public constant MINT_CALL_INDEX = 0;
uint8 public constant SWAP_CALL_INDEX = 1;
uint8 public constant REDEEM_CALL_INDEX = 2;
uint8 public constant STABLE_POOL_SWAP_CALL_INDEX = 3;
uint8 public constant MINT_WITH_CHANNEL_ID_CALL_INDEX = 13;
uint8 public constant CREATE_ORDER_CALL_INDEX = 14;
function buildMintCallBytes(
address caller,
bytes2 token,
bytes memory targetChain,
string memory remark
) public pure returns (bytes memory) {
bytes memory prefix = new bytes(2);
// storage pallet index
prefix[0] = bytes1(PALLET_INDEX);
// storage call index
prefix[1] = bytes1(MINT_CALL_INDEX);
// astar target_chain = bytes1(0)
return
bytes.concat(
prefix,
abi.encodePacked(caller),
token,
targetChain,
toScaleString(remark)
);
}
function buildMintWithChannelIdCallBytes(
address caller,
bytes2 token,
bytes memory targetChain,
string memory remark,
uint32 channel_id
) public pure returns (bytes memory) {
bytes memory prefix = new bytes(2);
// storage pallet index
prefix[0] = bytes1(PALLET_INDEX);
// storage call index
prefix[1] = bytes1(MINT_WITH_CHANNEL_ID_CALL_INDEX);
// astar target_chain = bytes1(0)
return
bytes.concat(
prefix,
abi.encodePacked(caller),
token,
targetChain,
toScaleString(remark),
encode_uint32(channel_id)
);
}
function buildCreateOrderCallBytes(
address caller,
uint256 chain_id,
uint256 block_number,
bytes2 token,
uint128 amount,
bytes memory targetChain,
string memory remark,
uint32 channel_id
) public pure returns (bytes memory) {
bytes memory prefix = new bytes(2);
// storage pallet index
prefix[0] = bytes1(PALLET_INDEX);
// storage call index
prefix[1] = bytes1(CREATE_ORDER_CALL_INDEX);
return
bytes.concat(
prefix,
abi.encodePacked(caller),
encode_uint64(uint64(chain_id)),
encode_uint128(uint128(block_number)),
token,
encode_uint128(amount),
targetChain,
toScaleString(remark),
encode_uint32(channel_id)
);
}
function buildSwapCallBytes(
address caller,
bytes2 currency_in,
bytes2 currency_out,
uint128 currency_out_min,
bytes memory targetChain
) public pure returns (bytes memory) {
bytes memory prefix = new bytes(2);
// storage pallet index
prefix[0] = bytes1(PALLET_INDEX);
// storage call index
prefix[1] = bytes1(SWAP_CALL_INDEX);
// astar target_chain = bytes1(0)
return
bytes.concat(
prefix,
abi.encodePacked(caller),
currency_in,
currency_out,
encode_uint128(currency_out_min),
targetChain
);
}
function buildStablePoolSwapCallBytes(
address caller,
uint32 pool_id,
bytes2 currency_in,
bytes2 currency_out,
uint128 min_dy,
bytes memory targetChain
) public pure returns (bytes memory) {
bytes memory prefix = new bytes(2);
// storage pallet index
prefix[0] = bytes1(PALLET_INDEX);
// storage call index
prefix[1] = bytes1(STABLE_POOL_SWAP_CALL_INDEX);
// astar target_chain = bytes1(0)
return
bytes.concat(
prefix,
abi.encodePacked(caller),
encode_uint32(pool_id),
currency_in,
currency_out,
encode_uint128(min_dy),
targetChain
);
}
function buildRedeemCallBytes(
address caller,
bytes2 vtoken,
bytes memory targetChain
) public pure returns (bytes memory) {
bytes memory prefix = new bytes(2);
// storage pallet index
prefix[0] = bytes1(PALLET_INDEX);
// storage call index
prefix[1] = bytes1(REDEEM_CALL_INDEX);
// astar target_chain = bytes1(0)
return
bytes.concat(prefix, abi.encodePacked(caller), vtoken, targetChain);
}
//https://docs.substrate.io/reference/scale-codec/
function encode_uint128(uint128 x) internal pure returns (bytes memory) {
bytes memory b = new bytes(16);
for (uint i = 0; i < 16; i++) {
b[i] = bytes1(uint8(x / (2 ** (8 * i))));
}
return b;
}
//https://docs.substrate.io/reference/scale-codec/
function encode_uint64(uint64 x) internal pure returns (bytes memory) {
bytes memory b = new bytes(8);
for (uint i = 0; i < 8; i++) {
b[i] = bytes1(uint8(x / (2 ** (8 * i))));
}
return b;
}
//https://docs.substrate.io/reference/scale-codec/
function encode_uint32(uint32 x) internal pure returns (bytes memory) {
bytes memory b = new bytes(4);
for (uint i = 0; i < 4; i++) {
b[i] = bytes1(uint8(x / (2 ** (8 * i))));
}
return b;
}
//https://docs.substrate.io/reference/scale-codec/
function toTruncBytes(uint64 x) internal pure returns (bytes memory) {
bytes memory b = new bytes(8);
uint len = 0;
for (uint i = 0; i < 8; i++) {
uint8 temp = uint8(x / (2 ** (8 * i)));
if (temp != 0) {
b[i] = bytes1(temp);
} else {
len = i;
break;
}
}
bytes memory rst = new bytes(len);
for (uint i = 0; i < len; i++) {
rst[i] = b[i];
}
return rst;
}
// Convert an hexadecimal character to their value
function fromScaleChar(uint8 c) internal pure returns (uint8) {
if (bytes1(c) >= bytes1("0") && bytes1(c) <= bytes1("9")) {
return 48 + c - uint8(bytes1("0"));
}
if (bytes1(c) >= bytes1("a") && bytes1(c) <= bytes1("z")) {
return 97 + c - uint8(bytes1("a"));
}
if (bytes1(c) >= bytes1("A") && bytes1(c) <= bytes1("Z")) {
return 65 + c - uint8(bytes1("A"));
}
revert("fail");
}
// encode the string to bytes
// following the scale format
// format: len + content
// a-z: 61->87
// A-Z: 41->57
// 0-9: 30->40
function toScaleString(
string memory s
) internal pure returns (bytes memory) {
bytes memory ss = bytes(s);
bytes memory len = toTruncBytes(uint64(ss.length * 4));
bytes memory content = new bytes(ss.length);
for (uint i = 0; i < ss.length; ++i) {
content[i] = bytes1(fromScaleChar(uint8(ss[i])));
}
bytes memory rst = bytes.concat(len, content);
return rst;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {
"contracts/utils/AddressToAccount.sol": {
"AddressToAccount": "0x2fd8bbf5dc8b342c09abf34f211b3488e2d9d691"
},
"contracts/utils/BuildCallData.sol": {
"BuildCallData": "0x5d0fe2b02d449e47715596cd256e59d501109519"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"derivativeAddress","type":"address"}],"name":"SetDerivativeAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"scriptTrigger","type":"address"},{"indexed":true,"internalType":"uint256","name":"layerZeroFee","type":"uint256"}],"name":"SetLayerZeroFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"scriptTrigger","type":"address"}],"name":"SetScriptTrigger","type":"event"},{"inputs":[],"name":"BNC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANTA","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VMANTA","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"callerToDerivativeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes","name":"_adapterParams","type":"bytes"}],"name":"claimManta","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes","name":"_adapterParams","type":"bytes"}],"name":"claimVManta","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"destChainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"layerZeroFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mantaOFT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mantaPacificSlpx","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"onOFTReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"scriptTrigger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setDerivativeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_layerZeroFee","type":"uint256"}],"name":"setLayerZeroFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mantaPacificSlpx","type":"address"}],"name":"setRemoteContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_scriptTrigger","type":"address"}],"name":"setScriptTrigger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"slpx","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vMantaProxyOFT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6126998061007e6000396000f3fe60806040526004361061012a5760003560e01c8063a7fd9c6b116100ab578063c24133971161006f578063c241339714610339578063c4af1c0b14610359578063f012945314610381578063f17e1d3d146103a9578063f29588c7146103d1578063f2fde38b146103f957600080fd5b8063a7fd9c6b1461028c578063a97d9f44146102c2578063ae83f844146102e6578063afd6aab714610306578063c0afb3f41461031957600080fd5b80635d76da01116100f25780635d76da01146101e9578063715018a6146102115780637fcf35da146102265780638da5cb5b14610246578063a6a6e9261461026457600080fd5b80630d1bf91f1461012f57806325a2236714610174578063357ba05f14610189578063525560ed146101a95780635d741b09146101c9575b600080fd5b34801561013b57600080fd5b5061015773debbb9309d95dabbfb82411a9c6daa3909b164a481565b6040516001600160a01b0390911681526020015b60405180910390f35b610187610182366004611a46565b610419565b005b34801561019557600080fd5b506101876101a4366004611a9b565b610804565b3480156101b557600080fd5b50600154610157906001600160a01b031681565b3480156101d557600080fd5b50600354610157906001600160a01b031681565b3480156101f557600080fd5b5061015773f1d4797e51a4640a76769a50b57abe7479add3d881565b34801561021d57600080fd5b5061018761087c565b34801561023257600080fd5b50610187610241366004611ace565b610890565b34801561025257600080fd5b506000546001600160a01b0316610157565b34801561027057600080fd5b5061015773ffffffffda2a05fb50e7ae99275f4341aed4337981565b34801561029857600080fd5b506101576102a7366004611a9b565b6004602052600090815260409020546001600160a01b031681565b3480156102ce57600080fd5b506102d860025481565b60405190815260200161016b565b3480156102f257600080fd5b50610187610301366004611b7f565b610cdf565b610187610314366004611a46565b610d52565b34801561032557600080fd5b50610187610334366004611a9b565b6110f8565b34801561034557600080fd5b50610187610354366004611a9b565b611178565b34801561036557600080fd5b5061036e60d981565b60405161ffff909116815260200161016b565b34801561038d57600080fd5b506101577317313ce6e47d796e61fdeac34ab1f58e3e08908281565b3480156103b557600080fd5b5061015773ffffffff7d3875460d4509eb8d0362c611b4e84181565b3480156103dd57600080fd5b5061015773ffffffff7cc06abdf7201b350a1265c62c8601d281565b34801561040557600080fd5b50610187610414366004611a9b565b61127d565b6003546001600160a01b0316336001600160a01b0316146104555760405162461bcd60e51b815260040161044c90611b98565b60405180910390fd5b6001600160a01b03808416600090815260046020526040902054168061048d5760405162461bcd60e51b815260040161044c90611bc7565b6040516308aea7fd60e41b815273ffffffffda2a05fb50e7ae99275f4341aed4337960048201526000906001600160a01b03831690638aea7fd0906024016020604051808303816000875af11580156104ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050e9190611bf0565b60405163095ea7b360e01b815273debbb9309d95dabbfb82411a9c6daa3909b164a460048201526024810182905290915073ffffffffda2a05fb50e7ae99275f4341aed433799063095ea7b3906044016020604051808303816000875af115801561057d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a19190611c09565b50600060405180606001604052806105b63390565b6001600160a01b0316815260200160006001600160a01b0316815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050604051630d94982d60e21b81529293506001600160a01b0389169290915073debbb9309d95dabbfb82411a9c6daa3909b164a49063365260b49061065f9060d9908690899087908e908e90600401611c2b565b6040805180830381865afa15801561067b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069f9190611c7c565b509050803410156106e25760405162461bcd60e51b815260206004820152600d60248201526c746f6f20736d616c6c2066656560981b604482015260640161044c565b8034146107865760006106f58234611ca0565b604051909150600090339083908381818185875af1925050503d806000811461073a576040519150601f19603f3d011682016040523d82523d6000602084013e61073f565b606091505b50509050806107835760405162461bcd60e51b815260206004820152601060248201526f19985a5b1959081d1bc81c99599d5b9960821b604482015260640161044c565b50505b60405163695ef6bf60e01b815273debbb9309d95dabbfb82411a9c6daa3909b164a49063695ef6bf9083906107c890309060d99088908b908b90600401611d21565b6000604051808303818588803b1580156107e157600080fd5b505af11580156107f5573d6000803e3d6000fd5b50505050505050505050505050565b61080c6112f6565b6001600160a01b0381166108325760405162461bcd60e51b815260040161044c90611bc7565b600380546001600160a01b0319166001600160a01b0383169081179091556040517fda100d63215e418eb5fdfcdb0b592f13bc6aea387392797c16c70caf4ea8772190600090a250565b6108846112f6565b61088e6000611350565b565b61ffff881660d9146108f05760405162461bcd60e51b815260206004820152602360248201527f6f6e6c792072656365697665206d73672066726f6d206d616e7461207061636960448201526266696360e81b606482015260840161044c565b337317313ce6e47d796e61fdeac34ab1f58e3e089082148061092557503373debbb9309d95dabbfb82411a9c6daa3909b164a4145b6109715760405162461bcd60e51b815260206004820152601860248201527f6f6e6c79206e6174697665206f66742063616e2063616c6c0000000000000000604482015260640161044c565b6001546001600160a01b038581169116146109dd5760405162461bcd60e51b815260206004820152602660248201527f6f6e6c792072656365697665206d73672066726f6d206d616e746150616369666044820152650d2c6a6d8e0f60d31b606482015260840161044c565b6000806109ec83850185611d88565b6001600160a01b0380831660009081526004602052604090205492945090925016610a1a57610a1a82611178565b6000337317313ce6e47d796e61fdeac34ab1f58e3e0890821415610b245760035460025460405163a9059cbb60e01b81526001600160a01b039092166004830152602482015260009073ffffffff7d3875460d4509eb8d0362c611b4e8419063a9059cbb906044016020604051808303816000875af1158015610aa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac59190611c09565b905080610b075760405162461bcd60e51b815260206004820152601060248201526f6661696c656420746f2063686172676560801b604482015260640161044c565b73ffffffff7d3875460d4509eb8d0362c611b4e841915050610c69565b3373debbb9309d95dabbfb82411a9c6daa3909b164a41415610c2c5760035460025460405163a9059cbb60e01b81526001600160a01b039092166004830152602482015260009073ffffffffda2a05fb50e7ae99275f4341aed433799063a9059cbb906044016020604051808303816000875af1158015610ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcd9190611c09565b905080610c0f5760405162461bcd60e51b815260206004820152601060248201526f6661696c656420746f2063686172676560801b604482015260640161044c565b73ffffffffda2a05fb50e7ae99275f4341aed43379915050610c69565b60405162461bcd60e51b815260206004820152601260248201527134b73b30b634b21036b9b39739b2b73232b960711b604482015260640161044c565b610cd283826001600160a01b03811673ffffffff7d3875460d4509eb8d0362c611b4e84114610c9d5761012160f31b610ca4565b61010160f31b5b600254610cb1908b611ca0565b6001600160a01b0380891660009081526004602052604090205416876113a0565b5050505050505050505050565b6003546001600160a01b0316336001600160a01b031614610d125760405162461bcd60e51b815260040161044c90611b98565b600281905560035460405182916001600160a01b0316907f405485c96e1fef0d0e7aa1b6bc6f839d6e825f49f9e5607dc07fcd69e098970690600090a350565b6003546001600160a01b0316336001600160a01b031614610d855760405162461bcd60e51b815260040161044c90611b98565b6001600160a01b038084166000908152600460205260409020541680610dbd5760405162461bcd60e51b815260040161044c90611bc7565b6040516308aea7fd60e41b815273ffffffff7d3875460d4509eb8d0362c611b4e84160048201526000906001600160a01b03831690638aea7fd0906024016020604051808303816000875af1158015610e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3e9190611bf0565b60405163095ea7b360e01b81527317313ce6e47d796e61fdeac34ab1f58e3e08908260048201526024810182905290915073ffffffff7d3875460d4509eb8d0362c611b4e8419063095ea7b3906044016020604051808303816000875af1158015610ead573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed19190611c09565b5060006040518060600160405280610ee63390565b6001600160a01b0316815260200160006001600160a01b0316815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050604051630d94982d60e21b81529293506001600160a01b038916929091507317313ce6e47d796e61fdeac34ab1f58e3e0890829063365260b490610f8f9060d9908690899087908e908e90600401611c2b565b6040805180830381865afa158015610fab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcf9190611c7c565b509050803410156110125760405162461bcd60e51b815260206004820152600d60248201526c746f6f20736d616c6c2066656560981b604482015260640161044c565b8034146110b65760006110258234611ca0565b604051909150600090339083908381818185875af1925050503d806000811461106a576040519150601f19603f3d011682016040523d82523d6000602084013e61106f565b606091505b50509050806110b35760405162461bcd60e51b815260206004820152601060248201526f19985a5b1959081d1bc81c99599d5b9960821b604482015260640161044c565b50505b60405163695ef6bf60e01b81527317313ce6e47d796e61fdeac34ab1f58e3e0890829063695ef6bf9083906107c890309060d99088908b908b90600401611d21565b6111006112f6565b6001600160a01b0381166111565760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964206d616e746150616369666963536c70780000000000000000604482015260640161044c565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381811660009081526004602052604090205416156111e05760405162461bcd60e51b815260206004820152601d60248201527f616c726561647920736574206465726976617469766541646472657373000000604482015260640161044c565b6000604051806020016111f2906119db565b601f1982820381018352601f9091011660405290506001600160a01b038216600061121e8183856115e6565b6001600160a01b0385811660008181526004602052604080822080546001600160a01b031916948616948517905551939450919290917f57b0e11e6397ba91fdcf1893a12f81fa7f83af6687a4c7c51bb7ec5cc87b700991a350505050565b6112856112f6565b6001600160a01b0381166112ea5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161044c565b6112f381611350565b50565b6000546001600160a01b0316331461088e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161044c565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000836001600160801b0316116113f95760405162461bcd60e51b815260206004820152601d60248201527f616d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161044c565b61140d8587856001600160801b03166116ee565b60408051600160f81b6020820152606084901b6bffffffffffffffffffffffff191660218201528151601581830301815260358201928390526309e4f00160e01b909252600091735d0fe2b02d449e47715596cd256e59d501109519916309e4f00191611489918b91469143918c918c91908b90603901611dca565b600060405180830381865af41580156114a6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114ce9190810190611e76565b9050600080600073f1d4797e51a4640a76769a50b57abe7479add3d86001600160a01b031663bddef61a60006040518263ffffffff1660e01b81526004016115169190611f23565b606060405180830381865afa158015611533573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115579190611f4b565b9194509250905061080d63b648f3fe61156e611836565b73ffffffff7cc06abdf7201b350a1265c62c8601d2868887876040518763ffffffff1660e01b81526004016115a896959493929190612001565b600060405180830381600087803b1580156115c257600080fd5b505af11580156115d6573d6000803e3d6000fd5b5050505050505050505050505050565b6000834710156116385760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e6365000000604482015260640161044c565b81516116865760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f604482015260640161044c565b8282516020840186f590506001600160a01b0381166116e75760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f7900000000000000604482015260640161044c565b9392505050565b6001600160a01b03831661173b5760405162461bcd60e51b8152602060048201526014602482015273496e76616c69642061737365744164647265737360601b604482015260640161044c565b604051631932052960e11b81526001600160a01b0383166004820152600090732fd8bbf5dc8b342c09abf34f211b3488e2d9d691906332640a5290602401602060405180830381865af4158015611796573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ba9190611bf0565b905060006117c7826118dd565b60405163b9f813ff60e01b81529091506108049063b9f813ff906117fd9088908790869067ffffffffffffffff90600401612063565b600060405180830381600087803b15801561181757600080fd5b505af115801561182b573d6000803e3d6000fd5b505050505050505050565b604080518082018252600080825260606020830152825160018082528185019094529192909190816020015b606081526020019060019003908161186257905050604051600060208201526103f760e11b6021820152909150602501604051602081830303815290604052816000815181106118b4576118b46120a5565b602090810291909101810191909152604080518082019091526001815290810191909152919050565b60408051808201825260008082526060602083018190528351600280825291810190945291929091816020015b606081526020019060019003908161190a57905050604051600060208201526103f760e11b60218201529091506025016040516020818303038152906040528160008151811061195c5761195c6120a5565b60200260200101819052508260405160200161198f9190600160f81b815260018101919091526000602182015260220190565b604051602081830303815290604052816001815181106119b1576119b16120a5565b60209081029190910181019190915260408051808201909152600181529081019190915292915050565b6105a8806120bc83390190565b6001600160a01b03811681146112f357600080fd5b60008083601f840112611a0f57600080fd5b50813567ffffffffffffffff811115611a2757600080fd5b602083019150836020828501011115611a3f57600080fd5b9250929050565b600080600060408486031215611a5b57600080fd5b8335611a66816119e8565b9250602084013567ffffffffffffffff811115611a8257600080fd5b611a8e868287016119fd565b9497909650939450505050565b600060208284031215611aad57600080fd5b81356116e7816119e8565b67ffffffffffffffff811681146112f357600080fd5b60008060008060008060008060c0898b031215611aea57600080fd5b883561ffff81168114611afc57600080fd5b9750602089013567ffffffffffffffff80821115611b1957600080fd5b611b258c838d016119fd565b909950975060408b01359150611b3a82611ab8565b90955060608a0135945060808a0135935060a08a01359080821115611b5e57600080fd5b50611b6b8b828c016119fd565b999c989b5096995094979396929594505050565b600060208284031215611b9157600080fd5b5035919050565b60208082526015908201527436bab9ba1031329039b1b934b83a2a3934b3b3b2b960591b604082015260600190565b6020808252600f908201526e696e76616c6964206164647265737360881b604082015260600190565b600060208284031215611c0257600080fd5b5051919050565b600060208284031215611c1b57600080fd5b815180151581146116e757600080fd5b61ffff87168152856020820152846040820152831515606082015260a060808201528160a0820152818360c0830137600081830160c090810191909152601f909201601f1916010195945050505050565b60008060408385031215611c8f57600080fd5b505080516020909101519092909150565b600082821015611cc057634e487b7160e01b600052601160045260246000fd5b500390565b60005b83811015611ce0578181015183820152602001611cc8565b83811115611cef576000848401525b50505050565b60008151808452611d0d816020860160208601611cc5565b601f01601f19169290920160200192915050565b600060018060a01b03808816835261ffff8716602084015285604084015284606084015260a060808401528084511660a08401528060208501511660c0840152506040830151606060e0840152611d7c610100840182611cf5565b98975050505050505050565b60008060408385031215611d9b57600080fd5b8235611da6816119e8565b9150602083013563ffffffff81168114611dbf57600080fd5b809150509250929050565b6001600160a01b038816815260208101879052604081018690526001600160f01b0319851660608201526001600160801b038416608082015261010060a08201819052600090611e1c83820186611cf5565b905082810360c0840152600e81526d26b0b73a30a830b1b4b334b1ab1960911b60208201526040810191505063ffffffff831660e083015298975050505050505050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215611e8857600080fd5b815167ffffffffffffffff80821115611ea057600080fd5b818401915084601f830112611eb457600080fd5b815181811115611ec657611ec6611e60565b604051601f8201601f19908116603f01168101908382118183101715611eee57611eee611e60565b81604052828152876020848701011115611f0757600080fd5b611f18836020830160208801611cc5565b979650505050505050565b6020810160048310611f4557634e487b7160e01b600052602160045260246000fd5b91905290565b600080600060608486031215611f6057600080fd5b8351611f6b81611ab8565b602085015160408601519194509250611f8381611ab8565b809150509250925092565b60006040830160ff835116845260208084015160408287015282815180855260608801915060608160051b8901019450838301925060005b81811015611ff457605f19898703018352611fe2868551611cf5565b95509284019291840191600101611fc6565b5093979650505050505050565b60c08152600061201460c0830189611f8e565b6001600160a01b038816602084015267ffffffffffffffff878116604085015283820360608501526120468288611cf5565b925085608085015280851660a08501525050979650505050505050565b60018060a01b038516815283602082015260806040820152600061208a6080830185611f8e565b905067ffffffffffffffff8316606083015295945050505050565b634e487b7160e01b600052603260045260246000fdfe608060405234801561001057600080fd5b506001600081905580546001600160a01b03191633179055610571806100376000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806317e0f252146100465780638aea7fd01461005b578063f7260d3e14610081575b600080fd5b6100596100543660046104b7565b6100ac565b005b61006e6100693660046104d0565b610240565b6040519081526020015b60405180910390f35b600154610094906001600160a01b031681565b6040516001600160a01b039091168152602001610078565b6100b461045d565b6001546001600160a01b031633146100ff5760405162461bcd60e51b81526020600482015260096024820152683337b93134b23232b760b91b60448201526064015b60405180910390fd5b8061013d5760405162461bcd60e51b815260206004820152600e60248201526d62616c616e636520746f206c6f7760901b60448201526064016100f6565b6001546040516000916001600160a01b03169083908381818185875af1925050503d806000811461018a576040519150601f19603f3d011682016040523d82523d6000602084013e61018f565b606091505b50509050806101e05760405162461bcd60e51b815260206004820152601d60248201527f6661696c656420746f2077697468647261774e6174697665546f6b656e00000060448201526064016100f6565b600154604080513381526001600160a01b03909216602083015260008282015260608201849052517f3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f79181900360800190a15061023d6001600055565b50565b600061024a61045d565b6001546001600160a01b031633146102905760405162461bcd60e51b81526020600482015260096024820152683337b93134b23232b760b91b60448201526064016100f6565b6001600160a01b0382166102d65760405162461bcd60e51b815260206004820152600d60248201526c0696e76616c696420657263323609c1b60448201526064016100f6565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561031d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103419190610500565b9050806103815760405162461bcd60e51b815260206004820152600e60248201526d62616c616e636520746f206c6f7760901b60448201526064016100f6565b60015460405163a9059cbb60e01b81526001600160a01b039182166004820152602481018390529084169063a9059cbb906044016020604051808303816000875af11580156103d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f89190610519565b50600154604080513381526001600160a01b0392831660208201529185168282015260608201839052517f3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f79181900360800190a190506104586001600055565b919050565b600260005414156104b05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016100f6565b6002600055565b6000602082840312156104c957600080fd5b5035919050565b6000602082840312156104e257600080fd5b81356001600160a01b03811681146104f957600080fd5b9392505050565b60006020828403121561051257600080fd5b5051919050565b60006020828403121561052b57600080fd5b815180151581146104f957600080fdfea26469706673582212208cdaeacfdd5c4018a525a04627735e0394975d213762f15d3134e53ec33ca9a164736f6c634300080a0033a2646970667358221220b7bcb807772d4af83d75b6cb351240918152db91939504b144944482c690acfa64736f6c634300080a0033
Deployed Bytecode
0x60806040526004361061012a5760003560e01c8063a7fd9c6b116100ab578063c24133971161006f578063c241339714610339578063c4af1c0b14610359578063f012945314610381578063f17e1d3d146103a9578063f29588c7146103d1578063f2fde38b146103f957600080fd5b8063a7fd9c6b1461028c578063a97d9f44146102c2578063ae83f844146102e6578063afd6aab714610306578063c0afb3f41461031957600080fd5b80635d76da01116100f25780635d76da01146101e9578063715018a6146102115780637fcf35da146102265780638da5cb5b14610246578063a6a6e9261461026457600080fd5b80630d1bf91f1461012f57806325a2236714610174578063357ba05f14610189578063525560ed146101a95780635d741b09146101c9575b600080fd5b34801561013b57600080fd5b5061015773debbb9309d95dabbfb82411a9c6daa3909b164a481565b6040516001600160a01b0390911681526020015b60405180910390f35b610187610182366004611a46565b610419565b005b34801561019557600080fd5b506101876101a4366004611a9b565b610804565b3480156101b557600080fd5b50600154610157906001600160a01b031681565b3480156101d557600080fd5b50600354610157906001600160a01b031681565b3480156101f557600080fd5b5061015773f1d4797e51a4640a76769a50b57abe7479add3d881565b34801561021d57600080fd5b5061018761087c565b34801561023257600080fd5b50610187610241366004611ace565b610890565b34801561025257600080fd5b506000546001600160a01b0316610157565b34801561027057600080fd5b5061015773ffffffffda2a05fb50e7ae99275f4341aed4337981565b34801561029857600080fd5b506101576102a7366004611a9b565b6004602052600090815260409020546001600160a01b031681565b3480156102ce57600080fd5b506102d860025481565b60405190815260200161016b565b3480156102f257600080fd5b50610187610301366004611b7f565b610cdf565b610187610314366004611a46565b610d52565b34801561032557600080fd5b50610187610334366004611a9b565b6110f8565b34801561034557600080fd5b50610187610354366004611a9b565b611178565b34801561036557600080fd5b5061036e60d981565b60405161ffff909116815260200161016b565b34801561038d57600080fd5b506101577317313ce6e47d796e61fdeac34ab1f58e3e08908281565b3480156103b557600080fd5b5061015773ffffffff7d3875460d4509eb8d0362c611b4e84181565b3480156103dd57600080fd5b5061015773ffffffff7cc06abdf7201b350a1265c62c8601d281565b34801561040557600080fd5b50610187610414366004611a9b565b61127d565b6003546001600160a01b0316336001600160a01b0316146104555760405162461bcd60e51b815260040161044c90611b98565b60405180910390fd5b6001600160a01b03808416600090815260046020526040902054168061048d5760405162461bcd60e51b815260040161044c90611bc7565b6040516308aea7fd60e41b815273ffffffffda2a05fb50e7ae99275f4341aed4337960048201526000906001600160a01b03831690638aea7fd0906024016020604051808303816000875af11580156104ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050e9190611bf0565b60405163095ea7b360e01b815273debbb9309d95dabbfb82411a9c6daa3909b164a460048201526024810182905290915073ffffffffda2a05fb50e7ae99275f4341aed433799063095ea7b3906044016020604051808303816000875af115801561057d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a19190611c09565b50600060405180606001604052806105b63390565b6001600160a01b0316815260200160006001600160a01b0316815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050604051630d94982d60e21b81529293506001600160a01b0389169290915073debbb9309d95dabbfb82411a9c6daa3909b164a49063365260b49061065f9060d9908690899087908e908e90600401611c2b565b6040805180830381865afa15801561067b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069f9190611c7c565b509050803410156106e25760405162461bcd60e51b815260206004820152600d60248201526c746f6f20736d616c6c2066656560981b604482015260640161044c565b8034146107865760006106f58234611ca0565b604051909150600090339083908381818185875af1925050503d806000811461073a576040519150601f19603f3d011682016040523d82523d6000602084013e61073f565b606091505b50509050806107835760405162461bcd60e51b815260206004820152601060248201526f19985a5b1959081d1bc81c99599d5b9960821b604482015260640161044c565b50505b60405163695ef6bf60e01b815273debbb9309d95dabbfb82411a9c6daa3909b164a49063695ef6bf9083906107c890309060d99088908b908b90600401611d21565b6000604051808303818588803b1580156107e157600080fd5b505af11580156107f5573d6000803e3d6000fd5b50505050505050505050505050565b61080c6112f6565b6001600160a01b0381166108325760405162461bcd60e51b815260040161044c90611bc7565b600380546001600160a01b0319166001600160a01b0383169081179091556040517fda100d63215e418eb5fdfcdb0b592f13bc6aea387392797c16c70caf4ea8772190600090a250565b6108846112f6565b61088e6000611350565b565b61ffff881660d9146108f05760405162461bcd60e51b815260206004820152602360248201527f6f6e6c792072656365697665206d73672066726f6d206d616e7461207061636960448201526266696360e81b606482015260840161044c565b337317313ce6e47d796e61fdeac34ab1f58e3e089082148061092557503373debbb9309d95dabbfb82411a9c6daa3909b164a4145b6109715760405162461bcd60e51b815260206004820152601860248201527f6f6e6c79206e6174697665206f66742063616e2063616c6c0000000000000000604482015260640161044c565b6001546001600160a01b038581169116146109dd5760405162461bcd60e51b815260206004820152602660248201527f6f6e6c792072656365697665206d73672066726f6d206d616e746150616369666044820152650d2c6a6d8e0f60d31b606482015260840161044c565b6000806109ec83850185611d88565b6001600160a01b0380831660009081526004602052604090205492945090925016610a1a57610a1a82611178565b6000337317313ce6e47d796e61fdeac34ab1f58e3e0890821415610b245760035460025460405163a9059cbb60e01b81526001600160a01b039092166004830152602482015260009073ffffffff7d3875460d4509eb8d0362c611b4e8419063a9059cbb906044016020604051808303816000875af1158015610aa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac59190611c09565b905080610b075760405162461bcd60e51b815260206004820152601060248201526f6661696c656420746f2063686172676560801b604482015260640161044c565b73ffffffff7d3875460d4509eb8d0362c611b4e841915050610c69565b3373debbb9309d95dabbfb82411a9c6daa3909b164a41415610c2c5760035460025460405163a9059cbb60e01b81526001600160a01b039092166004830152602482015260009073ffffffffda2a05fb50e7ae99275f4341aed433799063a9059cbb906044016020604051808303816000875af1158015610ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcd9190611c09565b905080610c0f5760405162461bcd60e51b815260206004820152601060248201526f6661696c656420746f2063686172676560801b604482015260640161044c565b73ffffffffda2a05fb50e7ae99275f4341aed43379915050610c69565b60405162461bcd60e51b815260206004820152601260248201527134b73b30b634b21036b9b39739b2b73232b960711b604482015260640161044c565b610cd283826001600160a01b03811673ffffffff7d3875460d4509eb8d0362c611b4e84114610c9d5761012160f31b610ca4565b61010160f31b5b600254610cb1908b611ca0565b6001600160a01b0380891660009081526004602052604090205416876113a0565b5050505050505050505050565b6003546001600160a01b0316336001600160a01b031614610d125760405162461bcd60e51b815260040161044c90611b98565b600281905560035460405182916001600160a01b0316907f405485c96e1fef0d0e7aa1b6bc6f839d6e825f49f9e5607dc07fcd69e098970690600090a350565b6003546001600160a01b0316336001600160a01b031614610d855760405162461bcd60e51b815260040161044c90611b98565b6001600160a01b038084166000908152600460205260409020541680610dbd5760405162461bcd60e51b815260040161044c90611bc7565b6040516308aea7fd60e41b815273ffffffff7d3875460d4509eb8d0362c611b4e84160048201526000906001600160a01b03831690638aea7fd0906024016020604051808303816000875af1158015610e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3e9190611bf0565b60405163095ea7b360e01b81527317313ce6e47d796e61fdeac34ab1f58e3e08908260048201526024810182905290915073ffffffff7d3875460d4509eb8d0362c611b4e8419063095ea7b3906044016020604051808303816000875af1158015610ead573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed19190611c09565b5060006040518060600160405280610ee63390565b6001600160a01b0316815260200160006001600160a01b0316815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050604051630d94982d60e21b81529293506001600160a01b038916929091507317313ce6e47d796e61fdeac34ab1f58e3e0890829063365260b490610f8f9060d9908690899087908e908e90600401611c2b565b6040805180830381865afa158015610fab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcf9190611c7c565b509050803410156110125760405162461bcd60e51b815260206004820152600d60248201526c746f6f20736d616c6c2066656560981b604482015260640161044c565b8034146110b65760006110258234611ca0565b604051909150600090339083908381818185875af1925050503d806000811461106a576040519150601f19603f3d011682016040523d82523d6000602084013e61106f565b606091505b50509050806110b35760405162461bcd60e51b815260206004820152601060248201526f19985a5b1959081d1bc81c99599d5b9960821b604482015260640161044c565b50505b60405163695ef6bf60e01b81527317313ce6e47d796e61fdeac34ab1f58e3e0890829063695ef6bf9083906107c890309060d99088908b908b90600401611d21565b6111006112f6565b6001600160a01b0381166111565760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964206d616e746150616369666963536c70780000000000000000604482015260640161044c565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381811660009081526004602052604090205416156111e05760405162461bcd60e51b815260206004820152601d60248201527f616c726561647920736574206465726976617469766541646472657373000000604482015260640161044c565b6000604051806020016111f2906119db565b601f1982820381018352601f9091011660405290506001600160a01b038216600061121e8183856115e6565b6001600160a01b0385811660008181526004602052604080822080546001600160a01b031916948616948517905551939450919290917f57b0e11e6397ba91fdcf1893a12f81fa7f83af6687a4c7c51bb7ec5cc87b700991a350505050565b6112856112f6565b6001600160a01b0381166112ea5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161044c565b6112f381611350565b50565b6000546001600160a01b0316331461088e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161044c565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000836001600160801b0316116113f95760405162461bcd60e51b815260206004820152601d60248201527f616d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161044c565b61140d8587856001600160801b03166116ee565b60408051600160f81b6020820152606084901b6bffffffffffffffffffffffff191660218201528151601581830301815260358201928390526309e4f00160e01b909252600091735d0fe2b02d449e47715596cd256e59d501109519916309e4f00191611489918b91469143918c918c91908b90603901611dca565b600060405180830381865af41580156114a6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114ce9190810190611e76565b9050600080600073f1d4797e51a4640a76769a50b57abe7479add3d86001600160a01b031663bddef61a60006040518263ffffffff1660e01b81526004016115169190611f23565b606060405180830381865afa158015611533573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115579190611f4b565b9194509250905061080d63b648f3fe61156e611836565b73ffffffff7cc06abdf7201b350a1265c62c8601d2868887876040518763ffffffff1660e01b81526004016115a896959493929190612001565b600060405180830381600087803b1580156115c257600080fd5b505af11580156115d6573d6000803e3d6000fd5b5050505050505050505050505050565b6000834710156116385760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e6365000000604482015260640161044c565b81516116865760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f604482015260640161044c565b8282516020840186f590506001600160a01b0381166116e75760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f7900000000000000604482015260640161044c565b9392505050565b6001600160a01b03831661173b5760405162461bcd60e51b8152602060048201526014602482015273496e76616c69642061737365744164647265737360601b604482015260640161044c565b604051631932052960e11b81526001600160a01b0383166004820152600090732fd8bbf5dc8b342c09abf34f211b3488e2d9d691906332640a5290602401602060405180830381865af4158015611796573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ba9190611bf0565b905060006117c7826118dd565b60405163b9f813ff60e01b81529091506108049063b9f813ff906117fd9088908790869067ffffffffffffffff90600401612063565b600060405180830381600087803b15801561181757600080fd5b505af115801561182b573d6000803e3d6000fd5b505050505050505050565b604080518082018252600080825260606020830152825160018082528185019094529192909190816020015b606081526020019060019003908161186257905050604051600060208201526103f760e11b6021820152909150602501604051602081830303815290604052816000815181106118b4576118b46120a5565b602090810291909101810191909152604080518082019091526001815290810191909152919050565b60408051808201825260008082526060602083018190528351600280825291810190945291929091816020015b606081526020019060019003908161190a57905050604051600060208201526103f760e11b60218201529091506025016040516020818303038152906040528160008151811061195c5761195c6120a5565b60200260200101819052508260405160200161198f9190600160f81b815260018101919091526000602182015260220190565b604051602081830303815290604052816001815181106119b1576119b16120a5565b60209081029190910181019190915260408051808201909152600181529081019190915292915050565b6105a8806120bc83390190565b6001600160a01b03811681146112f357600080fd5b60008083601f840112611a0f57600080fd5b50813567ffffffffffffffff811115611a2757600080fd5b602083019150836020828501011115611a3f57600080fd5b9250929050565b600080600060408486031215611a5b57600080fd5b8335611a66816119e8565b9250602084013567ffffffffffffffff811115611a8257600080fd5b611a8e868287016119fd565b9497909650939450505050565b600060208284031215611aad57600080fd5b81356116e7816119e8565b67ffffffffffffffff811681146112f357600080fd5b60008060008060008060008060c0898b031215611aea57600080fd5b883561ffff81168114611afc57600080fd5b9750602089013567ffffffffffffffff80821115611b1957600080fd5b611b258c838d016119fd565b909950975060408b01359150611b3a82611ab8565b90955060608a0135945060808a0135935060a08a01359080821115611b5e57600080fd5b50611b6b8b828c016119fd565b999c989b5096995094979396929594505050565b600060208284031215611b9157600080fd5b5035919050565b60208082526015908201527436bab9ba1031329039b1b934b83a2a3934b3b3b2b960591b604082015260600190565b6020808252600f908201526e696e76616c6964206164647265737360881b604082015260600190565b600060208284031215611c0257600080fd5b5051919050565b600060208284031215611c1b57600080fd5b815180151581146116e757600080fd5b61ffff87168152856020820152846040820152831515606082015260a060808201528160a0820152818360c0830137600081830160c090810191909152601f909201601f1916010195945050505050565b60008060408385031215611c8f57600080fd5b505080516020909101519092909150565b600082821015611cc057634e487b7160e01b600052601160045260246000fd5b500390565b60005b83811015611ce0578181015183820152602001611cc8565b83811115611cef576000848401525b50505050565b60008151808452611d0d816020860160208601611cc5565b601f01601f19169290920160200192915050565b600060018060a01b03808816835261ffff8716602084015285604084015284606084015260a060808401528084511660a08401528060208501511660c0840152506040830151606060e0840152611d7c610100840182611cf5565b98975050505050505050565b60008060408385031215611d9b57600080fd5b8235611da6816119e8565b9150602083013563ffffffff81168114611dbf57600080fd5b809150509250929050565b6001600160a01b038816815260208101879052604081018690526001600160f01b0319851660608201526001600160801b038416608082015261010060a08201819052600090611e1c83820186611cf5565b905082810360c0840152600e81526d26b0b73a30a830b1b4b334b1ab1960911b60208201526040810191505063ffffffff831660e083015298975050505050505050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215611e8857600080fd5b815167ffffffffffffffff80821115611ea057600080fd5b818401915084601f830112611eb457600080fd5b815181811115611ec657611ec6611e60565b604051601f8201601f19908116603f01168101908382118183101715611eee57611eee611e60565b81604052828152876020848701011115611f0757600080fd5b611f18836020830160208801611cc5565b979650505050505050565b6020810160048310611f4557634e487b7160e01b600052602160045260246000fd5b91905290565b600080600060608486031215611f6057600080fd5b8351611f6b81611ab8565b602085015160408601519194509250611f8381611ab8565b809150509250925092565b60006040830160ff835116845260208084015160408287015282815180855260608801915060608160051b8901019450838301925060005b81811015611ff457605f19898703018352611fe2868551611cf5565b95509284019291840191600101611fc6565b5093979650505050505050565b60c08152600061201460c0830189611f8e565b6001600160a01b038816602084015267ffffffffffffffff878116604085015283820360608501526120468288611cf5565b925085608085015280851660a08501525050979650505050505050565b60018060a01b038516815283602082015260806040820152600061208a6080830185611f8e565b905067ffffffffffffffff8316606083015295945050505050565b634e487b7160e01b600052603260045260246000fdfe608060405234801561001057600080fd5b506001600081905580546001600160a01b03191633179055610571806100376000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806317e0f252146100465780638aea7fd01461005b578063f7260d3e14610081575b600080fd5b6100596100543660046104b7565b6100ac565b005b61006e6100693660046104d0565b610240565b6040519081526020015b60405180910390f35b600154610094906001600160a01b031681565b6040516001600160a01b039091168152602001610078565b6100b461045d565b6001546001600160a01b031633146100ff5760405162461bcd60e51b81526020600482015260096024820152683337b93134b23232b760b91b60448201526064015b60405180910390fd5b8061013d5760405162461bcd60e51b815260206004820152600e60248201526d62616c616e636520746f206c6f7760901b60448201526064016100f6565b6001546040516000916001600160a01b03169083908381818185875af1925050503d806000811461018a576040519150601f19603f3d011682016040523d82523d6000602084013e61018f565b606091505b50509050806101e05760405162461bcd60e51b815260206004820152601d60248201527f6661696c656420746f2077697468647261774e6174697665546f6b656e00000060448201526064016100f6565b600154604080513381526001600160a01b03909216602083015260008282015260608201849052517f3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f79181900360800190a15061023d6001600055565b50565b600061024a61045d565b6001546001600160a01b031633146102905760405162461bcd60e51b81526020600482015260096024820152683337b93134b23232b760b91b60448201526064016100f6565b6001600160a01b0382166102d65760405162461bcd60e51b815260206004820152600d60248201526c0696e76616c696420657263323609c1b60448201526064016100f6565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561031d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103419190610500565b9050806103815760405162461bcd60e51b815260206004820152600e60248201526d62616c616e636520746f206c6f7760901b60448201526064016100f6565b60015460405163a9059cbb60e01b81526001600160a01b039182166004820152602481018390529084169063a9059cbb906044016020604051808303816000875af11580156103d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f89190610519565b50600154604080513381526001600160a01b0392831660208201529185168282015260608201839052517f3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f79181900360800190a190506104586001600055565b919050565b600260005414156104b05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016100f6565b6002600055565b6000602082840312156104c957600080fd5b5035919050565b6000602082840312156104e257600080fd5b81356001600160a01b03811681146104f957600080fd5b9392505050565b60006020828403121561051257600080fd5b5051919050565b60006020828403121561052b57600080fd5b815180151581146104f957600080fdfea26469706673582212208cdaeacfdd5c4018a525a04627735e0394975d213762f15d3134e53ec33ca9a164736f6c634300080a0033a2646970667358221220b7bcb807772d4af83d75b6cb351240918152db91939504b144944482c690acfa64736f6c634300080a0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.38
Net Worth in GLMR
Token Allocations
XCVGLMR
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| GLMR | 100.00% | $0.038033 | 9.8888 | $0.376 |
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.