More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 317 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Claim Manta | 8565497 | 2 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim Manta | 8565448 | 2 hrs ago | IN | 1 GLMR | 0.02679371 | ||||
Claim Manta | 8565448 | 2 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim Manta | 8564756 | 3 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim Manta | 8564706 | 3 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim Manta | 8564659 | 4 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim V Manta | 8562429 | 7 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim V Manta | 8562284 | 8 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim Manta | 8557289 | 16 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim V Manta | 8555996 | 18 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim V Manta | 8554250 | 21 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim V Manta | 8553903 | 22 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim V Manta | 8553803 | 22 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim V Manta | 8551961 | 25 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim V Manta | 8551911 | 25 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim V Manta | 8551812 | 25 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim V Manta | 8549931 | 28 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim Manta | 8549290 | 29 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim Manta | 8549242 | 30 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim Manta | 8549197 | 30 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim Manta | 8549150 | 30 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim V Manta | 8549103 | 30 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim Manta | 8546386 | 34 hrs ago | IN | 1 GLMR | 0.30416672 | ||||
Claim V Manta | 8546283 | 35 hrs ago | IN | 1 GLMR | 0.30344415 | ||||
Claim V Manta | 8544742 | 37 hrs ago | IN | 1 GLMR | 0.30344415 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
8565519 | 2 hrs ago | Contract Creation | 0 GLMR | |||
8565497 | 2 hrs ago | 0.33150764 GLMR | ||||
8565497 | 2 hrs ago | 0.66849235 GLMR | ||||
8565448 | 2 hrs ago | 0.33150764 GLMR | ||||
8565448 | 2 hrs ago | 0.66849235 GLMR | ||||
8565125 | 3 hrs ago | Contract Creation | 0 GLMR | |||
8564756 | 3 hrs ago | 0.33150764 GLMR | ||||
8564756 | 3 hrs ago | 0.66849235 GLMR | ||||
8564706 | 3 hrs ago | 0.33150764 GLMR | ||||
8564706 | 3 hrs ago | 0.66849235 GLMR | ||||
8564659 | 4 hrs ago | 0.33150764 GLMR | ||||
8564659 | 4 hrs ago | 0.66849235 GLMR | ||||
8562429 | 7 hrs ago | 0.33150764 GLMR | ||||
8562429 | 7 hrs ago | 0.66849235 GLMR | ||||
8562284 | 8 hrs ago | 0.33150764 GLMR | ||||
8562284 | 8 hrs ago | 0.66849235 GLMR | ||||
8560217 | 11 hrs ago | Contract Creation | 0 GLMR | |||
8557289 | 16 hrs ago | 0.33150764 GLMR | ||||
8557289 | 16 hrs ago | 0.66849235 GLMR | ||||
8556273 | 18 hrs ago | Contract Creation | 0 GLMR | |||
8555996 | 18 hrs ago | 0.33150764 GLMR | ||||
8555996 | 18 hrs ago | 0.66849235 GLMR | ||||
8555945 | 18 hrs ago | Contract Creation | 0 GLMR | |||
8554250 | 21 hrs ago | 0.33150764 GLMR | ||||
8554250 | 21 hrs ago | 0.66849235 GLMR |
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
[{"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
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.