Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
FarmFacet
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.8.19; import {IOwnable} from "@solidstate/contracts/access/ownable/IOwnable.sol"; import {LibFarmStorage} from "./LibFarmStorage.sol"; import {Scale} from "../tokens/Scale.sol"; import {ReentrancyGuard} from "@solidstate/contracts/security/reentrancy_guard/ReentrancyGuard.sol"; import {Pausable} from "@solidstate/contracts/security/pausable/Pausable.sol"; import {OwnableInternal} from "@solidstate/contracts/access/ownable/OwnableInternal.sol"; interface IUniswapV2Router02 { function factory() external pure returns (address); function WETH() external pure returns (address); function swapExactTokensForETHSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external; function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function getAmountsOut( uint amountIn, address[] memory path ) external view returns (uint[] memory amounts); function getAmountsIn( uint amountOut, address[] memory path ) external view returns (uint[] memory amounts); } interface IERC20 { function totalSupply() external view returns (uint); function balanceOf(address account) external view returns (uint); function transfer(address recipient, uint amount) external returns (bool); function allowance( address owner, address spender ) external view returns (uint); function approve(address spender, uint amount) external returns (bool); function transferFrom( address sender, address recipient, uint amount ) external returns (bool); event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); } contract FarmFacet is IERC20, ReentrancyGuard, Pausable, OwnableInternal { uint256 private constant MULTIPLIER = 1 ether; error FarmFacet__MinLockDuration(); error FarmFacet__NotLocker(); error FarmFacet__AlreadyUnlocked(); error FarmFacet__StillLocked(uint256 _timeLeft); error FarmFacet__NotEnoughRewards(); error FarmFacet__AlreadyVested(); error FarmFacet__NotVester(); error FarmFacet__NotTransferable(); error FarmFacet__InvalidDuration(); modifier setLastRewardBalance() { _; LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); fs.lastRewardBalance = Scale(payable(fs.rewardToken)).baseBalanceOf( address(this) ); } /* internal */ function updateRewardIndex(uint reward) internal { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); if (fs.totalSupply != 0) { Scale _scale = Scale(payable(fs.rewardToken)); uint256 currentRewardBalance = _scale.baseBalanceOf(address(this)); // if S is directly transferred to contract via ERC20.transfer() if (reward == 0 && currentRewardBalance > fs.lastRewardBalance) { reward = currentRewardBalance - fs.lastRewardBalance; } fs.rewardIndex = fs.rewardIndex + ((reward * MULTIPLIER) / fs.totalSupply); } } function _calculateRewards(address account) internal view returns (uint) { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); uint shares = fs.balanceOf[account]; return (shares * (fs.rewardIndex - fs.rewardIndexOf[account])) / MULTIPLIER; } function _updateRewards(address account) internal { updateRewardIndex(0); LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); fs.earned[account] = fs.earned[account] + _calculateRewards(account); fs.rewardIndexOf[account] = fs.rewardIndex; } /* public */ function lock( uint amount, uint256 duration ) external whenNotPaused nonReentrant setLastRewardBalance { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); uint maxLockDuration = fs.maxLockDuration; uint minLockDuration = fs.minLockDuration; if (duration < minLockDuration) revert FarmFacet__MinLockDuration(); if (duration > maxLockDuration) duration = maxLockDuration; _updateRewards(msg.sender); uint receiptAmount = duration >= maxLockDuration ? amount : _getReceiptAmount(amount, duration, minLockDuration, maxLockDuration); // create lock fs.currentLockingIndex = fs.currentLockingIndex + 1; fs.lockingIndexToLock[fs.currentLockingIndex] = LibFarmStorage.Lock({ startTimestamp: block.timestamp, amount: amount, receiptAmount: receiptAmount, duration: duration, unlocked: 0, locker: msg.sender }); uint256[] storage userLockingIndexList = fs.addressToLockingIndexList[ msg.sender ]; userLockingIndexList.push(fs.currentLockingIndex); // mint receipt tokens fs.balanceOf[msg.sender] = fs.balanceOf[msg.sender] + receiptAmount; fs.totalSupply = fs.totalSupply + receiptAmount; IERC20(fs.stakingToken).transferFrom(msg.sender, address(this), amount); } function unlock( uint _lockingIndex ) external whenNotPaused nonReentrant setLastRewardBalance { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); LibFarmStorage.Lock storage _lock = fs.lockingIndexToLock[ _lockingIndex ]; if (_lock.locker != msg.sender) revert FarmFacet__NotLocker(); // prevent others from unlocking your lock if (_lock.unlocked != 0) revert FarmFacet__AlreadyUnlocked(); // prevent double spending if (_lock.startTimestamp + _lock.duration > block.timestamp) revert FarmFacet__StillLocked( _lock.startTimestamp + _lock.duration - block.timestamp ); // ensure lock period has passed _updateRewards(msg.sender); _lock.unlocked = 1; fs.balanceOf[msg.sender] = fs.balanceOf[msg.sender]- _lock.receiptAmount; fs.totalSupply = fs.totalSupply - _lock.receiptAmount; IERC20(fs.stakingToken).transfer(msg.sender, _lock.amount); } function vest() external whenNotPaused nonReentrant setLastRewardBalance { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); _updateRewards(msg.sender); if (fs.earned[msg.sender] <= fs.addressToTotalVesting[msg.sender]) revert FarmFacet__NotEnoughRewards(); // create vest uint256 vestAmount = fs.earned[msg.sender] - fs.addressToTotalVesting[msg.sender]; fs.currentVestIndex = fs.currentVestIndex + 1; fs.vestIndexToVest[fs.currentVestIndex] = LibFarmStorage.Vest({ startTimestamp: block.timestamp, amount: vestAmount, vested: 0, vester: msg.sender }); fs.addressToTotalVesting[msg.sender] = fs.addressToTotalVesting[msg.sender] + vestAmount; fs.addressToVestIndexList[msg.sender].push(fs.currentVestIndex); } function claim( uint256 _vestIndex ) external whenNotPaused nonReentrant setLastRewardBalance returns (uint) { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); _updateRewards(msg.sender); LibFarmStorage.Vest storage _vest = fs.vestIndexToVest[_vestIndex]; if (_vest.vested != 0) revert FarmFacet__AlreadyVested(); if (_vest.vester != msg.sender) revert FarmFacet__NotVester(); uint256 vestAmount = _vest.amount; Scale _scale = Scale(payable(fs.rewardToken)); uint256 reward = _scale.baseToReflectionAmount(vestAmount); // early vest penalty uint256 toStaker; uint256 toTreasury; if (block.timestamp < _vest.startTimestamp + fs.vestDuration) { uint256 fees = (reward * fs.earlyVestPenalty) / 10_000; // 50% toStaker = fees * fs.penaltyToStaker / 10_000; toTreasury = fees * (10_000 - fs.penaltyToStaker) / 10_000; reward = reward - toStaker - toTreasury; } _vest.vested = 1; fs.earned[msg.sender] = fs.earned[msg.sender] - vestAmount; fs.addressToTotalVesting[msg.sender] = fs.addressToTotalVesting[msg.sender] - vestAmount; // transfers if (toTreasury != 0) { // swap fees to ETH IUniswapV2Router02 router = IUniswapV2Router02(fs.router); address[] memory path = new address[](2); path[0] = fs.rewardToken; path[1] = router.WETH(); router.swapExactTokensForETHSupportingFeeOnTransferTokens( toTreasury, 0, path, fs.treasury, block.timestamp ); } if (toStaker != 0) { updateRewardIndex(_scale.reflectionToBaseAmount(toStaker)); // redistribute to stakers } _scale.transfer(msg.sender, reward); return reward; } /* internal */ function _getReceiptAmount( uint amount, uint _duration, uint _minLockDuration, uint _maxLockDuration ) internal pure returns(uint) { int duration = int(_duration); int minLockDuration = int(_minLockDuration); int maxLockDuration = int(_maxLockDuration); int durationSpan = maxLockDuration - minLockDuration; int linearFactor = 1_000 + (9_000 * (duration - minLockDuration) / durationSpan); int limit = durationSpan / 172_800; int curveFactor = 1_000 * limit; for( int i = -limit; i < limit; ) { curveFactor = curveFactor - _abs( 500 - (1_000 * (duration + (i * 86_400) - minLockDuration)) / durationSpan ); unchecked { i = i + 1; } } return amount * uint(linearFactor + curveFactor / 10_000) / 10_000; } function _abs(int val) internal pure returns (int) { return val > 0 ? val : -val; } /* admin */ function setLockDurations( uint minLockDuration, uint maxLockDuration, uint earlyVestPenalty, uint penaltyToStaker ) external onlyOwner { if (minLockDuration >= maxLockDuration) revert FarmFacet__InvalidDuration(); LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); fs.minLockDuration = minLockDuration; fs.maxLockDuration = maxLockDuration; fs.earlyVestPenalty = earlyVestPenalty; // in BP fs.penaltyToStaker = penaltyToStaker; // in BP } function setVestDuration(uint256 vestDuration) external onlyOwner { LibFarmStorage.layout().vestDuration = vestDuration; } function setTokens( address _stakingToken, address _rewardToken ) external onlyOwner { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); fs.stakingToken = _stakingToken; fs.rewardToken = _rewardToken; } function setTreasury( address _treasury, address _router ) external onlyOwner { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); fs.treasury = _treasury; // approve Scale _scale = Scale(payable(fs.rewardToken)); _scale.approve(fs.router, 0); fs.router = _router; _scale.approve(fs.router, type(uint256).max); } function setPauseStatus(bool _paused) external onlyOwner { if (_paused) { _pause(); } else { _unpause(); } } /* view */ function calculateRewardsEarned( address account ) external view returns (uint) { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); if (fs.totalSupply != 0) { // rewardIndex Scale _scale = Scale(payable(fs.rewardToken)); uint256 _currentRewardBalance = _scale.baseBalanceOf(address(this)); uint256 _reward = _currentRewardBalance - fs.lastRewardBalance; uint256 _rewardIndex = fs.rewardIndex + (_reward * MULTIPLIER) / fs.totalSupply; uint256 _shares = fs.balanceOf[account]; return _scale.baseToReflectionAmount( fs.earned[account] + ((_shares * (_rewardIndex - fs.rewardIndexOf[account])) / MULTIPLIER) - fs.addressToTotalVesting[account] ); } return 0; } function getUserLockList( address _address ) external view returns ( LibFarmStorage.Lock[] memory _lockList, uint256[] memory lockingIndexList ) { lockingIndexList = addressToLockingIndexList(_address); _lockList = new LibFarmStorage.Lock[](lockingIndexList.length); for (uint256 i; i < lockingIndexList.length; i++) { _lockList[i] = lockingIndexToLock(lockingIndexList[i]); } } function getUserVestList( address _address ) external view returns ( LibFarmStorage.Vest[] memory _vestList, uint256[] memory vestIndexList ) { vestIndexList = addressToVestIndexList(_address); _vestList = new LibFarmStorage.Vest[](vestIndexList.length); for (uint256 i; i < vestIndexList.length; i++) { _vestList[i] = vestIndexToVest(vestIndexList[i]); } } function addressToLockingIndexList( address _address ) public view returns (uint256[] memory) { return LibFarmStorage.layout().addressToLockingIndexList[_address]; } function lockingIndexToLock( uint256 _lockingIndex ) public view returns (LibFarmStorage.Lock memory) { return LibFarmStorage.layout().lockingIndexToLock[_lockingIndex]; } function addressToVestIndexList( address _address ) public view returns (uint256[] memory) { return LibFarmStorage.layout().addressToVestIndexList[_address]; } function vestIndexToVest( uint256 _vestIndex ) public view returns (LibFarmStorage.Vest memory) { return LibFarmStorage.layout().vestIndexToVest[_vestIndex]; } function stakingToken() external view returns (address) { return LibFarmStorage.layout().stakingToken; } function rewardToken() external view returns (address) { return LibFarmStorage.layout().rewardToken; } function earned(address _address) external view returns (uint256) { return LibFarmStorage.layout().earned[_address]; } function rewardIndex() external view returns (uint256) { return LibFarmStorage.layout().rewardIndex; } function getLockDuration() external view returns (uint256, uint256) { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); return (fs.minLockDuration, fs.maxLockDuration); } function getVestDuration() external view returns (uint256, uint256) { LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); return (fs.vestDuration, fs.earlyVestPenalty); } /* ERC20 functions */ function totalSupply() external view returns (uint) { return LibFarmStorage.layout().totalSupply; } function balanceOf(address account) external view returns (uint) { return LibFarmStorage.layout().balanceOf[account]; } /* some ERC20 functions are disabled for receipt tokens */ function transfer( address recipient, uint amount ) external pure returns (bool) { // receipt tokens are not transferable at this moment revert FarmFacet__NotTransferable(); } function allowance( address owner, address spender ) external pure returns (uint) { // no allowance since not transferable revert FarmFacet__NotTransferable(); } function approve( address spender, uint amount ) external pure returns (bool) { // not approvable since not transferable revert FarmFacet__NotTransferable(); } function transferFrom( address sender, address recipient, uint amount ) external pure returns (bool) { // receipt tokens are not transferable at this moment revert FarmFacet__NotTransferable(); } // function _transfer(address from, address to, uint256 amount) internal { // require(from != address(0), "ERC20: transfer from the zero address"); // require(to != address(0), "ERC20: transfer to the zero address"); // LibFarmStorage.Layout storage fs = LibFarmStorage.layout(); // uint256 fromBalance = fs.balanceOf[from]; // require( // fromBalance >= amount, // "ERC20: transfer amount exceeds balance" // ); // unchecked { // fs.balanceOf[from] = fromBalance - amount; // // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // // decrementing then incrementing. // fs.balanceOf[to] += amount; // } // emit Transfer(from, to, amount); // } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import "./ILayerZeroUserApplicationConfigUpgradeable.sol"; interface ILayerZeroEndpointUpgradeable is ILayerZeroUserApplicationConfigUpgradeable { // @notice send a LayerZero message to the specified address at a LayerZero endpoint. // @param _dstChainId - the destination chain identifier // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains // @param _payload - a custom bytes payload to send to the destination contract // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable; // @notice used by the messaging library to publish verified payload // @param _srcChainId - the source chain identifier // @param _srcAddress - the source contract (as bytes) at the source chain // @param _dstAddress - the address on destination chain // @param _nonce - the unbound message ordering nonce // @param _gasLimit - the gas limit for external contract execution // @param _payload - verified payload to send to the destination contract function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external; // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64); // @notice get the outboundNonce from this source chain which, consequently, is always an EVM // @param _srcAddress - the source chain contract address function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64); // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery // @param _dstChainId - the destination chain identifier // @param _userApplication - the user app address on this EVM chain // @param _payload - the custom message to send over LayerZero // @param _payInZRO - if false, user app pays the protocol fee in native token // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee); // @notice get this Endpoint's immutable source identifier function getChainId() external view returns (uint16); // @notice the interface to retry failed message on this Endpoint destination // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address // @param _payload - the payload to be retried function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external; // @notice query if any STORED payload (message blocking) at the endpoint. // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool); // @notice query if the _libraryAddress is valid for sending msgs. // @param _userApplication - the user app address on this EVM chain function getSendLibraryAddress(address _userApplication) external view returns (address); // @notice query if the _libraryAddress is valid for receiving msgs. // @param _userApplication - the user app address on this EVM chain function getReceiveLibraryAddress(address _userApplication) external view returns (address); // @notice query if the non-reentrancy guard for send() is on // @return true if the guard is on. false otherwise function isSendingPayload() external view returns (bool); // @notice query if the non-reentrancy guard for receive() is on // @return true if the guard is on. false otherwise function isReceivingPayload() external view returns (bool); // @notice get the configuration of the LayerZero messaging library of the specified version // @param _version - messaging library version // @param _chainId - the chainId for the pending config change // @param _userApplication - the contract address of the user application // @param _configType - type of configuration. every messaging library has its own convention. function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory); // @notice get the send() LayerZero messaging library version // @param _userApplication - the contract address of the user application function getSendVersion(address _userApplication) external view returns (uint16); // @notice get the lzReceive() LayerZero messaging library version // @param _userApplication - the contract address of the user application function getReceiveVersion(address _userApplication) external view returns (uint16); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; interface ILayerZeroReceiverUpgradeable { // @notice LayerZero endpoint will invoke this function to deliver the message on the destination // @param _srcChainId - the source endpoint identifier // @param _srcAddress - the source sending contract address from the source chain // @param _nonce - the ordered message nonce // @param _payload - the signed payload is the UA bytes has encoded to be sent function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; interface ILayerZeroUserApplicationConfigUpgradeable { // @notice set the configuration of the LayerZero messaging library of the specified version // @param _version - messaging library version // @param _chainId - the chainId for the pending config change // @param _configType - type of configuration. every messaging library has its own convention. // @param _config - configuration in the bytes. can encode arbitrary content. function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external; // @notice set the send() LayerZero messaging library version to _version // @param _version - new messaging library version function setSendVersion(uint16 _version) external; // @notice set the lzReceive() LayerZero messaging library version to _version // @param _version - new messaging library version function setReceiveVersion(uint16 _version) external; // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload // @param _srcChainId - the chainId of the source chain // @param _srcAddress - the contract address of the source contract at the source chain function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "../interfaces/ILayerZeroReceiverUpgradeable.sol"; import "../interfaces/ILayerZeroUserApplicationConfigUpgradeable.sol"; import "../interfaces/ILayerZeroEndpointUpgradeable.sol"; import "../../util/BytesLib.sol"; /* * a generic LzReceiver implementation */ abstract contract LzAppUpgradeable is Initializable, OwnableUpgradeable, ILayerZeroReceiverUpgradeable, ILayerZeroUserApplicationConfigUpgradeable { using BytesLib for bytes; // ua can not send payload larger than this by default, but it can be changed by the ua owner uint constant public DEFAULT_PAYLOAD_SIZE_LIMIT = 10000; ILayerZeroEndpointUpgradeable public lzEndpoint; mapping(uint16 => bytes) public trustedRemoteLookup; mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup; mapping(uint16 => uint) public payloadSizeLimitLookup; address public precrime; event SetPrecrime(address precrime); event SetTrustedRemote(uint16 _remoteChainId, bytes _path); event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress); event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas); function __LzAppUpgradeable_init(address _endpoint) internal onlyInitializing { __Ownable_init_unchained(); __LzAppUpgradeable_init_unchained(_endpoint); } function __LzAppUpgradeable_init_unchained(address _endpoint) internal onlyInitializing { lzEndpoint = ILayerZeroEndpointUpgradeable(_endpoint); } function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public virtual override { // lzReceive must be called by the endpoint for security require(_msgSender() == address(lzEndpoint), "LzApp: invalid endpoint caller"); bytes memory trustedRemote = trustedRemoteLookup[_srcChainId]; // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote. require(_srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote), "LzApp: invalid source sending contract"); _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload); } // abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging function _blockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual; function _lzSend(uint16 _dstChainId, bytes memory _payload, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams, uint _nativeFee) internal virtual { bytes memory trustedRemote = trustedRemoteLookup[_dstChainId]; require(trustedRemote.length != 0, "LzApp: destination chain is not a trusted source"); _checkPayloadSize(_dstChainId, _payload.length); lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams); } function _checkGasLimit(uint16 _dstChainId, uint16 _type, bytes memory _adapterParams, uint _extraGas) internal view virtual { uint providedGasLimit = _getGasLimit(_adapterParams); uint minGasLimit = minDstGasLookup[_dstChainId][_type] + _extraGas; require(minGasLimit > 0, "LzApp: minGasLimit not set"); require(providedGasLimit >= minGasLimit, "LzApp: gas limit is too low"); } function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint gasLimit) { require(_adapterParams.length >= 34, "LzApp: invalid adapterParams"); assembly { gasLimit := mload(add(_adapterParams, 34)) } } function _checkPayloadSize(uint16 _dstChainId, uint _payloadSize) internal view virtual { uint payloadSizeLimit = payloadSizeLimitLookup[_dstChainId]; if (payloadSizeLimit == 0) { // use default if not set payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT; } require(_payloadSize <= payloadSizeLimit, "LzApp: payload size is too large"); } //---------------------------UserApplication config---------------------------------------- function getConfig(uint16 _version, uint16 _chainId, address, uint _configType) external view returns (bytes memory) { return lzEndpoint.getConfig(_version, _chainId, address(this), _configType); } // generic config for LayerZero user Application function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external override onlyOwner { lzEndpoint.setConfig(_version, _chainId, _configType, _config); } function setSendVersion(uint16 _version) external override onlyOwner { lzEndpoint.setSendVersion(_version); } function setReceiveVersion(uint16 _version) external override onlyOwner { lzEndpoint.setReceiveVersion(_version); } function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner { lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress); } // _path = abi.encodePacked(remoteAddress, localAddress) // this function set the trusted path for the cross-chain communication function setTrustedRemote(uint16 _srcChainId, bytes calldata _path) external onlyOwner { trustedRemoteLookup[_srcChainId] = _path; emit SetTrustedRemote(_srcChainId, _path); } function setTrustedRemoteAddress(uint16 _remoteChainId, bytes calldata _remoteAddress) external onlyOwner { trustedRemoteLookup[_remoteChainId] = abi.encodePacked(_remoteAddress, address(this)); emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress); } function getTrustedRemoteAddress(uint16 _remoteChainId) external view returns (bytes memory) { bytes memory path = trustedRemoteLookup[_remoteChainId]; require(path.length != 0, "LzApp: no trusted path record"); return path.slice(0, path.length - 20); // the last 20 bytes should be address(this) } function setPrecrime(address _precrime) external onlyOwner { precrime = _precrime; emit SetPrecrime(_precrime); } function setMinDstGas(uint16 _dstChainId, uint16 _packetType, uint _minGas) external onlyOwner { require(_minGas > 0, "LzApp: invalid minGas"); minDstGasLookup[_dstChainId][_packetType] = _minGas; emit SetMinDstGas(_dstChainId, _packetType, _minGas); } // if the size is 0, it means default size limit function setPayloadSizeLimit(uint16 _dstChainId, uint _size) external onlyOwner { payloadSizeLimitLookup[_dstChainId] = _size; } //--------------------------- VIEW FUNCTION ---------------------------------------- function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) { bytes memory trustedSource = trustedRemoteLookup[_srcChainId]; return keccak256(trustedSource) == keccak256(_srcAddress); } /** * @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 */ uint[45] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import "./LzAppUpgradeable.sol"; import "../../util/ExcessivelySafeCall.sol"; /* * the default LayerZero messaging behaviour is blocking, i.e. any failed message will block the channel * this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking * NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress) */ abstract contract NonblockingLzAppUpgradeable is Initializable, LzAppUpgradeable { using ExcessivelySafeCall for address; function __NonblockingLzAppUpgradeable_init(address _endpoint) internal onlyInitializing { __Ownable_init_unchained(); __LzAppUpgradeable_init_unchained(_endpoint); } function __NonblockingLzAppUpgradeable_init_unchained(address _endpoint) internal onlyInitializing {} mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages; event MessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason); event RetryMessageSuccess(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash); // overriding the virtual function in LzReceiver function _blockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual override { (bool success, bytes memory reason) = address(this).excessivelySafeCall(gasleft(), 150, abi.encodeWithSelector(this.nonblockingLzReceive.selector, _srcChainId, _srcAddress, _nonce, _payload)); // try-catch all errors/exceptions if (!success) { _storeFailedMessage(_srcChainId, _srcAddress, _nonce, _payload, reason); } } function _storeFailedMessage(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload, bytes memory _reason) internal virtual { failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload); emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason); } function nonblockingLzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public virtual { // only internal transaction require(_msgSender() == address(this), "NonblockingLzApp: caller must be LzApp"); _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload); } //@notice override this function function _nonblockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual; function retryMessage(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public payable virtual { // assert there is message to retry bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce]; require(payloadHash != bytes32(0), "NonblockingLzApp: no stored message"); require(keccak256(_payload) == payloadHash, "NonblockingLzApp: invalid payload"); // clear the stored message failedMessages[_srcChainId][_srcAddress][_nonce] = bytes32(0); // execute the message. revert if it fails again _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload); emit RetryMessageSuccess(_srcChainId, _srcAddress, _nonce, payloadHash); } /** * @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 */ uint[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol"; /** * @dev Interface of the IOFT core standard */ interface IOFTCoreUpgradeable is IERC165Upgradeable { /** * @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, bytes calldata _toAddress, uint _amount, bool _useZro, bytes calldata _adapterParams) external view returns (uint nativeFee, uint zroFee); /** * @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, bytes calldata _toAddress, uint _amount, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable; /** * @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); /** * @dev Emitted when `_amount` tokens are moved from the `_sender` to (`_dstChainId`, `_toAddress`) * `_nonce` is the outbound nonce */ event SendToChain(uint16 indexed _dstChainId, address indexed _from, bytes _toAddress, uint _amount); /** * @dev Emitted when `_amount` tokens are received from `_srcChainId` into the `_toAddress` on the local chain. * `_nonce` is the inbound nonce. */ event ReceiveFromChain(uint16 indexed _srcChainId, address indexed _to, uint _amount); event SetUseCustomAdapterParams(bool _useCustomAdapterParams); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import "./IOFTCoreUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; /** * @dev Interface of the OFT standard */ interface IOFTUpgradeable is IOFTCoreUpgradeable, IERC20Upgradeable { }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import "./IOFTCoreUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol"; import "../../lzApp/NonblockingLzAppUpgradeable.sol"; abstract contract OFTCoreUpgradeable is Initializable, NonblockingLzAppUpgradeable, ERC165Upgradeable, IOFTCoreUpgradeable { using BytesLib for bytes; uint public constant NO_EXTRA_GAS = 0; // packet type uint16 public constant PT_SEND = 0; bool public useCustomAdapterParams; function __OFTCoreUpgradeable_init(address _lzEndpoint) internal onlyInitializing { __Ownable_init_unchained(); __LzAppUpgradeable_init_unchained(_lzEndpoint); } function __OFTCoreUpgradeable_init_unchained() internal onlyInitializing {} function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) { return interfaceId == type(IOFTCoreUpgradeable).interfaceId || super.supportsInterface(interfaceId); } function estimateSendFee(uint16 _dstChainId, bytes calldata _toAddress, uint _amount, bool _useZro, bytes calldata _adapterParams) public view virtual override returns (uint nativeFee, uint zroFee) { // mock the payload for sendFrom() bytes memory payload = abi.encode(PT_SEND, _toAddress, _amount); return lzEndpoint.estimateFees(_dstChainId, address(this), payload, _useZro, _adapterParams); } function sendFrom(address _from, uint16 _dstChainId, bytes calldata _toAddress, uint _amount, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) public payable virtual override { _send(_from, _dstChainId, _toAddress, _amount, _refundAddress, _zroPaymentAddress, _adapterParams); } function setUseCustomAdapterParams(bool _useCustomAdapterParams) public virtual onlyOwner { useCustomAdapterParams = _useCustomAdapterParams; emit SetUseCustomAdapterParams(_useCustomAdapterParams); } function _nonblockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual override { uint16 packetType; assembly { packetType := mload(add(_payload, 32)) } if (packetType == PT_SEND) { _sendAck(_srcChainId, _srcAddress, _nonce, _payload); } else { revert("OFTCore: unknown packet type"); } } function _send(address _from, uint16 _dstChainId, bytes memory _toAddress, uint _amount, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams) internal virtual { _checkAdapterParams(_dstChainId, PT_SEND, _adapterParams, NO_EXTRA_GAS); uint amount = _debitFrom(_from, _dstChainId, _toAddress, _amount); bytes memory lzPayload = abi.encode(PT_SEND, _toAddress, amount); _lzSend(_dstChainId, lzPayload, _refundAddress, _zroPaymentAddress, _adapterParams, msg.value); emit SendToChain(_dstChainId, _from, _toAddress, amount); } function _sendAck(uint16 _srcChainId, bytes memory, uint64, bytes memory _payload) internal virtual { (, bytes memory toAddressBytes, uint amount) = abi.decode(_payload, (uint16, bytes, uint)); address to = toAddressBytes.toAddress(0); amount = _creditTo(_srcChainId, to, amount); emit ReceiveFromChain(_srcChainId, to, amount); } function _checkAdapterParams(uint16 _dstChainId, uint16 _pkType, bytes memory _adapterParams, uint _extraGas) internal virtual { if (useCustomAdapterParams) { _checkGasLimit(_dstChainId, _pkType, _adapterParams, _extraGas); } else { require(_adapterParams.length == 0, "OFTCore: _adapterParams must be empty."); } } function _debitFrom(address _from, uint16 _dstChainId, bytes memory _toAddress, uint _amount) internal virtual returns(uint); function _creditTo(uint16 _srcChainId, address _toAddress, uint _amount) internal virtual returns(uint); /** * @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 */ uint[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; import "./ILayerZeroUserApplicationConfig.sol"; interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig { // @notice send a LayerZero message to the specified address at a LayerZero endpoint. // @param _dstChainId - the destination chain identifier // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains // @param _payload - a custom bytes payload to send to the destination contract // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable; // @notice used by the messaging library to publish verified payload // @param _srcChainId - the source chain identifier // @param _srcAddress - the source contract (as bytes) at the source chain // @param _dstAddress - the address on destination chain // @param _nonce - the unbound message ordering nonce // @param _gasLimit - the gas limit for external contract execution // @param _payload - verified payload to send to the destination contract function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external; // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64); // @notice get the outboundNonce from this source chain which, consequently, is always an EVM // @param _srcAddress - the source chain contract address function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64); // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery // @param _dstChainId - the destination chain identifier // @param _userApplication - the user app address on this EVM chain // @param _payload - the custom message to send over LayerZero // @param _payInZRO - if false, user app pays the protocol fee in native token // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee); // @notice get this Endpoint's immutable source identifier function getChainId() external view returns (uint16); // @notice the interface to retry failed message on this Endpoint destination // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address // @param _payload - the payload to be retried function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external; // @notice query if any STORED payload (message blocking) at the endpoint. // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool); // @notice query if the _libraryAddress is valid for sending msgs. // @param _userApplication - the user app address on this EVM chain function getSendLibraryAddress(address _userApplication) external view returns (address); // @notice query if the _libraryAddress is valid for receiving msgs. // @param _userApplication - the user app address on this EVM chain function getReceiveLibraryAddress(address _userApplication) external view returns (address); // @notice query if the non-reentrancy guard for send() is on // @return true if the guard is on. false otherwise function isSendingPayload() external view returns (bool); // @notice query if the non-reentrancy guard for receive() is on // @return true if the guard is on. false otherwise function isReceivingPayload() external view returns (bool); // @notice get the configuration of the LayerZero messaging library of the specified version // @param _version - messaging library version // @param _chainId - the chainId for the pending config change // @param _userApplication - the contract address of the user application // @param _configType - type of configuration. every messaging library has its own convention. function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory); // @notice get the send() LayerZero messaging library version // @param _userApplication - the contract address of the user application function getSendVersion(address _userApplication) external view returns (uint16); // @notice get the lzReceive() LayerZero messaging library version // @param _userApplication - the contract address of the user application function getReceiveVersion(address _userApplication) external view returns (uint16); }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface ILayerZeroUserApplicationConfig { // @notice set the configuration of the LayerZero messaging library of the specified version // @param _version - messaging library version // @param _chainId - the chainId for the pending config change // @param _configType - type of configuration. every messaging library has its own convention. // @param _config - configuration in the bytes. can encode arbitrary content. function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external; // @notice set the send() LayerZero messaging library version to _version // @param _version - new messaging library version function setSendVersion(uint16 _version) external; // @notice set the lzReceive() LayerZero messaging library version to _version // @param _version - new messaging library version function setReceiveVersion(uint16 _version) external; // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload // @param _srcChainId - the chainId of the source chain // @param _srcAddress - the contract address of the source contract at the source chain function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external; }
// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.7.6; library ExcessivelySafeCall { uint256 constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff; /// @notice Use when you _really_ really _really_ don't trust the called /// contract. This prevents the called contract from causing reversion of /// the caller in as many ways as we can. /// @dev The main difference between this and a solidity low-level call is /// that we limit the number of bytes that the callee can cause to be /// copied to caller memory. This prevents stupid things like malicious /// contracts returning 10,000,000 bytes causing a local OOG when copying /// to memory. /// @param _target The address to call /// @param _gas The amount of gas to forward to the remote contract /// @param _maxCopy The maximum number of bytes of returndata to copy /// to memory. /// @param _calldata The data to send to the remote contract /// @return success and returndata, as `.call()`. Returndata is capped to /// `_maxCopy` bytes. function excessivelySafeCall( address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata ) internal returns (bool, bytes memory) { // set up for assembly call uint256 _toCopy; bool _success; bytes memory _returnData = new bytes(_maxCopy); // dispatch message to recipient // by assembly calling "handle" function // we call via assembly to avoid memcopying a very large returndata // returned by a malicious contract assembly { _success := call( _gas, // gas _target, // recipient 0, // ether value add(_calldata, 0x20), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) // limit our copy to 256 bytes _toCopy := returndatasize() if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy } // Store the length of the copied bytes mstore(_returnData, _toCopy) // copy the bytes from returndata[0:_toCopy] returndatacopy(add(_returnData, 0x20), 0, _toCopy) } return (_success, _returnData); } /// @notice Use when you _really_ really _really_ don't trust the called /// contract. This prevents the called contract from causing reversion of /// the caller in as many ways as we can. /// @dev The main difference between this and a solidity low-level call is /// that we limit the number of bytes that the callee can cause to be /// copied to caller memory. This prevents stupid things like malicious /// contracts returning 10,000,000 bytes causing a local OOG when copying /// to memory. /// @param _target The address to call /// @param _gas The amount of gas to forward to the remote contract /// @param _maxCopy The maximum number of bytes of returndata to copy /// to memory. /// @param _calldata The data to send to the remote contract /// @return success and returndata, as `.call()`. Returndata is capped to /// `_maxCopy` bytes. function excessivelySafeStaticCall( address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata ) internal view returns (bool, bytes memory) { // set up for assembly call uint256 _toCopy; bool _success; bytes memory _returnData = new bytes(_maxCopy); // dispatch message to recipient // by assembly calling "handle" function // we call via assembly to avoid memcopying a very large returndata // returned by a malicious contract assembly { _success := staticcall( _gas, // gas _target, // recipient add(_calldata, 0x20), // inloc mload(_calldata), // inlen 0, // outloc 0 // outlen ) // limit our copy to 256 bytes _toCopy := returndatasize() if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy } // Store the length of the copied bytes mstore(_returnData, _toCopy) // copy the bytes from returndata[0:_toCopy] returndatacopy(add(_returnData, 0x20), 0, _toCopy) } return (_success, _returnData); } /** * @notice Swaps function selectors in encoded contract calls * @dev Allows reuse of encoded calldata for functions with identical * argument types but different names. It simply swaps out the first 4 bytes * for the new selector. This function modifies memory in place, and should * only be used with caution. * @param _newSelector The new 4-byte selector * @param _buf The encoded contract args */ function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure { require(_buf.length >= 4); uint256 _mask = LOW_28_MASK; assembly { // load the first word of let _word := mload(add(_buf, 0x20)) // mask out the top 4 bytes // /x _word := and(_word, _mask) _word := or(_newSelector, _word) mstore(add(_buf, 0x20), _word) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../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.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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.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 v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../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; } /** * @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 v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @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 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 IERC165Upgradeable { /** * @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: 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 pragma solidity ^0.8.8; import { IERC173 } from '../../interfaces/IERC173.sol'; import { IOwnableInternal } from './IOwnableInternal.sol'; interface IOwnable is IOwnableInternal, IERC173 {}
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IERC173Internal } from '../../interfaces/IERC173Internal.sol'; interface IOwnableInternal is IERC173Internal { error Ownable__NotOwner(); error Ownable__NotTransitiveOwner(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IERC173 } from '../../interfaces/IERC173.sol'; import { AddressUtils } from '../../utils/AddressUtils.sol'; import { IOwnableInternal } from './IOwnableInternal.sol'; import { OwnableStorage } from './OwnableStorage.sol'; abstract contract OwnableInternal is IOwnableInternal { using AddressUtils for address; modifier onlyOwner() { if (msg.sender != _owner()) revert Ownable__NotOwner(); _; } modifier onlyTransitiveOwner() { if (msg.sender != _transitiveOwner()) revert Ownable__NotTransitiveOwner(); _; } function _owner() internal view virtual returns (address) { return OwnableStorage.layout().owner; } function _transitiveOwner() internal view virtual returns (address owner) { owner = _owner(); while (owner.isContract()) { try IERC173(owner).owner() returns (address transitiveOwner) { owner = transitiveOwner; } catch { break; } } } function _transferOwnership(address account) internal virtual { _setOwner(account); } function _setOwner(address account) internal virtual { OwnableStorage.Layout storage l = OwnableStorage.layout(); emit OwnershipTransferred(l.owner, account); l.owner = account; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; library OwnableStorage { struct Layout { address owner; } bytes32 internal constant STORAGE_SLOT = keccak256('solidstate.contracts.storage.Ownable'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IERC173Internal } from './IERC173Internal.sol'; /** * @title Contract ownership standard interface * @dev see https://eips.ethereum.org/EIPS/eip-173 */ interface IERC173 is IERC173Internal { /** * @notice get the ERC173 contract owner * @return contract owner */ function owner() external view returns (address); /** * @notice transfer contract ownership to new account * @param account address of new owner */ function transferOwnership(address account) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title Partial ERC173 interface needed by internal functions */ interface IERC173Internal { event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IPausableInternal } from './IPausableInternal.sol'; interface IPausable is IPausableInternal { /** * @notice query whether contract is paused * @return status whether contract is paused */ function paused() external view returns (bool status); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; interface IPausableInternal { error Pausable__Paused(); error Pausable__NotPaused(); event Paused(address account); event Unpaused(address account); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IPausable } from './IPausable.sol'; import { PausableInternal } from './PausableInternal.sol'; /** * @title Pausable security control module. */ abstract contract Pausable is IPausable, PausableInternal { /** * @inheritdoc IPausable */ function paused() external view virtual returns (bool status) { status = _paused(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IPausableInternal } from './IPausableInternal.sol'; import { PausableStorage } from './PausableStorage.sol'; /** * @title Internal functions for Pausable security control module. */ abstract contract PausableInternal is IPausableInternal { modifier whenNotPaused() { if (_paused()) revert Pausable__Paused(); _; } modifier whenPaused() { if (!_paused()) revert Pausable__NotPaused(); _; } /** * @notice query whether contract is paused * @return status whether contract is paused */ function _paused() internal view virtual returns (bool status) { status = PausableStorage.layout().paused; } /** * @notice Triggers paused state, when contract is unpaused. */ function _pause() internal virtual whenNotPaused { PausableStorage.layout().paused = true; emit Paused(msg.sender); } /** * @notice Triggers unpaused state, when contract is paused. */ function _unpause() internal virtual whenPaused { delete PausableStorage.layout().paused; emit Unpaused(msg.sender); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; library PausableStorage { struct Layout { bool paused; } bytes32 internal constant STORAGE_SLOT = keccak256('solidstate.contracts.storage.Pausable'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IReentrancyGuard { error ReentrancyGuard__ReentrantCall(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IReentrancyGuard } from './IReentrancyGuard.sol'; import { ReentrancyGuardStorage } from './ReentrancyGuardStorage.sol'; /** * @title Utility contract for preventing reentrancy attacks */ abstract contract ReentrancyGuard is IReentrancyGuard { uint256 internal constant REENTRANCY_STATUS_LOCKED = 2; uint256 internal constant REENTRANCY_STATUS_UNLOCKED = 1; modifier nonReentrant() virtual { if (_isReentrancyGuardLocked()) revert ReentrancyGuard__ReentrantCall(); _lockReentrancyGuard(); _; _unlockReentrancyGuard(); } /** * @notice returns true if the reentrancy guard is locked, false otherwise */ function _isReentrancyGuardLocked() internal view virtual returns (bool) { return ReentrancyGuardStorage.layout().status == REENTRANCY_STATUS_LOCKED; } /** * @notice lock functions that use the nonReentrant modifier */ function _lockReentrancyGuard() internal virtual { ReentrancyGuardStorage.layout().status = REENTRANCY_STATUS_LOCKED; } /** * @notice unlock functions that use the nonReentrant modifier */ function _unlockReentrancyGuard() internal virtual { ReentrancyGuardStorage.layout().status = REENTRANCY_STATUS_UNLOCKED; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; library ReentrancyGuardStorage { struct Layout { uint256 status; } bytes32 internal constant STORAGE_SLOT = keccak256('solidstate.contracts.storage.ReentrancyGuard'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { UintUtils } from './UintUtils.sol'; library AddressUtils { using UintUtils for uint256; error AddressUtils__InsufficientBalance(); error AddressUtils__NotContract(); error AddressUtils__SendValueFailed(); function toString(address account) internal pure returns (string memory) { return uint256(uint160(account)).toHexString(20); } function isContract(address account) internal view returns (bool) { uint256 size; assembly { size := extcodesize(account) } return size > 0; } function sendValue(address payable account, uint256 amount) internal { (bool success, ) = account.call{ value: amount }(''); if (!success) revert AddressUtils__SendValueFailed(); } function functionCall( address target, bytes memory data ) internal returns (bytes memory) { return functionCall(target, data, 'AddressUtils: failed low-level call'); } function functionCall( address target, bytes memory data, string memory error ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, error); } function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, 'AddressUtils: failed low-level call with value' ); } function functionCallWithValue( address target, bytes memory data, uint256 value, string memory error ) internal returns (bytes memory) { if (value > address(this).balance) revert AddressUtils__InsufficientBalance(); return _functionCallWithValue(target, data, value, error); } /** * @notice execute arbitrary external call with limited gas usage and amount of copied return data * @dev derived from https://github.com/nomad-xyz/ExcessivelySafeCall (MIT License) * @param target recipient of call * @param gasAmount gas allowance for call * @param value native token value to include in call * @param maxCopy maximum number of bytes to copy from return data * @param data encoded call data * @return success whether call is successful * @return returnData copied return data */ function excessivelySafeCall( address target, uint256 gasAmount, uint256 value, uint16 maxCopy, bytes memory data ) internal returns (bool success, bytes memory returnData) { returnData = new bytes(maxCopy); assembly { // execute external call via assembly to avoid automatic copying of return data success := call( gasAmount, target, value, add(data, 0x20), mload(data), 0, 0 ) // determine whether to limit amount of data to copy let toCopy := returndatasize() if gt(toCopy, maxCopy) { toCopy := maxCopy } // store the length of the copied bytes mstore(returnData, toCopy) // copy the bytes from returndata[0:toCopy] returndatacopy(add(returnData, 0x20), 0, toCopy) } } function _functionCallWithValue( address target, bytes memory data, uint256 value, string memory error ) private returns (bytes memory) { if (!isContract(target)) revert AddressUtils__NotContract(); (bool success, bytes memory returnData) = target.call{ value: value }( data ); if (success) { return returnData; } else if (returnData.length > 0) { assembly { let returnData_size := mload(returnData) revert(add(32, returnData), returnData_size) } } else { revert(error); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title utility functions for uint256 operations * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license) */ library UintUtils { error UintUtils__InsufficientHexLength(); bytes16 private constant HEX_SYMBOLS = '0123456789abcdef'; function add(uint256 a, int256 b) internal pure returns (uint256) { return b < 0 ? sub(a, -b) : a + uint256(b); } function sub(uint256 a, int256 b) internal pure returns (uint256) { return b < 0 ? add(a, -b) : a - uint256(b); } function toString(uint256 value) internal pure returns (string memory) { if (value == 0) { return '0'; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return '0x00'; } uint256 length = 0; for (uint256 temp = value; temp != 0; temp >>= 8) { unchecked { length++; } } return toHexString(value, length); } function toHexString( uint256 value, uint256 length ) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = '0'; buffer[1] = 'x'; unchecked { for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_SYMBOLS[value & 0xf]; value >>= 4; } } if (value != 0) revert UintUtils__InsufficientHexLength(); return string(buffer); } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; library LibFarmStorage { bytes32 internal constant STORAGE_SLOT = keccak256("Farm.contracts.storage.LibFarmStorage"); struct Lock { uint256 startTimestamp; // lock start time uint256 amount; // amount of LP uint256 receiptAmount; // amount of receipt tokens uint256 duration; // lock duration uint256 unlocked; // 0 false, 1 true address locker; // address that locked LP } struct Vest { uint256 startTimestamp; // reward vesting start time uint256 amount; // amount of S rewards vested in base amount uint256 vested; // 0 false, 1 true address vester; // address that is vesting } struct Layout { address stakingToken; // WETH-S-LP address rewardToken; // S address treasury; // treasury multisig or something address router; // router for swapping to ETH mapping(address => uint) balanceOf; // balance of receipt token uint256 totalSupply; // totalSupply of receipt tokens uint256 rewardIndex; // in base amount mapping(address => uint) rewardIndexOf; mapping(address => uint) earned; uint256 lastRewardBalance; // rewardToken balance of farm in base amounts /* lock */ uint256 currentLockingIndex; // current index and current total locks uint256 minLockDuration; // currently 3 days uint256 maxLockDuration; // currently 90 days mapping(uint256 => Lock) lockingIndexToLock; // lockingIndex => Lock mapping(address => uint256[]) addressToLockingIndexList; // address => lockingIndexList that is still locked /* vest */ uint256 currentVestIndex; uint256 earlyVestPenalty; // in BP currently 5_000 uint256 vestDuration; // currently 7 days mapping(uint256 => Vest) vestIndexToVest; // vestIndex => Vest mapping(address => uint256[]) addressToVestIndexList; // address => vestIndexList mapping(address => uint256) addressToTotalVesting; // address => totalVesting uint256 penaltyToStaker; } function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol"; import {OFTCoreUpgradeable} from "@layerzerolabs/solidity-examples/contracts/contracts-upgradable/token/oft/OFTCoreUpgradeable.sol"; import {IOFTUpgradeable} from "@layerzerolabs/solidity-examples/contracts/contracts-upgradable/token/oft/IOFTUpgradeable.sol"; import {ILayerZeroEndpoint} from "@layerzerolabs/solidity-examples/contracts/interfaces/ILayerZeroEndpoint.sol"; import {SingleLinkedList, SingleLinkedListLib} from "../utils/SingleLinkedList.sol"; interface IUniswapV2Router02 { function factory() external pure returns (address); function WETH() external pure returns (address); function swapExactTokensForETHSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external; function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function getAmountsOut(uint amountIn, address[] memory path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] memory path) external view returns (uint[] memory amounts); } interface IUniswapV2Factory { function createPair( address tokenA, address tokenB ) external returns (address); } interface IUniswapV2Pair { function sync() external; } // TODO /** * - share totalSubLP across all chains? * */ contract Scale is OFTCoreUpgradeable, IERC20Upgradeable { using SingleLinkedListLib for SingleLinkedList; /* -------------------------------------------------------------------------- */ /* events */ /* -------------------------------------------------------------------------- */ error InvalidParameters(); error RemoteStateOutOfSync(uint remoteState); error ERC20InsufficientAllowance(address, address, uint); error InsuffcientBalance(uint); error OFTCoreUnknownPacketType(); error MaxTransaction(); error MaxWallet(); event Reflect(uint256 baseAmountReflected, uint256 totalReflected); event LaunchFee(address user, uint amount); event TransmitToRemote( uint16 indexed destinationChain, uint totalReflections ); event AnswerToRemote(uint16 indexed remoteChainId, uint answer); event RequestRemoteState(uint16 indexed requestedChain); event ReceiveRemoteState( uint16 indexed sourceChain, uint receivedRemoteState ); event XReflect(uint256 baseAmountReflected, uint256 totalReflected); /* -------------------------------------------------------------------------- */ /* constants */ /* -------------------------------------------------------------------------- */ string constant _name = "ScaleX.gg | Scale"; string constant _symbol = "S"; // @custom:oz-upgrades-unsafe-allow state-variable-immutable IUniswapV2Router02 public immutable UNISWAP_V2_ROUTER; // --- BSC (Pancake) // IUniswapV2Router02 public constant UNISWAP_V2_ROUTER = // IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E); // --- Polygon (Quickswap) // IUniswapV2Router02 public constant UNISWAP_V2_ROUTER = // IUniswapV2Router02(0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff); // --- Fantom (Spookyswap) // IUniswapV2Router02 public constant UNISWAP_V2_ROUTER = // IUniswapV2Router02(0xF491e7B69E4244ad4002BC14e878a34207E38c29); // --- Arbitrum (Camelot) // IUniswapV2Router02 public constant UNISWAP_V2_ROUTER = // IUniswapV2Router02(0xc873fEcbd354f5A56E00E710B90EF4201db2448d); // --- Base (Alienbase) // IUniswapV2Router02 public constant UNISWAP_V2_ROUTER = // IUniswapV2Router02(0x8c1A3cF8f83074169FE5D7aD50B978e1cD6b37c7); // --- Ethereum (Uniswap) // IUniswapV2Router02 public constant UNISWAP_V2_ROUTER = // IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); address constant DEAD = 0x000000000000000000000000000000000000dEaD; address constant ZERO = 0x0000000000000000000000000000000000000000; // supplies uint256 constant TOTAL_SUPPLY = 1_000_000 ether; uint256 constant PRESALE_SUPPLY = TOTAL_SUPPLY * 5_257 / MAX_BP; uint256 constant LZ_GAS_USAGE_LIMIT = 1_000_000; uint256 constant MAX_BP = 10_000; // fees uint256 constant MAX_FEE = 1_500; /* 15% */ uint256 constant LAUNCH_FEE = 1_500; /* 15% */ uint256 constant LAUNCH_FEE_DURATION = 1 days; // reflections uint256 constant REFLECTION_GROWTH_FACTOR = 20; uint256 constant MAX_BURN_REWARD_RATE = MAX_BP; uint256 constant ASYMPTOTE = 2; // TODO adjust uint256 private constant MIN_MAX_WALLET = (TOTAL_SUPPLY * 160) / MAX_BP; // 1.6% uint256 private constant MIN_MAX_TX = TOTAL_SUPPLY / 100; uint16 public constant PT_TRANSMIT_AND_REQUEST = 1; uint16 public constant PT_TRANSMIT = 2; uint16 public constant PT_RESPONSE = 3; /* -------------------------------------------------------------------------- */ /* states */ /* -------------------------------------------------------------------------- */ struct Fee { // not to be swapped to native uint8 reflection; // sent off uint8 marketing; // to be swapped to native uint8 omnichain /* used to cover gas for transmitting reflections across chains */; uint8 treasury; uint8 referral /* 50% user buying free reduction & 50% to referrer */; uint8 lp /* local LP + chain expansion */; uint8 buyback; uint8 burn; uint128 total; } // L0 chain IDs sorted by avg gas costs in decreasing order SingleLinkedList public chains; uint16 private lzChainId; bool private liquidityInitialised; uint256 public feesEnabled; uint256 public swapThreshold; // denominated as reflected amount uint256 public totalReflected; uint256 private launchTime; uint256 private isInSwap; uint256 private isLowGasChain; // wallet limits uint256 private limitsEnabled; uint256 private maxWallet; uint256 private maxTx; // for auto lp burn uint256 private lastBurnTime; uint256 private burnRewardRate; uint256 private lpBurnRatePerDay; uint256 private burnTimeDiffCap; address private _uniswapPair; address private marketingFeeReceiver; address private lpFeeReceiver; address private buybackFeeReceiver; address private treasuryReceiver; address private lpBurnReceiver; Fee public buyFee; Fee public sellFee; mapping(address => uint256) private isRegistredPool; mapping(address => uint256) private _baseBalance; mapping(address => uint256) private txLimitsExcluded; mapping(address => mapping(address => uint256)) private _allowances; //@custom:oz-upgrades-unsafe-allow state-variable-immutable constructor(address router) { UNISWAP_V2_ROUTER = IUniswapV2Router02(router); } receive() external payable {} function initialize( address _lzEndpoint, address newMarketingFeeReceiver, address newLPfeeReceiver, address newBuyBackFeeReceiver, address newTreasuryReceiver, address newLPBurnReceiver ) public payable initializer { // initialise parents __Ownable_init_unchained(); __LzAppUpgradeable_init_unchained(_lzEndpoint); // set variables swapThreshold = (TOTAL_SUPPLY * 20) / MAX_BP; /* 0.2% of total supply */ // limits limitsEnabled = 1; maxWallet = TOTAL_SUPPLY * 160 / MAX_BP; maxTx = maxWallet; // LZ setup lzChainId = ILayerZeroEndpoint(_lzEndpoint).getChainId() + 100; chains.addNode(lzChainId, 0); marketingFeeReceiver = newMarketingFeeReceiver; lpFeeReceiver = newLPfeeReceiver; buybackFeeReceiver = newBuyBackFeeReceiver; treasuryReceiver = newTreasuryReceiver; lpBurnReceiver = newLPBurnReceiver; // exclude project wallets from limits txLimitsExcluded[address(this)] = 1; txLimitsExcluded[treasuryReceiver] = 1; txLimitsExcluded[marketingFeeReceiver] = 1; txLimitsExcluded[lpFeeReceiver] = 1; txLimitsExcluded[buybackFeeReceiver] = 1; txLimitsExcluded[lpBurnReceiver] = 1; buyFee = Fee({ reflection: 100, omnichain: 100, buyback: 0, marketing: 100, lp: 200, treasury: 100, referral: 0, burn: 0, total: 600 }); sellFee = Fee({ reflection: 100, omnichain: 100, buyback: 0, marketing: 100, lp: 200, treasury: 100, referral: 0, burn: 0, total: 600 }); // mint presale supply to treasury if (block.chainid == 1) { // only on Ethereum main net _baseBalance[treasuryReceiver] = PRESALE_SUPPLY; emit Transfer(address(0), treasuryReceiver, PRESALE_SUPPLY); } } function addLiquidity(uint sharesForChain) external payable onlyOwner { if (liquidityInitialised) revert(); liquidityInitialised = true; uint liquiditySupply = TOTAL_SUPPLY - PRESALE_SUPPLY; uint tokensForLiquidity = (liquiditySupply * sharesForChain) / MAX_BP; // fund address(this) with desired amount of liquidity tokens _baseBalance[address(this)] = tokensForLiquidity; emit Transfer(address(0), address(this), tokensForLiquidity); // create uniswap pair _uniswapPair = IUniswapV2Factory(UNISWAP_V2_ROUTER.factory()) .createPair(address(this), UNISWAP_V2_ROUTER.WETH()); // set unlimited allowance for uniswap router _allowances[address(this)][address(UNISWAP_V2_ROUTER)] = type(uint256) .max; // add desired amount of liquidity to pair UNISWAP_V2_ROUTER.addLiquidityETH{value: msg.value}( address(this), // address token, tokensForLiquidity, // uint amountTokenDesired, tokensForLiquidity, // uint amountTokenMin, msg.value, // uint amountETHMin, treasuryReceiver, // address to, block.timestamp // uint deadline ); // set fee variables isRegistredPool[_uniswapPair] = 1; feesEnabled = 1; launchTime = block.timestamp; // auto LP burn lastBurnTime = block.timestamp; // TODO set reward rate (burn rate is set manually as soon as we enabled the feature) // lpBurnRatePerDay = 1_000; /* 1% */ burnRewardRate = 10_000; burnTimeDiffCap = 1 days; } /* -------------------------------------------------------------------------- */ /* ERC20 */ /* -------------------------------------------------------------------------- */ function approve( address spender, uint256 amount ) public override returns (bool) { _allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function approveMax(address spender) external returns (bool) { return approve(spender, type(uint256).max); } function transfer( address recipient, uint256 amount ) external override returns (bool) { return _transferFrom(msg.sender, recipient, amount); } function transferFrom( address sender, address recipient, uint256 amount ) external override returns (bool) { if (_allowances[sender][msg.sender] != type(uint256).max) { if (_allowances[sender][msg.sender] < amount) revert ERC20InsufficientAllowance( sender, recipient, _allowances[sender][msg.sender] ); _allowances[sender][msg.sender] = _allowances[sender][msg.sender] - amount; } return _transferFrom(sender, recipient, amount); } /* -------------------------------------------------------------------------- */ /* OFT */ /* -------------------------------------------------------------------------- */ function token() external view override returns (address) { return address(this); } function _debitFrom( address _from, uint16 /* dst chain id */, bytes memory /* toAddress */, uint _amount ) internal override returns (uint) { if (_from != msg.sender) { if (_allowances[_from][msg.sender] < _amount) revert ERC20InsufficientAllowance(_from, msg.sender, _amount); unchecked { _allowances[_from][msg.sender] = _allowances[_from][msg.sender] - _amount; } } if (_baseBalance[_from] < _amount) revert InsuffcientBalance(_amount); unchecked { // burn _baseBalance[_from] = _baseBalance[_from] - _amount; } return _amount; } function _creditTo( uint16 /* src chain id */, address _toAddress, uint _amount ) internal override returns (uint) { // mint _baseBalance[_toAddress] = _baseBalance[_toAddress] + _amount; return _amount; } /* -------------------------------------------------------------------------- */ /* Views */ /* -------------------------------------------------------------------------- */ function supportsInterface( bytes4 interfaceId ) public view virtual override(OFTCoreUpgradeable) returns (bool) { return interfaceId == type(IOFTUpgradeable).interfaceId || interfaceId == type(IERC20Upgradeable).interfaceId || super.supportsInterface(interfaceId); } function totalSupply() external pure override returns (uint256) { return TOTAL_SUPPLY; } function decimals() external pure returns (uint8) { return 18; } function name() external pure returns (string memory) { return _name; } function symbol() external pure returns (string memory) { return _symbol; } function balanceOf(address account) public view override returns (uint256) { return baseToReflectionAmount(_baseBalance[account]); } function baseBalanceOf(address account) public view returns(uint256) { return _baseBalance[account]; } function allowance( address holder, address spender ) external view override returns (uint256) { return _allowances[holder][spender]; } function baseToReflectionAmount( uint256 baseAmount ) public view returns (uint256) { // ASYMPTOTE = N = post reflection supply approaches total supply * N // REFLECTION_GROWTH_FACTOR = M = speed of reflections // TODO form factor as constant uint numerator = (ASYMPTOTE - 1) * ASYMPTOTE * TOTAL_SUPPLY * baseAmount; uint denominator = (REFLECTION_GROWTH_FACTOR * totalReflected) + (ASYMPTOTE * TOTAL_SUPPLY); return ASYMPTOTE * baseAmount - (numerator / denominator); } function reflectionToBaseAmount( uint reflectionAmount ) public view returns (uint) { uint numerator = reflectionAmount * ((TOTAL_SUPPLY * ASYMPTOTE) + (REFLECTION_GROWTH_FACTOR * totalReflected)); uint denominator = ASYMPTOTE * (TOTAL_SUPPLY + (REFLECTION_GROWTH_FACTOR * totalReflected)); return numerator / denominator; } function circulatingSupply() public view returns (uint256) { return baseToReflectionAmount(TOTAL_SUPPLY - balanceOf(DEAD) - balanceOf(ZERO) - totalReflected); } function circulatingBaseSupply() public view returns (uint256) { return TOTAL_SUPPLY - balanceOf(DEAD) - balanceOf(ZERO) - totalReflected; } function getMaxWalletAndTx() external view returns (bool, uint, uint) { return ( feesEnabled != 0, baseToReflectionAmount(maxWallet), baseToReflectionAmount(maxTx) ); } function getLPBurnInfo() external view returns (uint, uint, uint, uint) { return (lpBurnRatePerDay, lastBurnTime, burnRewardRate, burnTimeDiffCap); } /* -------------------------------------------------------------------------- */ /* Access restricted */ /* -------------------------------------------------------------------------- */ function clearStuckBalance() external payable onlyOwner { (bool success, ) = payable(msg.sender).call{ value: address(this).balance }(""); require(success); } function clearStuckToken() external payable onlyOwner { _transferFrom(address(this), msg.sender, balanceOf(address(this))); } function setSwapBackSettings( uint256 _enabled /* 0 = false, 1 = true */, uint256 _amount ) external payable onlyOwner { feesEnabled = _enabled; swapThreshold = _amount; } function changeFees( Fee calldata _buyFee, Fee calldata _sellFee ) external payable onlyOwner { // can cast all numbers, or just the first to save gas I think, not sure what the saving differences are like uint128 totalBuyFee = uint128(_buyFee.reflection) + _buyFee.marketing + _buyFee.omnichain + _buyFee.treasury + _buyFee.referral + _buyFee.lp + _buyFee.buyback + _buyFee.burn; uint128 totalSellFee = uint128(_sellFee.reflection) + _sellFee.marketing + _sellFee.omnichain + _sellFee.treasury + _sellFee.referral + _sellFee.lp + _sellFee.buyback + _sellFee.burn; if ( totalBuyFee != _buyFee.total || totalSellFee != _sellFee.total || totalBuyFee > MAX_FEE || totalSellFee > MAX_FEE ) revert InvalidParameters(); buyFee = _buyFee; sellFee = _sellFee; } function setFeeReceivers( address newMarketingFeeReceiver, address newLPfeeReceiver, address newBuybackFeeReceiver, address newTreasuryReceiver, address newLPBurnReceiver ) external payable onlyOwner { marketingFeeReceiver = newMarketingFeeReceiver; lpFeeReceiver = newLPfeeReceiver; buybackFeeReceiver = newBuybackFeeReceiver; treasuryReceiver = newTreasuryReceiver; lpBurnReceiver = newLPBurnReceiver; } function setTrustedRemoteWithInfo( uint16 _remoteChainId, bytes calldata _remoteAddress, uint8 chainListPosition ) external payable onlyOwner { // we only add the chain to the list of lower gas chains if it actually is a lower gas chain if (chainListPosition != 0) { chains.addNode(_remoteChainId, chainListPosition); } trustedRemoteLookup[_remoteChainId] = abi.encodePacked( _remoteAddress, address(this) ); emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress); } function setRegistredPool( address pool, uint state ) external payable onlyOwner { isRegistredPool[pool] = state; } function removeChain(uint data) external payable onlyOwner { chains.removeNode(data); } function setLPBurnData( uint256 newBurnRewardRate, uint256 newBurnTimeDiffCap, address receiver ) public payable onlyOwner { if (newBurnRewardRate > MAX_BURN_REWARD_RATE) revert InvalidParameters(); burnRewardRate = newBurnRewardRate; lpBurnReceiver = receiver; burnTimeDiffCap = newBurnTimeDiffCap; } function manuallyBurnLP() public payable onlyOwner { _burnLP(); } function toggleLimitsEnabled(bool target) public payable onlyOwner { limitsEnabled = target ? 1 : 0; } function setExcludeFromLimits( address toExclude, bool targetValue ) public payable onlyOwner { txLimitsExcluded[toExclude] = targetValue ? 1 : 0; } function setMaxWalletTransction( uint256 newMaxWallet, uint256 newMaxTx ) public payable onlyOwner { require(newMaxWallet >= MIN_MAX_WALLET && newMaxTx >= MIN_MAX_TX); maxWallet = newMaxWallet; maxTx = newMaxTx; } /* -------------------------------------------------------------------------- */ /* Internal */ /* -------------------------------------------------------------------------- */ function _transferFrom( address sender, address recipient, uint256 amount ) internal returns (bool) { bool senderIsPool = isRegistredPool[sender] != 0; // = buy bool recipientIsPool = isRegistredPool[recipient] != 0; // = sell // take launch fee first uint baseLaunchFeeAmount; // take launch fee if ( feesEnabled != 0 && !senderIsPool && isInSwap == 0 && block.timestamp - launchTime < LAUNCH_FEE_DURATION ) { isInSwap = 1; // swap back address[] memory path = new address[](2); path[0] = address(this); path[1] = UNISWAP_V2_ROUTER.WETH(); uint reflectedLaunchFeeAmount = (amount * LAUNCH_FEE * (LAUNCH_FEE_DURATION - (block.timestamp - launchTime))) / LAUNCH_FEE_DURATION / MAX_BP; baseLaunchFeeAmount = reflectionToBaseAmount( reflectedLaunchFeeAmount ); _baseBalance[address(this)] = _baseBalance[address(this)] + baseLaunchFeeAmount; emit Transfer(sender, address(this), reflectedLaunchFeeAmount); emit LaunchFee(sender, reflectedLaunchFeeAmount); UNISWAP_V2_ROUTER .swapExactTokensForETHSupportingFeeOnTransferTokens( reflectedLaunchFeeAmount, 0, path, treasuryReceiver, block.timestamp ); isInSwap = 0; } // Swap own token balance against pool if conditions are fulfilled // this has to be done before calculating baseAmount since it shifts // the balance in the liquidity pool, thus altering the result { if ( isInSwap == 0 && // this only swaps if it's not a buy, amplifying impacts of sells and // leaving buys untouched but also shifting gas costs of this to sellers only isRegistredPool[msg.sender] == 0 && feesEnabled != 0 && _baseBalance[address(this)] >= swapThreshold ) { isInSwap = 1; Fee memory memorySellFee = sellFee; uint256 stack_SwapThreshold = swapThreshold; uint256 amountToBurn = (stack_SwapThreshold * memorySellFee.burn) / memorySellFee.total; uint256 amountToSwap = stack_SwapThreshold - amountToBurn; // burn, no further checks needed here uint256 baseAmountToBurn = reflectionToBaseAmount(amountToBurn); _baseBalance[address(this)] = _baseBalance[address(this)] - baseAmountToBurn; _baseBalance[DEAD] = _baseBalance[DEAD] + baseAmountToBurn; // swap non-burned tokens to ETH address[] memory path = new address[](2); path[0] = address(this); path[1] = UNISWAP_V2_ROUTER.WETH(); UNISWAP_V2_ROUTER .swapExactTokensForETHSupportingFeeOnTransferTokens( amountToSwap, 0, path, address(this), block.timestamp ); uint256 amountETH = address(this).balance; // share of fees that should be swapped to ETH uint256 totalSwapShare = memorySellFee.total - memorySellFee.reflection - memorySellFee.burn; /* * Send proceeds to respective wallets, except for omnichain which remains in contract. * * We don't need to use return values of low level calls here since we can just manually withdraw * funds in case of failure; receiver wallets are owner supplied though and should only be EOAs * anyway */ // marketing payable(marketingFeeReceiver).call{ value: (amountETH * memorySellFee.marketing) / totalSwapShare }(""); // LP payable(lpFeeReceiver).call{ value: (amountETH * memorySellFee.lp) / totalSwapShare }(""); // buyback payable(buybackFeeReceiver).call{ value: (amountETH * memorySellFee.buyback) / totalSwapShare }(""); // treasury payable(treasuryReceiver).call{ value: (amountETH * memorySellFee.treasury) / totalSwapShare }(""); isInSwap = 0; } } uint maxRequiredBaseInput; if( recipientIsPool && lpBurnRatePerDay != 0 && block.timestamp > lastBurnTime ) { uint totalSellFee = sellFee.total; // gas savings address[] memory path = new address[](2); path[0] = address(this); path[1] = UNISWAP_V2_ROUTER.WETH(); uint outputIfSwappedBeforeBurn = UNISWAP_V2_ROUTER.getAmountsOut( feesEnabled != 0 ? amount * (MAX_BP - totalSellFee) / MAX_BP : amount, path )[1]; _burnLP(); // required input to receive correct output after paying fees maxRequiredBaseInput = reflectionToBaseAmount( UNISWAP_V2_ROUTER.getAmountsIn( outputIfSwappedBeforeBurn, path )[0] * ( feesEnabled != 0 ? MAX_BP / (MAX_BP - totalSellFee) : 1 ) ); } uint256 baseAmount = reflectionToBaseAmount(amount); if (_baseBalance[sender] < baseAmount) revert InsuffcientBalance(_baseBalance[sender]); /** * If we burn before selling, the pool receives eg 10 tokens on * 80 (+12.5%) instead of 10 tokens on 100 (+10%) and therefore * creates a higher price to sell at. * * We therefore tax the sold amount so that the received ETH amount * is the same as if the burn didn't happen beforehand, essentially * making the burn happen 'after' the swap. */ uint256 postBurnFeeBaseAmount = baseAmount; if(maxRequiredBaseInput != 0 && maxRequiredBaseInput < baseAmount) { postBurnFeeBaseAmount = maxRequiredBaseInput; _baseBalance[address(this)] = _baseBalance[address(this)] + (baseAmount - maxRequiredBaseInput); emit Transfer(sender, address(this), baseAmount - maxRequiredBaseInput); } /** * @dev this modifies LP balance and thus also reflection amount that we * previously calculated, however the actually transferred amount will * still be based on the conversion from reflected amount to base amount * at the time of the transaction initiation and will NOT account for * changes made here */ uint256 baseAmountReceived = feesEnabled != 0 && isInSwap == 0 ? _performReflectionAndTakeFees(postBurnFeeBaseAmount, sender, senderIsPool) : postBurnFeeBaseAmount; if(limitsEnabled != 0) { if ( !senderIsPool && feesEnabled != 0 && txLimitsExcluded[sender] == 0 && baseAmount > maxTx ) revert MaxTransaction(); if ( feesEnabled != 0 && !recipientIsPool && txLimitsExcluded[recipient] == 0 && _baseBalance[recipient] + baseAmountReceived > maxWallet ) revert MaxWallet(); } _baseBalance[sender] = _baseBalance[sender] - baseAmount; _baseBalance[recipient] = _baseBalance[recipient] + baseAmountReceived; emit Transfer(sender, recipient, baseToReflectionAmount(baseAmountReceived)); return true; } function _burnLP() internal { uint mem_lastBurnTime = lastBurnTime; uint256 pairBalance = _baseBalance[_uniswapPair]; // gas savings uint256 timeDelta = block.timestamp <= mem_lastBurnTime + burnTimeDiffCap ? (block.timestamp - mem_lastBurnTime) : 1 days; uint256 tokensToRemove = pairBalance * timeDelta * lpBurnRatePerDay / (1 days * MAX_BP); uint256 tokensToReward = tokensToRemove * burnRewardRate / MAX_BP; uint256 tokensToBurn = tokensToRemove - tokensToReward; lastBurnTime = block.timestamp; _baseBalance[_uniswapPair] = pairBalance - tokensToRemove; if(tokensToBurn != 0) { emit Transfer( _uniswapPair, address(0), baseToReflectionAmount(tokensToBurn)); } if(tokensToReward != 0) { _baseBalance[lpBurnReceiver] = _baseBalance[lpBurnReceiver] + tokensToReward; emit Transfer(_uniswapPair, lpBurnReceiver, baseToReflectionAmount(tokensToReward)); } // Update the uniswap pair's reserves IUniswapV2Pair(_uniswapPair).sync(); } function _performReflectionAndTakeFees( uint256 baseAmount, address sender, bool buying ) internal returns (uint256) { Fee memory memoryBuyFee = buyFee; Fee memory memorySellFee = sellFee; // amount of fees in base amount (non-reflection adjusted) uint256 baseFeeAmount = buying ? (baseAmount * memoryBuyFee.total) / MAX_BP : (baseAmount * memorySellFee.total) / MAX_BP; // reflect uint256 baseAmountReflected = buying ? (baseAmount * memoryBuyFee.reflection) / MAX_BP : (baseAmount * memorySellFee.reflection) / MAX_BP; /** * Omnichain * * - integrate local delta into state * - send local delta to lower gas chains * - request local state from lowest gas chain * - set local state to minimum (=most recent) of local state & remote state */ totalReflected = totalReflected + baseAmountReflected; emit Reflect(baseAmountReflected, totalReflected); _transmitReflectionToOtherChainsAndFetchState(); // add entire non-reflected amount to contract balance for later swapping uint256 baseBalanceToContract = baseFeeAmount - baseAmountReflected; if (baseBalanceToContract != 0) { _baseBalance[address(this)] = _baseBalance[address(this)] + baseBalanceToContract; emit Transfer( sender, address(this), baseToReflectionAmount(baseBalanceToContract) ); } return baseAmount - baseFeeAmount; // - launchFeeAmount; } /* -------------------------------------------------------------------------- */ /* L0 */ /* -------------------------------------------------------------------------- */ /** * @notice Multicast reflection state change to all chains that are tendencially * cheaper than the local chain & fetch reflection state of cheapest chain to * integrate into local state */ function _transmitReflectionToOtherChainsAndFetchState() internal { if (chains.length < 2) return; uint256[] memory lowerGasChains = chains.getBeheadedList(); uint256 lowerGasChainsLen = lowerGasChains.length; // gas savings uint mem_totalReflected = totalReflected; // gas savings bytes memory lzPayload = abi.encode(PT_TRANSMIT, mem_totalReflected); for (uint iterator; iterator < lowerGasChainsLen - 1; ) { (uint gasRequired /* zroFee */, ) = lzEndpoint.estimateFees( uint16(lowerGasChains[iterator]), address(this), lzPayload, false, abi.encodePacked(uint16(1), LZ_GAS_USAGE_LIMIT) ); if (address(this).balance > gasRequired) { _lzSend( // cheapest chain = destination chainId uint16(lowerGasChains[iterator]), // abi.encode()'ed bytes lzPayload, // (msg.sender will be this contract) refund address // (LayerZero will refund any extra gas back to caller of send() payable(this), // future param, unused for this example address(0x0), // v1 adapterParams, specify custom destination gas qty abi.encodePacked(uint16(1), LZ_GAS_USAGE_LIMIT), address(this).balance ); emit TransmitToRemote( uint16(lowerGasChains[iterator]), mem_totalReflected ); unchecked { iterator = iterator + 1; } } else { // abort transmissions if gas is insufficient return; } } uint256 lowestGasChainId = lowerGasChains[lowerGasChainsLen - 1]; if (lzChainId != lowestGasChainId) { lzPayload = abi.encode(PT_TRANSMIT_AND_REQUEST, mem_totalReflected); (uint gasRequired /* zroFee */, ) = lzEndpoint.estimateFees( uint16(lowestGasChainId), address(this), lzPayload, false, abi.encodePacked(uint16(1), LZ_GAS_USAGE_LIMIT) ); if (address(this).balance > gasRequired) { // fetch the state from the lowest gas chain _lzSend( // destination chainId uint16(lowestGasChainId), // abi.encoded bytes lzPayload, // refund address payable(this), // future param, unused for this example address(0x0), // v1 adapterParams, specify custom destination gas qty abi.encodePacked(uint16(1), LZ_GAS_USAGE_LIMIT), address(this).balance ); emit TransmitToRemote( uint16(lowestGasChainId), mem_totalReflected ); emit RequestRemoteState(uint16(lowestGasChainId)); } } } function _nonblockingLzReceive( uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload ) internal virtual override { uint16 packetType; assembly { packetType := mload(add(_payload, 32)) } if (packetType == PT_SEND) { // token transfers between chains _sendAck(_srcChainId, _srcAddress, _nonce, _payload); } else if (packetType == PT_TRANSMIT_AND_REQUEST) { _receiveReflectionAndSendLocalState( _srcChainId, _payload, true /* is request? */ ); } else if (packetType == PT_TRANSMIT) { _receiveReflectionAndSendLocalState( _srcChainId, _payload, false /* is request? */ ); } else if (packetType == PT_RESPONSE) { _receiveRemoteReflectionState(_payload); } else { revert OFTCoreUnknownPacketType(); } } function _receiveReflectionAndSendLocalState( uint16 _srcChainId, bytes memory _payload, bool isReq ) internal { (, /* packet type */ uint remoteState) = abi.decode( _payload, (uint16, uint) ); // update local reflection data if (remoteState > totalReflected) { uint diff = remoteState - totalReflected; totalReflected = remoteState; emit XReflect(diff, totalReflected); emit ReceiveRemoteState(_srcChainId, remoteState); } // transmission comes from higher gas chain that wants to know local state if (isReq) { // pack payload AFTER integrating remote delta bytes memory lzPayload = abi.encode(PT_RESPONSE, totalReflected); // send response to origin chain _lzSend( _srcChainId, // destination chainId lzPayload, // abi.encode()'ed bytes payable(this), // (msg.sender will be this contract) refund address address(0x0), // future param, unused for this example abi.encodePacked(uint16(1), LZ_GAS_USAGE_LIMIT), // v1 adapterParams, specify custom destination gas qty address(this).balance ); emit AnswerToRemote(_srcChainId, totalReflected); } } /** * @notice receive response to a request made to the lowest gas chain * @param _payload contains (uint16 packetType, uint256 remoteReflectionState) */ function _receiveRemoteReflectionState(bytes memory _payload) internal { (, /* packet type */ uint remoteReflectionState) = abi.decode( _payload, (uint16, uint) ); // if remote that is less recent than local state, we just ignore instead // of throwing so L0 does not have to store failed message if (remoteReflectionState > totalReflected) { // integrate remote changes if they are more recent than local state (=smaller value) uint reflectionStateDiff = remoteReflectionState - totalReflected; if (reflectionStateDiff != 0) { totalReflected = remoteReflectionState; emit XReflect(reflectionStateDiff, remoteReflectionState); } } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19; // import "hardhat/console.sol"; struct ListElement { uint data; bytes32 pointer; } struct SingleLinkedList { uint length; ListElement head; mapping(bytes32 => ListElement) elements; } library SingleLinkedListLib { error CannotReplaceHead(); bytes32 constant ZERO_POINTER = keccak256(abi.encode(0)); function addNode(SingleLinkedList storage self, uint data, uint position) internal { if(position == 0 && self.length != 0) revert CannotReplaceHead(); ListElement memory element = ListElement({data: data, pointer: ZERO_POINTER}); bytes32 elementHash = keccak256(abi.encode(data)); if(self.length == 0) { self.head = element; self.elements[elementHash] = element; } else if(position >= self.length) { // find tail = element with a zero pointer ListElement storage toCheck = self.head; while(toCheck.pointer != ZERO_POINTER) { toCheck = self.elements[toCheck.pointer]; } toCheck.pointer = elementHash; /* pointer to new element */ self.elements[elementHash] = element; } else { ListElement storage toCheck = self.head; uint iterator; while(iterator < position) { toCheck = self.elements[toCheck.pointer]; unchecked { iterator = iterator + 1; } } // after loop executed, iterator is position // toCheck is predecessor bytes32 oldPointer = toCheck.pointer; toCheck.pointer = elementHash; element.pointer = oldPointer; self.elements[elementHash] = element; } self.length = self.length + 1; } function removeNode(SingleLinkedList storage self, uint data) internal { // TODO } function getBeheadedList(SingleLinkedList storage self) internal view returns(uint[] memory) { uint toReturnLen = self.length-1; uint[] memory beheadedList = new uint[](self.length-1); ListElement memory e = self.head; for(uint iterator; iterator < toReturnLen;) { e = self.elements[e.pointer]; beheadedList[iterator] = e.data; unchecked { iterator = iterator + 1; } } return beheadedList; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"FarmFacet__AlreadyUnlocked","type":"error"},{"inputs":[],"name":"FarmFacet__AlreadyVested","type":"error"},{"inputs":[],"name":"FarmFacet__InvalidDuration","type":"error"},{"inputs":[],"name":"FarmFacet__MinLockDuration","type":"error"},{"inputs":[],"name":"FarmFacet__NotEnoughRewards","type":"error"},{"inputs":[],"name":"FarmFacet__NotLocker","type":"error"},{"inputs":[],"name":"FarmFacet__NotTransferable","type":"error"},{"inputs":[],"name":"FarmFacet__NotVester","type":"error"},{"inputs":[{"internalType":"uint256","name":"_timeLeft","type":"uint256"}],"name":"FarmFacet__StillLocked","type":"error"},{"inputs":[],"name":"Ownable__NotOwner","type":"error"},{"inputs":[],"name":"Ownable__NotTransitiveOwner","type":"error"},{"inputs":[],"name":"Pausable__NotPaused","type":"error"},{"inputs":[],"name":"Pausable__Paused","type":"error"},{"inputs":[],"name":"ReentrancyGuard__ReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"addressToLockingIndexList","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"addressToVestIndexList","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"calculateRewardsEarned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vestIndex","type":"uint256"}],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getUserLockList","outputs":[{"components":[{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"receiptAmount","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"unlocked","type":"uint256"},{"internalType":"address","name":"locker","type":"address"}],"internalType":"struct LibFarmStorage.Lock[]","name":"_lockList","type":"tuple[]"},{"internalType":"uint256[]","name":"lockingIndexList","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getUserVestList","outputs":[{"components":[{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"vested","type":"uint256"},{"internalType":"address","name":"vester","type":"address"}],"internalType":"struct LibFarmStorage.Vest[]","name":"_vestList","type":"tuple[]"},{"internalType":"uint256[]","name":"vestIndexList","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVestDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockingIndex","type":"uint256"}],"name":"lockingIndexToLock","outputs":[{"components":[{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"receiptAmount","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"unlocked","type":"uint256"},{"internalType":"address","name":"locker","type":"address"}],"internalType":"struct LibFarmStorage.Lock","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"status","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minLockDuration","type":"uint256"},{"internalType":"uint256","name":"maxLockDuration","type":"uint256"},{"internalType":"uint256","name":"earlyVestPenalty","type":"uint256"},{"internalType":"uint256","name":"penaltyToStaker","type":"uint256"}],"name":"setLockDurations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPauseStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"address","name":"_rewardToken","type":"address"}],"name":"setTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_router","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vestDuration","type":"uint256"}],"name":"setVestDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockingIndex","type":"uint256"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vestIndex","type":"uint256"}],"name":"vestIndexToVest","outputs":[{"components":[{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"vested","type":"uint256"},{"internalType":"address","name":"vester","type":"address"}],"internalType":"struct LibFarmStorage.Vest","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608080604052346100165761257a908161001c8239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c80628cc26214611c5c578063095ea7b3146106eb5780631338736f1461183e57806318160ddd146118135780631d66b9e3146117c057806323b872dd146117a65780632421e21314611743578063379607f514610ff9578063458efde314610e155780635568587a14610dbc5780635c975abb14610d8c5780636198e33914610b0f5780636bdda71214610a9857806370a0823114610a6b57806370c6b8a41461098757806372f702f3146109515780637637704d146107e75780638b086764146107bb5780638d3fb84214610753578063a21230e9146106f0578063a9059cbb146106eb578063adfe08701461056c578063c38bb53714610469578063cbc7854e146103d1578063dd62ed3e1461039b578063e239c40014610338578063e9ee2fa91461030d578063ed033c99146101935763f7c618c11461015b57600080fd5b346101905780600319360112610190576000805160206124e5833981519152546040516001600160a01b039091168152602090f35b80fd5b503461019057602080600319360112610309576101b66101b1611c80565b611e21565b604051808284829454938481520190865284862092865b868282106102f3575050506101e492500382611d47565b8051926101f0846120d2565b936101fe6040519586611d47565b80855261020d601f19916120d2565b0183825b8281106102dd57505050805b825181101561025d578061023d61023761025893866120ea565b516123d5565b61024782886120ea565b5261025281876120ea565b5061231e565b61021d565b5091604051926040840160408552855180915282606086019601915b818110610297578587038487015285806102938988611cc5565b0390f35b909195836080826102d26001948b516060908051835260208101516020840152604081015160408401528160018060a01b0391015116910152565b019701929101610279565b6102e561232d565b828289010152018490610211565b85548452600195860195879550930192016101cd565b5080fd5b5034610190578060031936011261019057602060008051602061246583398151915254604051908152f35b503461019057806003193601126101905760407f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834b547f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834c5482519182526020820152f35b5034610190576040366003190112610190576103b5611c80565b506103be611c96565b506040516350662aa360e11b8152600490fd5b5034610190576040366003190112610190576103eb611c80565b6103f3611c96565b6000805160206124a5833981519152549091906001600160a01b039081163303610457576001600160601b0360a01b91816000805160206125058339815191529116838254161790556000805160206124e583398151915292169082541617905580f35b604051632f7a8ee160e01b8152600490fd5b5034610190576020366003190112610190576004358015158103610309576000805160206124a5833981519152546001600160a01b03163303610457571561050d57600080516020612445833981519152805460ff81166104fb5760019060ff19161790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b6040516302ca8ced60e11b8152600490fd5b600080516020612445833981519152805460ff81161561055a5760ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b604051632ca4452d60e11b8152600490fd5b503461019057604036600319011261019057610586611c80565b61058e611c96565b6000805160206124a5833981519152546001600160a01b0392919083163303610457576001600160601b0360a01b91837f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8342911683825416179055826000805160206124e58339815191525416917f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834391848354166040519363095ea7b360e01b91828652600486015287602486015260209687866044818c8b5af19384156106e05788966044956106c3575b501680948254161790558660405195869485938452600484015260001960248401525af180156106b85761068b578280f35b816106aa92903d106106b1575b6106a28183611d47565b810190611f10565b5038808280f35b503d610698565b6040513d85823e3d90fd5b6106d990883d8a116106b1576106a28183611d47565b5038610659565b6040513d8b823e3d90fd5b611cac565b503461019057806003193601126101905760407f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8351547f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83505482519182526020820152f35b50346101905760203660031901126101905760c0610772600435612352565b6107b9604051809260a090805183526020810151602084015260408101516040840152606081015160608401526080810151608084015281600180821b0391015116910152565bf35b50346101905760203660031901126101905760206107df6107da611c80565b612171565b604051908152f35b5034610190576020806003193601126103095761080a610805611c80565b611daf565b604051808284829454938481520190865284862092865b8682821061093b5750505061083892500382611d47565b805192610844846120d2565b936108526040519586611d47565b808552610861601f19916120d2565b0183825b82811061092557505050805b8251811015610896578061023d61088b61089193866120ea565b51612352565b610871565b5091604051926040840160408552855180915282606086019601915b8181106108cc578587038487015285806102938988611cc5565b9091958360c08261091a6001948b5160a090805183526020810151602084015260408101516040840152606081015160608401526080810151608084015281600180821b0391015116910152565b0197019291016108b2565b61092d6122ec565b828289010152018490610865565b8554845260019586019587955093019201610821565b5034610190578060031936011261019057600080516020612505833981519152546040516001600160a01b039091168152602090f35b5034610190576080366003190112610190576000805160206124a58339815191525460243590600435906001600160a01b031633036104575781811015610a59577f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834b557f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834c556044357f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8350556064357f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83555580f35b60405163945441ab60e01b8152600490fd5b5034610190576020366003190112610190576020610a8f610a8a611c80565b611de8565b54604051908152f35b50346101905760208060031936011261030957610ab6610805611c80565b91604051809384918482549182815201918452848420935b85828210610af957505050610ae592500383611d47565b610293604051928284938452830190611cc5565b8554845260019586019588955093019201610ace565b503461019057602090816003193601126101905760ff60008051602061244583398151915254166104fb576000805160206125258339815191526002815414610d7a576002815560043582527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834d83526040822060058101549093906001600160a01b039081163303610d685760048501948554610d5657805495600382015496610bb98882611d69565b4210610d2b575085965083916001610c5d92610bd433611f28565b55610bde33611de8565b54610bef6002830191825490612092565b610bf833611de8565b55610c16600080516020612485833981519152918254905490612092565b9055600080516020612505833981519152546001919091015460405163a9059cbb60e01b815233600482015260248101919091529687929185169183919082906044820190565b03925af1908115610d20576024948392610d03575b506000805160206124e58339815191525416604051948580926347a5051760e01b82523060048301525afa908115610cf8578491610cc4575b50600192506000805160206124c5833981519152555580f35b905082813d8311610cf1575b610cda8183611d47565b81010312610cec576001915138610cab565b600080fd5b503d610cd0565b6040513d86823e3d90fd5b610d1990833d85116106b1576106a28183611d47565b5038610c72565b6040513d87823e3d90fd5b610d41602491610d3c8a4292611d69565b612092565b6040519063a4de575760e01b82526004820152fd5b60405163349020f760e01b8152600490fd5b604051632905caf560e11b8152600490fd5b604051635db5c7cd60e11b8152600490fd5b5034610190578060031936011261019057602060ff60008051602061244583398151915254166040519015158152f35b5034610190576020366003190112610190576000805160206124a5833981519152546001600160a01b03163303610457576004357f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83515580f35b503461019057806003193601126101905760ff60008051602061244583398151915254166104fb576000805160206125258339815191526002815414610d7a5760028155610e6233611f28565b610e6b33611d76565b54610e7533611e5a565b541015610fe757610e99610e8833611d76565b54610e9233611e5a565b5490612092565b7f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834f80549060018201809211610fd3579181610f83846003946024979655610f6860405194610ee686611d2b565b428652602096868b89809901848152604080840192808452606085019a338c5281527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83528c5220925183555160018301555160028201550160018060a01b03809651166001600160601b0360a01b825416179055610f6233611e5a565b54611d69565b610f7133611e5a565b55610f7b33611e21565b905490611ecc565b6000805160206124e58339815191525416604051948580926347a5051760e01b82523060048301525afa908115610cf8578491610cc45750600192506000805160206124c5833981519152555580f35b634e487b7160e01b85526011600452602485fd5b604051630553202d60e01b8152600490fd5b50346101905760203660031901126101905760ff60008051602061244583398151915254166104fb5760026000805160206125258339815191525414610d7a5760026000805160206125258339815191525561105433611f28565b60043581527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8352602052604081206002810154611731576003810154336001600160a01b039091160361171f5760018101549060018060a01b036000805160206124e5833981519152541692604051634ab4948560e11b8152836004820152602081602481885afa9081156114325782916116ed575b5080938293839261111d82547f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83515490611d69565b4210611647575b5090600160026111569301556111438161113d33611d76565b54612092565b61114c33611d76565b5561113d33611e5a565b61115f33611e5a565b558061143d575b509080611285575b5060405163a9059cbb60e01b815233600482015260248101839052926020908490604490829085905af192831561127857602493611259575b506000805160206124e5833981519152546040516347a5051760e01b81523060048201529360209185919082906001600160a01b03165afa90811561124d579061121a575b602092506000805160206124c583398151915255600160008051602061252583398151915255604051908152f35b506020823d602011611245575b8161123460209383611d47565b81010312610cec57602091516111ec565b3d9150611227565b604051903d90823e3d90fd5b6112719060203d6020116106b1576106a28183611d47565b50386111a7565b50604051903d90823e3d90fd5b6040519063f9a3dbdd60e01b82526004820152602081602481875afa908115611432578291611400575b506000805160206124858339815191525481816112ce575b505061116e565b6000805160206124e5833981519152546040516347a5051760e01b81523060048201529190602090839060249082906001600160a01b03165afa9182156113f4576000926113c0575b5015806113a8575b611385575b5060008051602061246583398151915291825490670de0b6b3a76400009081810291818304149015171561136f576113659261135f916120b2565b90611d69565b90553880806112c7565b634e487b7160e01b600052601160045260246000fd5b6113a19192506000805160206124c58339815191525490612092565b9038611324565b506000805160206124c583398151915254811161131f565b90916020823d6020116113ec575b816113db60209383611d47565b810103126101905750519038611317565b3d91506113ce565b6040513d6000823e3d90fd5b90506020813d60201161142a575b8161141b60209383611d47565b81010312610cec5751386112af565b3d915061140e565b6040513d84823e3d90fd5b60018060a01b037f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8343541660405180606081011067ffffffffffffffff606083011117611633576060810160405260028152604036602083013760018060a01b036000805160206124e583398151915254168151156115dd5760208201526040516315ab88c960e31b8152602081600481865afa908115610d205785916115f1575b508151600110156115dd576001600160a01b0390811660408301527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83425416823b156115d957929091849260405194859363791ac94760e01b855260a4850190600486015285602486015260a060448601528251809152602060c48601930190865b8181106115b4575050508380928692606483015242608483015203925af1801561143257156111665767ffffffffffffffff81116115a05760405238611166565b634e487b7160e01b82526041600452602482fd5b82516001600160a01b031685528997508896506020948501949092019160010161155f565b8480fd5b634e487b7160e01b85526032600452602485fd5b90506020813d60201161162b575b8161160c60209383611d47565b810103126115d957516001600160a01b03811681036115d957386114de565b3d91506115ff565b634e487b7160e01b84526041600452602484fd5b94509450905061271061167b7f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8350548561209f565b04927f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf835554936127106116ad868361209f565b049461271081810311610fd35760026116e361115694610d3c6127106116da8b999760019783039061209f565b04978892612092565b9792935050611124565b90506020813d602011611717575b8161170860209383611d47565b810103126103095751386110e9565b3d91506116fb565b604051630140fc5360e41b8152600490fd5b60405163012c9a8b60e61b8152600490fd5b503461019057602080600319360112610309576117616101b1611c80565b91604051809384918482549182815201918452848420935b8582821061179057505050610ae592500383611d47565b8554845260019586019588955093019201611779565b5034610190576060366003190112610190576103b5611c80565b50346101905760203660031901126101905760806117df6004356123d5565b6107b960405180926060908051835260208101516020840152604081015160408401528160018060a01b0391015116910152565b5034610190578060031936011261019057602060008051602061248583398151915254604051908152f35b50346101905760403660031901126101905760043560249081359060ff60008051602061244583398151915254166104fb57600080516020612525833981519152916002835414610d7a5760028355807f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834c547f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834b5491828110611c4a578110611c42575b6118ea33611f28565b808310611b1157505081905b7f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834a9283549260018401809411611afe5790839291889486556119d86040519661193e88611cf9565b4288526005602098899687820190878252604083018781526060840191825260808401928c845260a085019b338d528d527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834d8b5260408d20945185555160018501555160028401555160038301555160048201550160018060a01b03809751166001600160601b0360a01b825416179055610f7b33611daf565b6119e581610f6233611de8565b6119ee33611de8565b55611a09600080516020612485833981519152918254611d69565b905560648360008051602061250583398151915254169160405195869384926323b872dd60e01b8452336004850152308c85015260448401525af1918215611af3578392611ad6575b506000805160206124e58339815191525416604051948580926347a5051760e01b82523060048301525afa908115610cf8578491611aa35750600192506000805160206124c5833981519152555580f35b905082813d8311611acf575b611ab98183611d47565b81010312611acb576001915138610cab565b8280fd5b503d611aaf565b611aec90833d85116106b1576106a28183611d47565b5038611a52565b6040513d88823e3d90fd5b634e487b7160e01b885260116004528688fd5b81611b1b916120fe565b611b2582846120fe565b6123289080820291820503611afe5781611b3e91612129565b806103e8019160019183128216611c2f5792906202a3008405611b6081612117565b94611b6a82612160565b935b828512611b98575050505050611b8b611b919161271080940590612144565b8461209f565b04906118f6565b909192939562015180808802908882051488151715611c1c5783611bd0611bcb85611bc6611bd5958e612144565b6120fe565b612117565b612129565b6101f48d8282039212818312811691831390151617611c1c578591611c02918e811315611c0d57906120fe565b960193929190611b6c565b611c1690612160565b906120fe565b634e487b7160e01b8d5260116004528b8dfd5b634e487b7160e01b895260116004528789fd5b9150816118e1565b60405163d290862b60e01b8152600490fd5b5034610190576020366003190112610190576020610a8f611c7b611c80565b611d76565b600435906001600160a01b0382168203610cec57565b602435906001600160a01b0382168203610cec57565b34610cec576040366003190112610cec576103be611c80565b90815180825260208080930193019160005b828110611ce5575050505090565b835185529381019392810192600101611cd7565b60c0810190811067ffffffffffffffff821117611d1557604052565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff821117611d1557604052565b90601f8019910116810190811067ffffffffffffffff821117611d1557604052565b9190820180921161136f57565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83486020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834e6020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83446020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83536020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83546020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83476020526040902090565b80549068010000000000000000821015611d155760018201808255821015611efa5760005260206000200155565b634e487b7160e01b600052603260045260246000fd5b90816020910312610cec57518015158103610cec5790565b60006000805160206124858339815191525480611fa8575b5050611fa5611f4e82611d76565b54611f94611f5b84611de8565b5491670de0b6b3a7640000611f8d60008051602061246583398151915294611f878654610e928a611e93565b9061209f565b0490611d69565b611f9d84611d76565b555491611e93565b55565b6000805160206124e5833981519152546040516347a5051760e01b815230600482015290602090829060249082906001600160a01b03165afa9081156106b8578391612061575b506000805160206124c5833981519152549081811161204e575b505060008051602061246583398151915291825490670de0b6b3a76400009081810291818304149015171561136f576120459261135f916120b2565b90553880611f40565b612059929350612092565b903880612009565b90506020813d821161208a575b8161207b60209383611d47565b81010312611acb575138611fef565b3d915061206e565b9190820391821161136f57565b8181029291811591840414171561136f57565b81156120bc570490565b634e487b7160e01b600052601260045260246000fd5b67ffffffffffffffff8111611d155760051b60200190565b8051821015611efa5760209160051b010190565b8181039291600013801582851316918412161761136f57565b906103e8918083029283050361136f57565b81156120bc57600160ff1b811460001983141661136f570590565b9190916000838201938412911290801582169115161761136f57565b600160ff1b811461136f5760000390565b600080516020612485833981519152548061218d575050600090565b6000805160206124e5833981519152546040516347a5051760e01b81523060048201526001600160a01b039091169260209290918381602481885afa80156113f4576000906122bd575b6121f291506000805160206124c58339815191525490612092565b9160008051602061246583398151915254670de0b6b3a7640000938481029080820486149015171561136f578594612237610e929361135f6122629761225c956120b2565b90611f8d61224486611de8565b54611f8761225188611d76565b5494610e9289611e93565b91611e5a565b602460405180958193634ab4948560e11b835260048301525afa9081156113f457600091612291575b50905090565b82813d83116122b6575b6122a58183611d47565b81010312610190575051803861228b565b503d61229b565b8482813d83116122e5575b6122d28183611d47565b8101031261019057506121f290516121d7565b503d6122c8565b604051906122f982611cf9565b8160a06000918281528260208201528260408201528260608201528260808201520152565b600019811461136f5760010190565b6040519061233a82611d2b565b60006060838281528260208201528260408201520152565b61235a6122ec565b506000527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834d60205260406000206040519061239482611cf9565b8054825260018101546020830152600281015460408301526003810154606083015260048101546080830152600501546001600160a01b031660a082015290565b6123dd61232d565b506000527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf835260205260406000206040519061241782611d2b565b805482526001810154602083015260028101546040830152600301546001600160a01b031660608201529056fe68721c0bbf2c02a4d65000340d1370666be06a630022208d4baa9bd7a4b6fea8057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8346057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83458a22373512790c48b83a1fe2efdd2888d4a917bcdc24d0adf63e60f671680460057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8349057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8341057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834009acf4e54214992e70883cf7dcd6957ff2c71cd9e14df4bec4383bc0d11607dca26469706673582212204dfe8470f1ce1730d0f3c5abc819398858ab4f5ff7eeab59f64049a86b844c2a64736f6c63430008130033
Deployed Bytecode
0x6080604052600436101561001257600080fd5b6000803560e01c80628cc26214611c5c578063095ea7b3146106eb5780631338736f1461183e57806318160ddd146118135780631d66b9e3146117c057806323b872dd146117a65780632421e21314611743578063379607f514610ff9578063458efde314610e155780635568587a14610dbc5780635c975abb14610d8c5780636198e33914610b0f5780636bdda71214610a9857806370a0823114610a6b57806370c6b8a41461098757806372f702f3146109515780637637704d146107e75780638b086764146107bb5780638d3fb84214610753578063a21230e9146106f0578063a9059cbb146106eb578063adfe08701461056c578063c38bb53714610469578063cbc7854e146103d1578063dd62ed3e1461039b578063e239c40014610338578063e9ee2fa91461030d578063ed033c99146101935763f7c618c11461015b57600080fd5b346101905780600319360112610190576000805160206124e5833981519152546040516001600160a01b039091168152602090f35b80fd5b503461019057602080600319360112610309576101b66101b1611c80565b611e21565b604051808284829454938481520190865284862092865b868282106102f3575050506101e492500382611d47565b8051926101f0846120d2565b936101fe6040519586611d47565b80855261020d601f19916120d2565b0183825b8281106102dd57505050805b825181101561025d578061023d61023761025893866120ea565b516123d5565b61024782886120ea565b5261025281876120ea565b5061231e565b61021d565b5091604051926040840160408552855180915282606086019601915b818110610297578587038487015285806102938988611cc5565b0390f35b909195836080826102d26001948b516060908051835260208101516020840152604081015160408401528160018060a01b0391015116910152565b019701929101610279565b6102e561232d565b828289010152018490610211565b85548452600195860195879550930192016101cd565b5080fd5b5034610190578060031936011261019057602060008051602061246583398151915254604051908152f35b503461019057806003193601126101905760407f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834b547f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834c5482519182526020820152f35b5034610190576040366003190112610190576103b5611c80565b506103be611c96565b506040516350662aa360e11b8152600490fd5b5034610190576040366003190112610190576103eb611c80565b6103f3611c96565b6000805160206124a5833981519152549091906001600160a01b039081163303610457576001600160601b0360a01b91816000805160206125058339815191529116838254161790556000805160206124e583398151915292169082541617905580f35b604051632f7a8ee160e01b8152600490fd5b5034610190576020366003190112610190576004358015158103610309576000805160206124a5833981519152546001600160a01b03163303610457571561050d57600080516020612445833981519152805460ff81166104fb5760019060ff19161790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b6040516302ca8ced60e11b8152600490fd5b600080516020612445833981519152805460ff81161561055a5760ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b604051632ca4452d60e11b8152600490fd5b503461019057604036600319011261019057610586611c80565b61058e611c96565b6000805160206124a5833981519152546001600160a01b0392919083163303610457576001600160601b0360a01b91837f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8342911683825416179055826000805160206124e58339815191525416917f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834391848354166040519363095ea7b360e01b91828652600486015287602486015260209687866044818c8b5af19384156106e05788966044956106c3575b501680948254161790558660405195869485938452600484015260001960248401525af180156106b85761068b578280f35b816106aa92903d106106b1575b6106a28183611d47565b810190611f10565b5038808280f35b503d610698565b6040513d85823e3d90fd5b6106d990883d8a116106b1576106a28183611d47565b5038610659565b6040513d8b823e3d90fd5b611cac565b503461019057806003193601126101905760407f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8351547f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83505482519182526020820152f35b50346101905760203660031901126101905760c0610772600435612352565b6107b9604051809260a090805183526020810151602084015260408101516040840152606081015160608401526080810151608084015281600180821b0391015116910152565bf35b50346101905760203660031901126101905760206107df6107da611c80565b612171565b604051908152f35b5034610190576020806003193601126103095761080a610805611c80565b611daf565b604051808284829454938481520190865284862092865b8682821061093b5750505061083892500382611d47565b805192610844846120d2565b936108526040519586611d47565b808552610861601f19916120d2565b0183825b82811061092557505050805b8251811015610896578061023d61088b61089193866120ea565b51612352565b610871565b5091604051926040840160408552855180915282606086019601915b8181106108cc578587038487015285806102938988611cc5565b9091958360c08261091a6001948b5160a090805183526020810151602084015260408101516040840152606081015160608401526080810151608084015281600180821b0391015116910152565b0197019291016108b2565b61092d6122ec565b828289010152018490610865565b8554845260019586019587955093019201610821565b5034610190578060031936011261019057600080516020612505833981519152546040516001600160a01b039091168152602090f35b5034610190576080366003190112610190576000805160206124a58339815191525460243590600435906001600160a01b031633036104575781811015610a59577f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834b557f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834c556044357f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8350556064357f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83555580f35b60405163945441ab60e01b8152600490fd5b5034610190576020366003190112610190576020610a8f610a8a611c80565b611de8565b54604051908152f35b50346101905760208060031936011261030957610ab6610805611c80565b91604051809384918482549182815201918452848420935b85828210610af957505050610ae592500383611d47565b610293604051928284938452830190611cc5565b8554845260019586019588955093019201610ace565b503461019057602090816003193601126101905760ff60008051602061244583398151915254166104fb576000805160206125258339815191526002815414610d7a576002815560043582527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834d83526040822060058101549093906001600160a01b039081163303610d685760048501948554610d5657805495600382015496610bb98882611d69565b4210610d2b575085965083916001610c5d92610bd433611f28565b55610bde33611de8565b54610bef6002830191825490612092565b610bf833611de8565b55610c16600080516020612485833981519152918254905490612092565b9055600080516020612505833981519152546001919091015460405163a9059cbb60e01b815233600482015260248101919091529687929185169183919082906044820190565b03925af1908115610d20576024948392610d03575b506000805160206124e58339815191525416604051948580926347a5051760e01b82523060048301525afa908115610cf8578491610cc4575b50600192506000805160206124c5833981519152555580f35b905082813d8311610cf1575b610cda8183611d47565b81010312610cec576001915138610cab565b600080fd5b503d610cd0565b6040513d86823e3d90fd5b610d1990833d85116106b1576106a28183611d47565b5038610c72565b6040513d87823e3d90fd5b610d41602491610d3c8a4292611d69565b612092565b6040519063a4de575760e01b82526004820152fd5b60405163349020f760e01b8152600490fd5b604051632905caf560e11b8152600490fd5b604051635db5c7cd60e11b8152600490fd5b5034610190578060031936011261019057602060ff60008051602061244583398151915254166040519015158152f35b5034610190576020366003190112610190576000805160206124a5833981519152546001600160a01b03163303610457576004357f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83515580f35b503461019057806003193601126101905760ff60008051602061244583398151915254166104fb576000805160206125258339815191526002815414610d7a5760028155610e6233611f28565b610e6b33611d76565b54610e7533611e5a565b541015610fe757610e99610e8833611d76565b54610e9233611e5a565b5490612092565b7f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834f80549060018201809211610fd3579181610f83846003946024979655610f6860405194610ee686611d2b565b428652602096868b89809901848152604080840192808452606085019a338c5281527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83528c5220925183555160018301555160028201550160018060a01b03809651166001600160601b0360a01b825416179055610f6233611e5a565b54611d69565b610f7133611e5a565b55610f7b33611e21565b905490611ecc565b6000805160206124e58339815191525416604051948580926347a5051760e01b82523060048301525afa908115610cf8578491610cc45750600192506000805160206124c5833981519152555580f35b634e487b7160e01b85526011600452602485fd5b604051630553202d60e01b8152600490fd5b50346101905760203660031901126101905760ff60008051602061244583398151915254166104fb5760026000805160206125258339815191525414610d7a5760026000805160206125258339815191525561105433611f28565b60043581527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8352602052604081206002810154611731576003810154336001600160a01b039091160361171f5760018101549060018060a01b036000805160206124e5833981519152541692604051634ab4948560e11b8152836004820152602081602481885afa9081156114325782916116ed575b5080938293839261111d82547f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83515490611d69565b4210611647575b5090600160026111569301556111438161113d33611d76565b54612092565b61114c33611d76565b5561113d33611e5a565b61115f33611e5a565b558061143d575b509080611285575b5060405163a9059cbb60e01b815233600482015260248101839052926020908490604490829085905af192831561127857602493611259575b506000805160206124e5833981519152546040516347a5051760e01b81523060048201529360209185919082906001600160a01b03165afa90811561124d579061121a575b602092506000805160206124c583398151915255600160008051602061252583398151915255604051908152f35b506020823d602011611245575b8161123460209383611d47565b81010312610cec57602091516111ec565b3d9150611227565b604051903d90823e3d90fd5b6112719060203d6020116106b1576106a28183611d47565b50386111a7565b50604051903d90823e3d90fd5b6040519063f9a3dbdd60e01b82526004820152602081602481875afa908115611432578291611400575b506000805160206124858339815191525481816112ce575b505061116e565b6000805160206124e5833981519152546040516347a5051760e01b81523060048201529190602090839060249082906001600160a01b03165afa9182156113f4576000926113c0575b5015806113a8575b611385575b5060008051602061246583398151915291825490670de0b6b3a76400009081810291818304149015171561136f576113659261135f916120b2565b90611d69565b90553880806112c7565b634e487b7160e01b600052601160045260246000fd5b6113a19192506000805160206124c58339815191525490612092565b9038611324565b506000805160206124c583398151915254811161131f565b90916020823d6020116113ec575b816113db60209383611d47565b810103126101905750519038611317565b3d91506113ce565b6040513d6000823e3d90fd5b90506020813d60201161142a575b8161141b60209383611d47565b81010312610cec5751386112af565b3d915061140e565b6040513d84823e3d90fd5b60018060a01b037f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8343541660405180606081011067ffffffffffffffff606083011117611633576060810160405260028152604036602083013760018060a01b036000805160206124e583398151915254168151156115dd5760208201526040516315ab88c960e31b8152602081600481865afa908115610d205785916115f1575b508151600110156115dd576001600160a01b0390811660408301527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83425416823b156115d957929091849260405194859363791ac94760e01b855260a4850190600486015285602486015260a060448601528251809152602060c48601930190865b8181106115b4575050508380928692606483015242608483015203925af1801561143257156111665767ffffffffffffffff81116115a05760405238611166565b634e487b7160e01b82526041600452602482fd5b82516001600160a01b031685528997508896506020948501949092019160010161155f565b8480fd5b634e487b7160e01b85526032600452602485fd5b90506020813d60201161162b575b8161160c60209383611d47565b810103126115d957516001600160a01b03811681036115d957386114de565b3d91506115ff565b634e487b7160e01b84526041600452602484fd5b94509450905061271061167b7f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8350548561209f565b04927f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf835554936127106116ad868361209f565b049461271081810311610fd35760026116e361115694610d3c6127106116da8b999760019783039061209f565b04978892612092565b9792935050611124565b90506020813d602011611717575b8161170860209383611d47565b810103126103095751386110e9565b3d91506116fb565b604051630140fc5360e41b8152600490fd5b60405163012c9a8b60e61b8152600490fd5b503461019057602080600319360112610309576117616101b1611c80565b91604051809384918482549182815201918452848420935b8582821061179057505050610ae592500383611d47565b8554845260019586019588955093019201611779565b5034610190576060366003190112610190576103b5611c80565b50346101905760203660031901126101905760806117df6004356123d5565b6107b960405180926060908051835260208101516020840152604081015160408401528160018060a01b0391015116910152565b5034610190578060031936011261019057602060008051602061248583398151915254604051908152f35b50346101905760403660031901126101905760043560249081359060ff60008051602061244583398151915254166104fb57600080516020612525833981519152916002835414610d7a5760028355807f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834c547f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834b5491828110611c4a578110611c42575b6118ea33611f28565b808310611b1157505081905b7f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834a9283549260018401809411611afe5790839291889486556119d86040519661193e88611cf9565b4288526005602098899687820190878252604083018781526060840191825260808401928c845260a085019b338d528d527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834d8b5260408d20945185555160018501555160028401555160038301555160048201550160018060a01b03809751166001600160601b0360a01b825416179055610f7b33611daf565b6119e581610f6233611de8565b6119ee33611de8565b55611a09600080516020612485833981519152918254611d69565b905560648360008051602061250583398151915254169160405195869384926323b872dd60e01b8452336004850152308c85015260448401525af1918215611af3578392611ad6575b506000805160206124e58339815191525416604051948580926347a5051760e01b82523060048301525afa908115610cf8578491611aa35750600192506000805160206124c5833981519152555580f35b905082813d8311611acf575b611ab98183611d47565b81010312611acb576001915138610cab565b8280fd5b503d611aaf565b611aec90833d85116106b1576106a28183611d47565b5038611a52565b6040513d88823e3d90fd5b634e487b7160e01b885260116004528688fd5b81611b1b916120fe565b611b2582846120fe565b6123289080820291820503611afe5781611b3e91612129565b806103e8019160019183128216611c2f5792906202a3008405611b6081612117565b94611b6a82612160565b935b828512611b98575050505050611b8b611b919161271080940590612144565b8461209f565b04906118f6565b909192939562015180808802908882051488151715611c1c5783611bd0611bcb85611bc6611bd5958e612144565b6120fe565b612117565b612129565b6101f48d8282039212818312811691831390151617611c1c578591611c02918e811315611c0d57906120fe565b960193929190611b6c565b611c1690612160565b906120fe565b634e487b7160e01b8d5260116004528b8dfd5b634e487b7160e01b895260116004528789fd5b9150816118e1565b60405163d290862b60e01b8152600490fd5b5034610190576020366003190112610190576020610a8f611c7b611c80565b611d76565b600435906001600160a01b0382168203610cec57565b602435906001600160a01b0382168203610cec57565b34610cec576040366003190112610cec576103be611c80565b90815180825260208080930193019160005b828110611ce5575050505090565b835185529381019392810192600101611cd7565b60c0810190811067ffffffffffffffff821117611d1557604052565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff821117611d1557604052565b90601f8019910116810190811067ffffffffffffffff821117611d1557604052565b9190820180921161136f57565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83486020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834e6020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83446020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83536020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83546020526040902090565b6001600160a01b031660009081527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83476020526040902090565b80549068010000000000000000821015611d155760018201808255821015611efa5760005260206000200155565b634e487b7160e01b600052603260045260246000fd5b90816020910312610cec57518015158103610cec5790565b60006000805160206124858339815191525480611fa8575b5050611fa5611f4e82611d76565b54611f94611f5b84611de8565b5491670de0b6b3a7640000611f8d60008051602061246583398151915294611f878654610e928a611e93565b9061209f565b0490611d69565b611f9d84611d76565b555491611e93565b55565b6000805160206124e5833981519152546040516347a5051760e01b815230600482015290602090829060249082906001600160a01b03165afa9081156106b8578391612061575b506000805160206124c5833981519152549081811161204e575b505060008051602061246583398151915291825490670de0b6b3a76400009081810291818304149015171561136f576120459261135f916120b2565b90553880611f40565b612059929350612092565b903880612009565b90506020813d821161208a575b8161207b60209383611d47565b81010312611acb575138611fef565b3d915061206e565b9190820391821161136f57565b8181029291811591840414171561136f57565b81156120bc570490565b634e487b7160e01b600052601260045260246000fd5b67ffffffffffffffff8111611d155760051b60200190565b8051821015611efa5760209160051b010190565b8181039291600013801582851316918412161761136f57565b906103e8918083029283050361136f57565b81156120bc57600160ff1b811460001983141661136f570590565b9190916000838201938412911290801582169115161761136f57565b600160ff1b811461136f5760000390565b600080516020612485833981519152548061218d575050600090565b6000805160206124e5833981519152546040516347a5051760e01b81523060048201526001600160a01b039091169260209290918381602481885afa80156113f4576000906122bd575b6121f291506000805160206124c58339815191525490612092565b9160008051602061246583398151915254670de0b6b3a7640000938481029080820486149015171561136f578594612237610e929361135f6122629761225c956120b2565b90611f8d61224486611de8565b54611f8761225188611d76565b5494610e9289611e93565b91611e5a565b602460405180958193634ab4948560e11b835260048301525afa9081156113f457600091612291575b50905090565b82813d83116122b6575b6122a58183611d47565b81010312610190575051803861228b565b503d61229b565b8482813d83116122e5575b6122d28183611d47565b8101031261019057506121f290516121d7565b503d6122c8565b604051906122f982611cf9565b8160a06000918281528260208201528260408201528260608201528260808201520152565b600019811461136f5760010190565b6040519061233a82611d2b565b60006060838281528260208201528260408201520152565b61235a6122ec565b506000527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834d60205260406000206040519061239482611cf9565b8054825260018101546020830152600281015460408301526003810154606083015260048101546080830152600501546001600160a01b031660a082015290565b6123dd61232d565b506000527f057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf835260205260406000206040519061241782611d2b565b805482526001810154602083015260028101546040830152600301546001600160a01b031660608201529056fe68721c0bbf2c02a4d65000340d1370666be06a630022208d4baa9bd7a4b6fea8057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8346057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf83458a22373512790c48b83a1fe2efdd2888d4a917bcdc24d0adf63e60f671680460057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8349057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf8341057357a05192c6b7de2725f3cf4f1cda28e9d1d2e8a05c4f84cf59721cdf834009acf4e54214992e70883cf7dcd6957ff2c71cd9e14df4bec4383bc0d11607dca26469706673582212204dfe8470f1ce1730d0f3c5abc819398858ab4f5ff7eeab59f64049a86b844c2a64736f6c63430008130033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.