More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 3,328,322 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Emergency Withdr... | 14167130 | 22 days ago | IN | 0 ETH | 0 | ||||
Nullify Battle | 14163009 | 22 days ago | IN | 0 ETH | 0 | ||||
Nullify Battle | 14162034 | 22 days ago | IN | 0 ETH | 0 | ||||
Nullify Battle | 14161962 | 22 days ago | IN | 0 ETH | 0 | ||||
Nullify Battle | 14161923 | 22 days ago | IN | 0 ETH | 0 | ||||
Nullify Battle | 14161918 | 22 days ago | IN | 0 ETH | 0 | ||||
Nullify Battle | 14160649 | 22 days ago | IN | 0 ETH | 0 | ||||
Claim Proceeds | 14160525 | 22 days ago | IN | 0.0006 ETH | 0.00000013 | ||||
Nullify Battle | 14160259 | 22 days ago | IN | 0 ETH | 0 | ||||
Nullify Battle | 14160243 | 22 days ago | IN | 0 ETH | 0 | ||||
Claim Proceeds | 14160196 | 22 days ago | IN | 0.00012 ETH | 0 | ||||
Claim Proceeds | 14160141 | 22 days ago | IN | 0.00006 ETH | 0.00000013 | ||||
Nullify Battle | 14160132 | 22 days ago | IN | 0 ETH | 0.00000008 | ||||
Nullify Battle | 14160127 | 22 days ago | IN | 0 ETH | 0 | ||||
Nullify Battle | 14160126 | 22 days ago | IN | 0 ETH | 0.00000008 | ||||
Withdraw Stake | 14160118 | 22 days ago | IN | 0 ETH | 0.00000013 | ||||
Claim Proceeds | 14160000 | 22 days ago | IN | 0.003 ETH | 0.00000012 | ||||
Claim Proceeds | 14159992 | 22 days ago | IN | 0.027 ETH | 0 | ||||
Claim Proceeds | 14159978 | 22 days ago | IN | 0.0006 ETH | 0.00000013 | ||||
Claim Proceeds | 14159970 | 22 days ago | IN | 0.00006 ETH | 0.00000013 | ||||
Nullify Battle | 14159968 | 22 days ago | IN | 0 ETH | 0 | ||||
Claim Proceeds | 14159952 | 22 days ago | IN | 0.0003 ETH | 0.00000012 | ||||
Nullify Battle | 14159951 | 22 days ago | IN | 0 ETH | 0 | ||||
Join Battle | 14159944 | 22 days ago | IN | 0.01 ETH | 0.00000027 | ||||
Init Battle | 14159940 | 22 days ago | IN | 0.01 ETH | 0.00000024 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
14167130 | 22 days ago | 2.30148 ETH | ||||
14159944 | 22 days ago | 0.01 ETH | ||||
14159940 | 22 days ago | 0.01 ETH | ||||
14159934 | 22 days ago | 0.001 ETH | ||||
14159923 | 22 days ago | 0.005 ETH | ||||
14159918 | 22 days ago | 0.005 ETH | ||||
14159918 | 22 days ago | 0.001 ETH | ||||
14159905 | 22 days ago | 0.04 ETH | ||||
14159899 | 22 days ago | 0.04 ETH | ||||
14159898 | 22 days ago | 0.002 ETH | ||||
14159897 | 22 days ago | 0.03 ETH | ||||
14159894 | 22 days ago | 0.001 ETH | ||||
14159892 | 22 days ago | 0.03 ETH | ||||
14159891 | 22 days ago | 0.01 ETH | ||||
14159891 | 22 days ago | 0.001 ETH | ||||
14159887 | 22 days ago | 0.005 ETH | ||||
14159885 | 22 days ago | 0.01 ETH | ||||
14159883 | 22 days ago | 0.005 ETH | ||||
14159883 | 22 days ago | 0.01 ETH | ||||
14159882 | 22 days ago | 0.001 ETH | ||||
14159880 | 22 days ago | 0.01 ETH | ||||
14159878 | 22 days ago | 0.001 ETH | ||||
14159863 | 22 days ago | 0.002 ETH | ||||
14159861 | 22 days ago | 0.001 ETH | ||||
14159861 | 22 days ago | 0.1 ETH |
Loading...
Loading
Contract Name:
BlastDuelArenaBattle
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 10000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED /** * /*** * * ,- _~. ,, * (' /| _ || ' _ * (( || < \, \\/\\/\\ ||/|, ,._-_ \\ < \, * (( || /-|| || || || || || || || /-|| * ( / | (( || || || || || |' || || (( || * -____- \/\\ \\ \\ \\ \\/ \\, \\ \/\\ * * ___ * -_____ ,, - -_, * ' | -, || ( ~/|| _ * /| | |` \\ \\ _-_ || ( / || ,._-_ _-_ \\/\\ < \, * || |==|| || || || \\ || \/==|| || || \\ || || /-|| * ~|| | |, || || ||/ || /_ _|| || ||/ || || (( || * ~-____, \\/\\ \\,/ \\ ( - \\, \\, \\,/ \\ \\ \/\\ * ( * * @title Cambria Blast Duel Arena * @notice See cambria.gg for more details. * @notice Modified for Blast * @author will [at] cambria dot gg * @notice questions, concerns, vulns to security [at] cambria.gg */ pragma solidity 0.8.18; import "openzeppelin-contracts/access/Ownable.sol"; import "openzeppelin-contracts/security/ReentrancyGuard.sol"; import "openzeppelin-contracts/utils/cryptography/ECDSA.sol"; import "openzeppelin-contracts/utils/cryptography/EIP712.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { ERC721 } from "solady/tokens/ERC721.sol"; import "openzeppelin-contracts/token/ERC721/utils/ERC721Holder.sol"; import "./IBatchBattle.sol"; import "./BlastDuelArenaEscrow.sol"; error BattleNotInitialized(); error BattleNotMatched(); error BattleAlreadyMatched(); error BattleAlreadyFinished(); error BattleAlreadyClaimed(); error BattleAlreadyNullified(); error BattleSelfForbidden(); error OnlyInitiatorCanNullify(); error ForgedSignature(); error ForgedWithdrawSignature(); error StakeAlreadyWithdrawn(); error NotAllowedParticipant(); error ClaimFromNonParticipant(); error UserAlreadyWithdrawn(); error WithdrawFromNonParticipant(); error UniqueJudge(); error TransferFailed(); error FeeTooLow(); error EthFeeNumerTooHigh(); error EthStakeMustMatchMsgValue(); error EthStakeNotUnique(); error ExistingStakes(); error MustHaveStake(); error ExceedsMaximumUniqueStakes(); contract BlastDuelArenaBattle is IBatchBattle, ReentrancyGuard, Ownable, ERC721Holder, EIP712 { using ECDSA for bytes32; BlastDuelArenaEscrow immutable escrow; address public immutable escrowAddr; address public judge; address public withdrawJudge; uint256 public nextBattleId; uint256 public withdrawFee; uint256 public ethFeeNumer; event BattleInitialized( uint256 indexed battleId, address indexed playerOne, address indexed playerTwo, uint256[] assetEnum, address[] contractAddr, uint256[] amtOrTokenId ); event BattleJoined( uint256 indexed battleId, address indexed playerOne, address indexed playerTwo, uint256[] assetEnum, address[] contractAddr, uint256[] amtOrTokenId ); event BattleWon(uint256 indexed battleId, address indexed winner); event BattleNullified(uint256 indexed battleId, address indexed caller, address indexed counterparty); event BattleCanceled(uint256 indexed battleId, address indexed caller); event JudgeChanged(address indexed newJudge); event WithdrawJudgeChanged(address indexed newWithdrawJudge); event FeeChanged(uint256 indexed feeChanged); event EthFeeNumerChanged(uint256 indexed ethFeeNumer); mapping(uint256 => Battle) public battles; IBlast public constant BLAST = IBlast(0x4300000000000000000000000000000000000002); constructor(address _owner, address _judge, address _withdrawJudge) EIP712("CambriaDuelArena", "1") { if (_owner == address(0) || _judge == address(0) || _withdrawJudge == address(0)) { revert ZeroAddressNotAllowed(); } escrow = new BlastDuelArenaEscrow(_owner); escrowAddr = address(escrow); judge = _judge; withdrawJudge = _withdrawJudge; // Blast Specific BLAST.configureClaimableYield(); BLAST.configureClaimableGas(); BLAST.configureGovernor(_owner); // End Blast Specific _transferOwnership(_owner); } function changeJudge(address newJudge) external onlyOwner { if (newJudge == address(0)) revert ZeroAddressNotAllowed(); if (newJudge == withdrawJudge) revert UniqueJudge(); judge = newJudge; emit JudgeChanged(newJudge); } function changeWithdrawJudge(address newWithdrawJudge) external onlyOwner { if (newWithdrawJudge == address(0)) revert ZeroAddressNotAllowed(); if (newWithdrawJudge == judge) revert UniqueJudge(); withdrawJudge = newWithdrawJudge; emit WithdrawJudgeChanged(newWithdrawJudge); } function changeFee(uint256 fee) external onlyOwner { withdrawFee = fee; emit FeeChanged(fee); } function _ethFeeDenom() internal pure returns (uint256) { return 10_000; } function changeEthFeeNumer(uint256 feeNumer) external onlyOwner { if (feeNumer >= _ethFeeDenom()) revert EthFeeNumerTooHigh(); ethFeeNumer = feeNumer; emit EthFeeNumerChanged(feeNumer); } function emergencyWithdraw(address payable payee) external onlyOwner nonReentrant { if (payee == address(0)) { revert ZeroAddressNotAllowed(); } uint256 balance = address(this).balance; (bool transferTx,) = payee.call{ value: balance }(""); if (!transferTx) { revert TransferFailed(); } } function emergencyWithdrawERC20(address payable payee, address token) external onlyOwner nonReentrant { if (payee == address(0)) { revert ZeroAddressNotAllowed(); } ERC20 tokenContract = ERC20(token); uint256 balance = tokenContract.balanceOf(address(this)); SafeTransferLib.safeTransfer(address(tokenContract), payee, balance); } function emergencyWithdrawERC721( address payable payee, address nft, uint256 tokenId ) external onlyOwner nonReentrant { if (payee == address(0)) { revert ZeroAddressNotAllowed(); } ERC721 nftContract = ERC721(nft); nftContract.safeTransferFrom(address(this), payee, tokenId); } function emergencyRefund(uint256 battleId) external battleExists(battleId) onlyOwner nonReentrant { Battle storage selectedBattle = battles[battleId]; if (!selectedBattle.claimed) { selectedBattle.claimed = true; battles[battleId] = selectedBattle; escrow.withdraw(selectedBattle.one.user, payable(selectedBattle.one.user), battleId); escrow.withdraw(selectedBattle.two.user, payable(selectedBattle.two.user), battleId); } } modifier battleExists(uint256 battleId) { require(battleId < nextBattleId, "Battle must exist!"); _; } function getBattle(uint256 battleId) external view battleExists(battleId) returns (Battle memory) { Battle memory btl = battles[battleId]; return btl; } function initBattle( address challenging, BatchStake[] calldata stakes ) external payable nonReentrant returns (uint256) { uint256 numStakes = stakes.length; if (numStakes <= 0) revert MustHaveStake(); if (numStakes > 8) revert ExceedsMaximumUniqueStakes(); if (msg.sender == challenging) revert BattleSelfForbidden(); uint256 ethValue = msg.value; uint256 battleId = nextBattleId; nextBattleId++; bool ethFlag = false; battles[battleId].one.user = msg.sender; BatchStake[] storage _stakes = battles[battleId].one.stakes; if (_stakes.length > 0) { revert ExistingStakes(); } for (uint256 i = 0; i < numStakes; i++) { _stakes.push(stakes[i]); } battles[battleId].one.stakes = _stakes; battles[battleId].two.user = challenging; battles[battleId].value = ethValue; for (uint256 i = 0; i < numStakes; i++) { if (stakes[i].asset == AssetType.ETH) { if (ethValue != stakes[i].amtOrTokenId) { revert EthStakeMustMatchMsgValue(); } if (ethFlag) { revert EthStakeNotUnique(); } ethFlag = true; } else if (stakes[i].asset == AssetType.TOKEN) { ERC20 token = ERC20(stakes[i].contractAddr); // transfers token to this contract SafeTransferLib.safeTransferFrom(address(token), msg.sender, address(this), stakes[i].amtOrTokenId); // approves transfer to escrow SafeTransferLib.safeApprove(address(token), escrowAddr, stakes[i].amtOrTokenId); } else if (stakes[i].asset == AssetType.NFT) { ERC721 nft = ERC721(stakes[i].contractAddr); nft.safeTransferFrom(msg.sender, address(this), stakes[i].amtOrTokenId); nft.approve(escrowAddr, stakes[i].amtOrTokenId); } } (uint256[] memory assets, address[] memory contractAddrs, uint256[] memory amtOrTokenIds) = escrow.deposit{ value: ethValue }(msg.sender, battleId, stakes); emit BattleInitialized(battleId, msg.sender, challenging, assets, contractAddrs, amtOrTokenIds); return battleId; } function nullifyBattle(uint256 battleId) external payable battleExists(battleId) nonReentrant { Battle storage selectedBattle = battles[battleId]; if (selectedBattle.matched) { revert BattleAlreadyMatched(); } else if (selectedBattle.nullified) { revert BattleAlreadyNullified(); } else if (selectedBattle.one.user != msg.sender) { revert OnlyInitiatorCanNullify(); } selectedBattle.nullified = true; emit BattleNullified(battleId, msg.sender, selectedBattle.two.user); escrow.withdraw(selectedBattle.one.user, payable(msg.sender), battleId); } function joinBattle( uint256 battleId, BatchStake[] calldata stakes ) external payable battleExists(battleId) nonReentrant { uint256 numStakes = stakes.length; if (numStakes <= 0) revert MustHaveStake(); if (numStakes > 8) revert ExceedsMaximumUniqueStakes(); uint256 ethValue = msg.value; bool ethFlag = false; Battle storage selectedBattle = battles[battleId]; if (selectedBattle.matched) { revert BattleAlreadyMatched(); } else if (selectedBattle.nullified) { revert BattleAlreadyNullified(); } else if (selectedBattle.two.user != msg.sender) { revert NotAllowedParticipant(); } else { BatchStake[] storage _stakes = battles[battleId].two.stakes; if (_stakes.length > 0) { revert ExistingStakes(); } for (uint256 i = 0; i < numStakes; i++) { _stakes.push(stakes[i]); } battles[battleId].two.stakes = _stakes; battles[battleId].matched = true; battles[battleId].value += ethValue; for (uint256 i = 0; i < numStakes; i++) { if (stakes[i].asset == AssetType.ETH) { if (ethValue != stakes[i].amtOrTokenId) { revert EthStakeMustMatchMsgValue(); } if (ethFlag) { revert EthStakeNotUnique(); } ethFlag = true; } else if (stakes[i].asset == AssetType.TOKEN) { ERC20 token = ERC20(stakes[i].contractAddr); // transfers token to this contract SafeTransferLib.safeTransferFrom(address(token), msg.sender, address(this), stakes[i].amtOrTokenId); // approves transfer to escrow SafeTransferLib.safeApprove(address(token), escrowAddr, stakes[i].amtOrTokenId); } else if (stakes[i].asset == AssetType.NFT) { ERC721 nft = ERC721(stakes[i].contractAddr); nft.safeTransferFrom(msg.sender, address(this), stakes[i].amtOrTokenId); nft.approve(escrowAddr, stakes[i].amtOrTokenId); } } (uint256[] memory assets, address[] memory contractAddrs, uint256[] memory amtOrTokenIds) = escrow.deposit{ value: ethValue }(msg.sender, battleId, stakes); emit BattleJoined(battleId, selectedBattle.one.user, msg.sender, assets, contractAddrs, amtOrTokenIds); } } function calcEthFee(uint256 battleId) public view battleExists(battleId) returns (uint256) { uint256 ethVal = battles[battleId].value; if (ethFeeNumer <= 0) return 0; return (ethVal * ethFeeNumer) / _ethFeeDenom(); } function claimProceeds( uint256 battleId, bytes memory signature ) external payable nonReentrant battleExists(battleId) { if (msg.value < withdrawFee) { revert FeeTooLow(); } if (msg.value < calcEthFee(battleId)) { revert FeeTooLow(); } if (battles[battleId].nullified) { revert BattleAlreadyNullified(); } if (!battles[battleId].matched) { revert BattleNotMatched(); } if (battles[battleId].claimed) { revert BattleAlreadyClaimed(); } if (battles[battleId].one.hasWithdrawn || battles[battleId].two.hasWithdrawn) { revert UserAlreadyWithdrawn(); } address signer = ECDSA.recover(getClaimTypedDataHash(Claim({ battleId: battleId, account: msg.sender })), signature); if (signer != judge) { revert ForgedSignature(); } else { Battle storage selectedBattle = battles[battleId]; if (msg.sender == selectedBattle.one.user) { selectedBattle.one.isWinner = true; } else if (msg.sender == selectedBattle.two.user) { selectedBattle.two.isWinner = true; } else { revert ClaimFromNonParticipant(); } selectedBattle.claimed = true; battles[battleId] = selectedBattle; emit BattleWon(battleId, msg.sender); escrow.withdraw(selectedBattle.one.user, payable(msg.sender), battleId); escrow.withdraw(selectedBattle.two.user, payable(msg.sender), battleId); } } function claimTypeHash() internal pure returns (bytes32) { return keccak256("Claim(uint256 battleId,address account)"); } function getClaimTypedDataHash(Claim memory claim) public view returns (bytes32) { return _hashTypedDataV4(keccak256(abi.encode(claimTypeHash(), claim.battleId, claim.account))); } function withdrawStake(uint256 battleId, bytes memory signature) external nonReentrant battleExists(battleId) { Battle storage selectedBattle = battles[battleId]; if (battles[battleId].nullified) { revert BattleAlreadyNullified(); } if (!battles[battleId].matched) { revert BattleNotMatched(); } if (selectedBattle.claimed) { revert BattleAlreadyClaimed(); } if (selectedBattle.one.user == msg.sender) { if (selectedBattle.one.hasWithdrawn) { revert UserAlreadyWithdrawn(); } } else if (selectedBattle.two.user == msg.sender) { if (selectedBattle.two.hasWithdrawn) { revert UserAlreadyWithdrawn(); } } else { revert WithdrawFromNonParticipant(); } address signer = ECDSA.recover(getClaimTypedDataHash(Claim({ battleId: battleId, account: msg.sender })), signature); if (signer != withdrawJudge) { revert ForgedWithdrawSignature(); } else { selectedBattle.one.hasWithdrawn = true; selectedBattle.two.hasWithdrawn = true; battles[battleId] = selectedBattle; emit BattleCanceled(battleId, msg.sender); escrow.withdraw(selectedBattle.one.user, payable(selectedBattle.one.user), battleId); escrow.withdraw(selectedBattle.two.user, payable(selectedBattle.two.user), battleId); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "./ECDSA.sol"; import "../ShortStrings.sol"; import "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ * * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _name.toStringWithFallback(_nameFallback), _version.toStringWithFallback(_versionFallback), block.chainid, address(this), bytes32(0), new uint256[](0) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// /// @dev Note: /// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection. /// - For ERC20s, this implementation won't check that a token has code, /// responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes. uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants. // // The regular variants: // - Forwards all remaining gas to the target. // - Reverts if the target reverts. // - Reverts if the current contract has insufficient balance. // // The force variants: // - Forwards with an optional gas stipend // (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases). // - If the target reverts, or if the gas stipend is exhausted, // creates a temporary contract to force send the ETH via `SELFDESTRUCT`. // Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758. // - Reverts if the current contract has insufficient balance. // // The try variants: // - Forwards with a mandatory gas stipend. // - Instead of reverting, returns whether the transfer succeeded. /// @dev Sends `amount` (in wei) ETH to `to`. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gas(), to, amount, gas(), 0x00, gas(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Sends all the ETH in the current contract to `to`. function safeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // Transfer all the ETH and check if it succeeded or not. if iszero(call(gas(), to, selfbalance(), gas(), 0x00, gas(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(gasStipend, to, amount, gas(), 0x00, gas(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { returndatacopy(gas(), returndatasize(), shr(20, gas())) // For gas estimation. } } } } /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`. function forceSafeTransferAllETH(address to, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gasStipend, to, selfbalance(), gas(), 0x00, gas(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { returndatacopy(gas(), returndatasize(), shr(20, gas())) // For gas estimation. } } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, gas(), 0x00, gas(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { returndatacopy(gas(), returndatasize(), shr(20, gas())) // For gas estimation. } } } } /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), gas(), 0x00, gas(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { returndatacopy(gas(), returndatasize(), shr(20, gas())) // For gas estimation. } } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, amount, gas(), 0x00, gas(), 0x00) } } /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`. function trySafeTransferAllETH(address to, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, selfbalance(), gas(), 0x00, gas(), 0x00) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have their entire balance approved for /// the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`. amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x14, to) // Store the `to` argument. amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// If the initial attempt to approve fails, attempts to reset the approved amount to zero, /// then retries the approval again (some tokens, e.g. USDT, requires this). /// Reverts upon failure. function safeApproveWithRetry(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, retrying upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x34, 0) // Store 0 for the `amount`. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00)) // Reset the approval. mstore(0x34, amount) // Store back the original `amount`. // Retry the approval, reverting upon failure. if iszero( and( or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x14, account) // Store the `account` argument. mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`. amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20) ) ) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC721 implementation with storage hitchhiking. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol) /// /// @dev Note: /// - The ERC721 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - For performance, methods are made payable where permitted by the ERC721 standard. /// - The `safeTransfer` functions use the identity precompile (0x4) /// to copy memory internally. /// /// If you are overriding: /// - NEVER violate the ERC721 invariant: /// the balance of an owner MUST be always be equal to their number of ownership slots. /// The transfer functions do not have an underflow guard for user token balances. /// - Make sure all variables written to storage are properly cleaned // (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood). /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC721 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev An account can hold up to 4294967295 tokens. uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Only the token owner or an approved account can manage the token. error NotOwnerNorApproved(); /// @dev The token does not exist. error TokenDoesNotExist(); /// @dev The token already exists. error TokenAlreadyExists(); /// @dev Cannot query the balance for the zero address. error BalanceQueryForZeroAddress(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The token must be owned by `from`. error TransferFromIncorrectOwner(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC721Receiver interface. error TransferToNonERC721ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when token `id` is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 indexed id); /// @dev Emitted when `owner` enables `account` to manage the `id` token. event Approval(address indexed owner, address indexed account, uint256 indexed id); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership data slot of `id` is given by: /// ``` /// mstore(0x00, id) /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) /// ``` /// Bits Layout: /// - [0..159] `addr` /// - [160..255] `extraData` /// /// The approved address slot is given by: `add(1, ownershipSlot)`. /// /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip /// /// The balance slot of `owner` is given by: /// ``` /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x1c) /// ``` /// Bits Layout: /// - [0..31] `balance` /// - [32..255] `aux` /// /// The `operator` approval slot of `owner` is given by: /// ``` /// mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) /// mstore(0x00, owner) /// let operatorApprovalSlot := keccak256(0x0c, 0x30) /// ``` uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192; /// @dev Pre-shifted and pre-masked constant. uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the token collection name. function name() public view virtual returns (string memory); /// @dev Returns the token collection symbol. function symbol() public view virtual returns (string memory); /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. function tokenURI(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of token `id`. /// /// Requirements: /// - Token `id` must exist. function ownerOf(uint256 id) public view virtual returns (address result) { result = _ownerOf(id); /// @solidity memory-safe-assembly assembly { if iszero(result) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } } } /// @dev Returns the number of tokens owned by `owner`. /// /// Requirements: /// - `owner` must not be the zero address. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Revert if the `owner` is the zero address. if iszero(owner) { mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`. revert(0x1c, 0x04) } mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE) } } /// @dev Returns the account approved to manage token `id`. /// /// Requirements: /// - Token `id` must exist. function getApproved(uint256 id) public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) if iszero(shl(96, sload(ownershipSlot))) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } result := sload(add(1, ownershipSlot)) } } /// @dev Sets `account` as the approved account to manage token `id`. /// /// Requirements: /// - Token `id` must exist. /// - The caller must be the owner of the token, /// or an approved operator for the token owner. /// /// Emits an {Approval} event. function approve(address account, uint256 id) public payable virtual { _approve(msg.sender, account, id); } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x30)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits an {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) log3( 0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)) ) } } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 id) public payable virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller())) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // Revert if the caller is not the owner, nor approved. if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`. function safeTransferFrom(address from, address to, uint256 id) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function safeTransferFrom(address from, address to, uint256 id, bytes calldata data) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL QUERY FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if token `id` exists. function _exists(uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))) } } /// @dev Returns the owner of token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _ownerOf(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL DATA HITCHHIKING FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, no events are emitted for the hitchhiking setters. // Please emit your own events if required. /// @dev Returns the auxiliary data for `owner`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _getAux(address owner) internal view virtual returns (uint224 result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := shr(32, sload(keccak256(0x0c, 0x1c))) } } /// @dev Set the auxiliary data for `owner` to `value`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _setAux(address owner, uint224 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) let balanceSlot := keccak256(0x0c, 0x1c) let packed := sload(balanceSlot) sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed))))) } } /// @dev Returns the extra data for token `id`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _getExtraData(uint256 id) internal view virtual returns (uint96 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Sets the extra data for token `id` to `value`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _setExtraData(uint256 id, uint96 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let packed := sload(ownershipSlot) sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id) internal virtual { _beforeTokenTransfer(address(0), to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load the ownership data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Revert if the token already exists. if shl(96, ownershipPacked) { mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`. revert(0x1c, 0x04) } // Update with the owner. sstore(ownershipSlot, or(ownershipPacked, to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id) } _afterTokenTransfer(address(0), to, id); } /// @dev Equivalent to `_safeMint(to, id, "")`. function _safeMint(address to, uint256 id) internal virtual { _safeMint(to, id, ""); } /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeMint(address to, uint256 id, bytes memory data) internal virtual { _mint(to, id); if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), id)`. function _burn(uint256 id) internal virtual { _burn(address(0), id); } /// @dev Destroys token `id`, using `by`. /// /// Requirements: /// /// - Token `id` must exist. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _burn(address by, uint256 id) internal virtual { address owner = ownerOf(id); _beforeTokenTransfer(owner, address(0), id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Reload the owner in case it is changed in `_beforeTokenTransfer`. owner := shr(96, shl(96, ownershipPacked)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Load and check the token approval. { mstore(0x00, owner) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Clear the owner. sstore(ownershipSlot, xor(ownershipPacked, owner)) // Decrement the balance of `owner`. { let balanceSlot := keccak256(0x0c, 0x1c) sstore(balanceSlot, sub(sload(balanceSlot), 1)) } // Emit the {Transfer} event. log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id) } _afterTokenTransfer(owner, address(0), id); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it. /// /// Requirements: /// - Token `id` must exist. function _isApprovedOrOwner(address account, uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 // Clear the upper 96 bits. account := shr(96, shl(96, account)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := shr(96, shl(96, sload(ownershipSlot))) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Check if `account` is the `owner`. if iszero(eq(account, owner)) { mstore(0x00, owner) // Check if `account` is approved to manage the token. if iszero(sload(keccak256(0x0c, 0x30))) { result := eq(account, sload(add(1, ownershipSlot))) } } } } /// @dev Returns the account approved to manage token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _getApproved(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Equivalent to `_approve(address(0), account, id)`. function _approve(address account, uint256 id) internal virtual { _approve(address(0), account, id); } /// @dev Sets `account` as the approved account to manage token `id`, using `by`. /// /// Requirements: /// - Token `id` must exist. /// - If `by` is not the zero address, `by` must be the owner /// or an approved operator for the token owner. /// /// Emits a {Transfer} event. function _approve(address by, address account, uint256 id) internal virtual { assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) account := and(bitmaskAddress, account) by := and(bitmaskAddress, by) // Load the owner of the token. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := and(bitmaskAddress, sload(ownershipSlot)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // If `by` is not the zero address, do the authorization check. // Revert if `by` is not the owner, nor approved. if iszero(or(iszero(by), eq(by, owner))) { mstore(0x00, owner) if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Sets `account` as the approved account to manage `id`. sstore(add(1, ownershipSlot), account) // Emit the {Approval} event. log4(0x00, 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id) } } /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits an {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) operator := shr(96, shl(96, operator)) // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) mstore(0x00, by) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_transfer(address(0), from, to, id)`. function _transfer(address from, address to, uint256 id) internal virtual { _transfer(address(0), from, to, id); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _transfer(address by, address from, address to, uint256 id) internal virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) by := and(bitmaskAddress, by) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `_safeTransfer(from, to, id, "")`. function _safeTransfer(address from, address to, uint256 id) internal virtual { _safeTransfer(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(address(0), from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`. function _safeTransfer(address by, address from, address to, uint256 id) internal virtual { _safeTransfer(by, from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address by, address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(by, from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Hook that is called before any token transfers, including minting and burning. function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {} /// @dev Hook that is called after any token transfers, including minting and burning. function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) let onERC721ReceivedSelector := 0x150b7a02 mstore(m, onERC721ReceivedSelector) mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`. mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), 0x80) let n := mload(data) mstore(add(m, 0xa0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.0; import "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: UNLICENSED // Written by will at cambria dot gg // reachout for questions / concerns / vuln reports pragma solidity 0.8.18; import "./IBatchEscrow.sol"; interface IBatchBattle is IBatchEscrow { struct BattleParticipant { bool isWinner; // 8 bits bool hasWithdrawn; // 8 bits address user; // 160 bits BatchStake[] stakes; } struct Battle { bool claimed; bool matched; bool nullified; uint256 value; BattleParticipant one; BattleParticipant two; } struct Claim { uint256 battleId; address account; } }
// SPDX-License-Identifier: UNLICENSED // Written by will [at] cambria dot gg // reachout for questions / concerns / vuln reports // Modified from OpenZeppelin Escrow (last updated v4.7.0) (utils/escrow/Escrow.sol) pragma solidity 0.8.18; import "openzeppelin-contracts/access/Ownable.sol"; import "openzeppelin-contracts/utils/Address.sol"; import { ERC20 } from "solady/tokens/ERC20.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { ERC721 } from "solady/tokens/ERC721.sol"; import "openzeppelin-contracts/token/ERC721/utils/ERC721Holder.sol"; import "./IBatchEscrow.sol"; import "./IBlast.sol"; error ZeroValueETH(); error ZeroAddressNotAllowed(); /** * @title DuelArenaEscrow * @notice Modified for Blast * Modified OpenZeppelin Escrow Contract for ETH/ERC20/ERC721 */ contract BlastDuelArenaEscrow is IBatchEscrow, Ownable, ERC721Holder { using Address for address payable; event Deposited( address indexed payee, uint256 battleId, uint256[] assetEnum, address[] contractAddr, uint256[] amtOrTokenId ); event Withdrawn( address indexed payee, uint256 battleId, uint256[] assetEnum, address[] contractAddr, uint256[] amtOrTokenId ); /* - - - - - - - - - - - - - - - - - - - | Blast Specific - - - - - - - - - - - - - - - - - - - */ IBlast public constant BLAST = IBlast(0x4300000000000000000000000000000000000002); constructor(address gov) { if (gov == address(0)) revert ZeroAddressNotAllowed(); BLAST.configureClaimableYield(); BLAST.configureClaimableGas(); BLAST.configureGovernor(gov); } /* = = = = = = = = = = = = = = = = = = = || End Blast Specific = = = = = = = = = = = = = = = = = = = */ mapping(address => mapping(uint256 => BatchStake[])) private _deposits; function depositsOf(address payee, uint256 battleId) public view returns (BatchStake[] memory) { BatchStake[] memory stakes = _deposits[payee][battleId]; return stakes; } /** * @dev Stores the sent amount as credit to be withdrawn. * @param payee The destination address of the funds. * * Emits a {Deposited} event. */ function deposit( address payee, uint256 battleId, BatchStake[] calldata stakes ) public payable onlyOwner returns (uint256[] memory, address[] memory, uint256[] memory) { uint256 numStakes = stakes.length; uint256 ethValue = msg.value; // event data uint256[] memory assets = new uint256[](numStakes); address[] memory contractAddrs = new address[](numStakes); uint256[] memory amtOrTokenIds = new uint256[](numStakes); // to avoid re-entrancy need to write state variables prior to // the action. for (uint256 i = 0; i < numStakes; i++) { assets[i] = uint256(stakes[i].asset); contractAddrs[i] = stakes[i].contractAddr; amtOrTokenIds[i] = stakes[i].amtOrTokenId; _deposits[payee][battleId].push( BatchStake({ asset: stakes[i].asset, contractAddr: stakes[i].contractAddr, amtOrTokenId: stakes[i].amtOrTokenId }) ); } for (uint256 i = 0; i < numStakes; i++) { // split depending on asset type if (stakes[i].asset == AssetType.ETH) { if (ethValue <= 0) { revert ZeroValueETH(); } } else if (stakes[i].asset == AssetType.TOKEN) { ERC20 token = ERC20(stakes[i].contractAddr); SafeTransferLib.safeTransferFrom(address(token), msg.sender, address(this), stakes[i].amtOrTokenId); } else if (stakes[i].asset == AssetType.NFT) { ERC721 nft = ERC721(stakes[i].contractAddr); nft.safeTransferFrom(msg.sender, address(this), stakes[i].amtOrTokenId); } } emit Deposited(payee, battleId, assets, contractAddrs, amtOrTokenIds); return (assets, contractAddrs, amtOrTokenIds); } /** * @dev Withdraw accumulated balance for a payee, forwarding all gas to the * recipient. * * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities. * Make sure you trust the recipient, or are either following the * checks-effects-interactions pattern or using {ReentrancyGuard}. * * @param payee The address whose funds will be withdrawn and transferred to. * * Emits a {Withdrawn} event. */ function withdraw(address payee, address payable receiver, uint256 battleId) public onlyOwner { BatchStake[] memory stakes = _deposits[payee][battleId]; uint256 numStakes = stakes.length; // event data uint256[] memory assets = new uint256[](numStakes); address[] memory contractAddrs = new address[](numStakes); uint256[] memory amtOrTokenIds = new uint256[](numStakes); for (uint256 i = 0; i < numStakes; i++) { BatchStake memory stake = _deposits[payee][battleId][i]; // split depending on asset type if (stake.asset == AssetType.ETH) { receiver.sendValue(stake.amtOrTokenId); } else if (stake.asset == AssetType.TOKEN) { ERC20 token = ERC20(stake.contractAddr); SafeTransferLib.safeTransfer(address(token), receiver, stake.amtOrTokenId); } else if (stake.asset == AssetType.NFT) { ERC721 nft = ERC721(stake.contractAddr); nft.safeTransferFrom(address(this), receiver, stake.amtOrTokenId); } assets[i] = uint256(stake.asset); contractAddrs[i] = stake.contractAddr; amtOrTokenIds[i] = stake.amtOrTokenId; } emit Withdrawn(payee, battleId, assets, contractAddrs, amtOrTokenIds); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed 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"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol) pragma solidity ^0.8.8; import "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(_FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: UNLICENSED // Written by will at cambria dot gg // reachout for questions / concerns / vuln reports pragma solidity 0.8.18; interface IBatchEscrow { enum AssetType { ETH, TOKEN, NFT } struct BatchStake { AssetType asset; // 8 bits address contractAddr; // 160 bits uint256 amtOrTokenId; // 256 bits } }
// 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 Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * 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 pragma solidity ^0.8.4; /// @notice Simple ERC20 + EIP-2612 implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol) /// /// @dev Note: /// - The ERC20 standard allows minting and transferring to and from the zero address, /// minting and transferring zero tokens, as well as self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - The `permit` function use the ecrecover precompile (0x1). /// /// If you are overriding: /// - NEVER violate the ERC20 invariant: /// the total sum of all balances must be equal to `totalSupply()`. /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC20 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The total supply has overflowed. error TotalSupplyOverflow(); /// @dev The allowance has overflowed. error AllowanceOverflow(); /// @dev The allowance has underflowed. error AllowanceUnderflow(); /// @dev Insufficient balance. error InsufficientBalance(); /// @dev Insufficient allowance. error InsufficientAllowance(); /// @dev The permit is invalid. error InvalidPermit(); /// @dev The permit has expired. error PermitExpired(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when `amount` tokens is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 amount); /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`. event Approval(address indexed owner, address indexed spender, uint256 amount); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The storage slot for the total supply. uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c; /// @dev The balance slot of `owner` is given by: /// ``` /// mstore(0x0c, _BALANCE_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x20) /// ``` uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2; /// @dev The allowance slot of (`owner`, `spender`) is given by: /// ``` /// mstore(0x20, spender) /// mstore(0x0c, _ALLOWANCE_SLOT_SEED) /// mstore(0x00, owner) /// let allowanceSlot := keccak256(0x0c, 0x34) /// ``` uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20; /// @dev The nonce slot of `owner` is given by: /// ``` /// mstore(0x0c, _NONCES_SLOT_SEED) /// mstore(0x00, owner) /// let nonceSlot := keccak256(0x0c, 0x20) /// ``` uint256 private constant _NONCES_SLOT_SEED = 0x38377508; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`. uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901; /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`. bytes32 private constant _DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; /// @dev `keccak256("1")`. bytes32 private constant _VERSION_HASH = 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6; /// @dev `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`. bytes32 private constant _PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the name of the token. function name() public view virtual returns (string memory); /// @dev Returns the symbol of the token. function symbol() public view virtual returns (string memory); /// @dev Returns the decimals places of the token. function decimals() public view virtual returns (uint8) { return 18; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the amount of tokens in existence. function totalSupply() public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { result := sload(_TOTAL_SUPPLY_SLOT) } } /// @dev Returns the amount of tokens owned by `owner`. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`. function allowance(address owner, address spender) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x34)) } } /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens. /// /// Emits a {Approval} event. function approve(address spender, uint256 amount) public virtual returns (bool) { /// @solidity memory-safe-assembly assembly { // Compute the allowance slot and store the amount. mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x34), amount) // Emit the {Approval} event. mstore(0x00, amount) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c))) } return true; } /// @dev Transfer `amount` tokens from the caller to `to`. /// /// Requirements: /// - `from` must at least have `amount`. /// /// Emits a {Transfer} event. function transfer(address to, uint256 amount) public virtual returns (bool) { _beforeTokenTransfer(msg.sender, to, amount); /// @solidity memory-safe-assembly assembly { // Compute the balance slot and load its value. mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, caller()) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Compute the balance slot of `to`. mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance of `to`. // Will not overflow because the sum of all user balances // cannot exceed the maximum uint256 value. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c))) } _afterTokenTransfer(msg.sender, to, amount); return true; } /// @dev Transfers `amount` tokens from `from` to `to`. /// /// Note: Does not update the allowance if it is the maximum uint256 value. /// /// Requirements: /// - `from` must at least have `amount`. /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) { _beforeTokenTransfer(from, to, amount); /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) // Compute the allowance slot and load its value. mstore(0x20, caller()) mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED)) let allowanceSlot := keccak256(0x0c, 0x34) let allowance_ := sload(allowanceSlot) // If the allowance is not the maximum uint256 value. if add(allowance_, 1) { // Revert if the amount to be transferred exceeds the allowance. if gt(amount, allowance_) { mstore(0x00, 0x13be252b) // `InsufficientAllowance()`. revert(0x1c, 0x04) } // Subtract and store the updated allowance. sstore(allowanceSlot, sub(allowance_, amount)) } // Compute the balance slot and load its value. mstore(0x0c, or(from_, _BALANCE_SLOT_SEED)) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Compute the balance slot of `to`. mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance of `to`. // Will not overflow because the sum of all user balances // cannot exceed the maximum uint256 value. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c))) } _afterTokenTransfer(from, to, amount); return true; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EIP-2612 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev For more performance, override to return the constant value /// of `keccak256(bytes(name()))` if `name()` will never change. function _constantNameHash() internal view virtual returns (bytes32 result) {} /// @dev Returns the current nonce for `owner`. /// This value is used to compute the signature for EIP-2612 permit. function nonces(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the nonce slot and load its value. mstore(0x0c, _NONCES_SLOT_SEED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x20)) } } /// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`, /// authorized by a signed approval by `owner`. /// /// Emits a {Approval} event. function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { bytes32 nameHash = _constantNameHash(); // We simply calculate it on-the-fly to allow for cases where the `name` may change. if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name())); /// @solidity memory-safe-assembly assembly { // Revert if the block timestamp greater than `deadline`. if gt(timestamp(), deadline) { mstore(0x00, 0x1a15a3cc) // `PermitExpired()`. revert(0x1c, 0x04) } let m := mload(0x40) // Grab the free memory pointer. // Clean the upper 96 bits. owner := shr(96, shl(96, owner)) spender := shr(96, shl(96, spender)) // Compute the nonce slot and load its value. mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX) mstore(0x00, owner) let nonceSlot := keccak256(0x0c, 0x20) let nonceValue := sload(nonceSlot) // Prepare the domain separator. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), nameHash) mstore(add(m, 0x40), _VERSION_HASH) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) mstore(0x2e, keccak256(m, 0xa0)) // Prepare the struct hash. mstore(m, _PERMIT_TYPEHASH) mstore(add(m, 0x20), owner) mstore(add(m, 0x40), spender) mstore(add(m, 0x60), value) mstore(add(m, 0x80), nonceValue) mstore(add(m, 0xa0), deadline) mstore(0x4e, keccak256(m, 0xc0)) // Prepare the ecrecover calldata. mstore(0x00, keccak256(0x2c, 0x42)) mstore(0x20, and(0xff, v)) mstore(0x40, r) mstore(0x60, s) let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20) // If the ecrecover fails, the returndatasize will be 0x00, // `owner` will be be checked if it equals the hash at 0x00, // which evaluates to false (i.e. 0), and we will revert. // If the ecrecover succeeds, the returndatasize will be 0x20, // `owner` will be compared against the returned address at 0x20. if iszero(eq(mload(returndatasize()), owner)) { mstore(0x00, 0xddafbaef) // `InvalidPermit()`. revert(0x1c, 0x04) } // Increment and store the updated nonce. sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds. // Compute the allowance slot and store the value. // The `owner` is already at slot 0x20. mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender)) sstore(keccak256(0x2c, 0x34), value) // Emit the {Approval} event. log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. } } /// @dev Returns the EIP-712 domain separator for the EIP-2612 permit. function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) { bytes32 nameHash = _constantNameHash(); // We simply calculate it on-the-fly to allow for cases where the `name` may change. if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name())); /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Grab the free memory pointer. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), nameHash) mstore(add(m, 0x40), _VERSION_HASH) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) result := keccak256(m, 0xa0) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints `amount` tokens to `to`, increasing the total supply. /// /// Emits a {Transfer} event. function _mint(address to, uint256 amount) internal virtual { _beforeTokenTransfer(address(0), to, amount); /// @solidity memory-safe-assembly assembly { let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT) let totalSupplyAfter := add(totalSupplyBefore, amount) // Revert if the total supply overflows. if lt(totalSupplyAfter, totalSupplyBefore) { mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`. revert(0x1c, 0x04) } // Store the updated total supply. sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter) // Compute the balance slot and load its value. mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c))) } _afterTokenTransfer(address(0), to, amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Burns `amount` tokens from `from`, reducing the total supply. /// /// Emits a {Transfer} event. function _burn(address from, uint256 amount) internal virtual { _beforeTokenTransfer(from, address(0), amount); /// @solidity memory-safe-assembly assembly { // Compute the balance slot and load its value. mstore(0x0c, _BALANCE_SLOT_SEED) mstore(0x00, from) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Subtract and store the updated total supply. sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount)) // Emit the {Transfer} event. mstore(0x00, amount) log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0) } _afterTokenTransfer(from, address(0), amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Moves `amount` of tokens from `from` to `to`. function _transfer(address from, address to, uint256 amount) internal virtual { _beforeTokenTransfer(from, to, amount); /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) // Compute the balance slot and load its value. mstore(0x0c, or(from_, _BALANCE_SLOT_SEED)) let fromBalanceSlot := keccak256(0x0c, 0x20) let fromBalance := sload(fromBalanceSlot) // Revert if insufficient balance. if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } // Subtract and store the updated balance. sstore(fromBalanceSlot, sub(fromBalance, amount)) // Compute the balance slot of `to`. mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x20) // Add and store the updated balance of `to`. // Will not overflow because the sum of all user balances // cannot exceed the maximum uint256 value. sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) // Emit the {Transfer} event. mstore(0x20, amount) log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c))) } _afterTokenTransfer(from, to, amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL ALLOWANCE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Updates the allowance of `owner` for `spender` based on spent `amount`. function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { /// @solidity memory-safe-assembly assembly { // Compute the allowance slot and load its value. mstore(0x20, spender) mstore(0x0c, _ALLOWANCE_SLOT_SEED) mstore(0x00, owner) let allowanceSlot := keccak256(0x0c, 0x34) let allowance_ := sload(allowanceSlot) // If the allowance is not the maximum uint256 value. if add(allowance_, 1) { // Revert if the amount to be transferred exceeds the allowance. if gt(amount, allowance_) { mstore(0x00, 0x13be252b) // `InsufficientAllowance()`. revert(0x1c, 0x04) } // Subtract and store the updated allowance. sstore(allowanceSlot, sub(allowance_, amount)) } } } /// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`. /// /// Emits a {Approval} event. function _approve(address owner, address spender, uint256 amount) internal virtual { /// @solidity memory-safe-assembly assembly { let owner_ := shl(96, owner) // Compute the allowance slot and store the amount. mstore(0x20, spender) mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED)) sstore(keccak256(0x0c, 0x34), amount) // Emit the {Approval} event. mstore(0x00, amount) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS TO OVERRIDE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Hook that is called before any transfer of tokens. /// This includes minting and burning. function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /// @dev Hook that is called after any transfer of tokens. /// This includes minting and burning. function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; enum YieldMode { AUTOMATIC, VOID, CLAIMABLE } enum GasMode { VOID, CLAIMABLE } interface IBlast { // configure function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external; function configure(YieldMode _yield, GasMode gasMode, address governor) external; // base configuration options function configureClaimableYield() external; function configureClaimableYieldOnBehalf(address contractAddress) external; function configureAutomaticYield() external; function configureAutomaticYieldOnBehalf(address contractAddress) external; function configureVoidYield() external; function configureVoidYieldOnBehalf(address contractAddress) external; function configureClaimableGas() external; function configureClaimableGasOnBehalf(address contractAddress) external; function configureVoidGas() external; function configureVoidGasOnBehalf(address contractAddress) external; function configureGovernor(address _governor) external; function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external; // claim yield function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256); function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256); // claim gas function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGasAtMinClaimRate( address contractAddress, address recipientOfGas, uint256 minClaimRateBips ) external returns (uint256); function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGas( address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume ) external returns (uint256); // read functions function readClaimableYield(address contractAddress) external view returns (uint256); function readYieldConfiguration(address contractAddress) external view returns (uint8); function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
{ "remappings": [ "ds-test/=contracts/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=contracts/lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=contracts/lib/forge-std/src/", "openzeppelin-contracts/=contracts/lib/openzeppelin-contracts/contracts/", "solady/=contracts/lib/solady/src/", "openzeppelin/=contracts/lib/openzeppelin-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 10000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_judge","type":"address"},{"internalType":"address","name":"_withdrawJudge","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BattleAlreadyClaimed","type":"error"},{"inputs":[],"name":"BattleAlreadyMatched","type":"error"},{"inputs":[],"name":"BattleAlreadyNullified","type":"error"},{"inputs":[],"name":"BattleNotMatched","type":"error"},{"inputs":[],"name":"BattleSelfForbidden","type":"error"},{"inputs":[],"name":"ClaimFromNonParticipant","type":"error"},{"inputs":[],"name":"EthFeeNumerTooHigh","type":"error"},{"inputs":[],"name":"EthStakeMustMatchMsgValue","type":"error"},{"inputs":[],"name":"EthStakeNotUnique","type":"error"},{"inputs":[],"name":"ExceedsMaximumUniqueStakes","type":"error"},{"inputs":[],"name":"ExistingStakes","type":"error"},{"inputs":[],"name":"FeeTooLow","type":"error"},{"inputs":[],"name":"ForgedSignature","type":"error"},{"inputs":[],"name":"ForgedWithdrawSignature","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"MustHaveStake","type":"error"},{"inputs":[],"name":"NotAllowedParticipant","type":"error"},{"inputs":[],"name":"OnlyInitiatorCanNullify","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UniqueJudge","type":"error"},{"inputs":[],"name":"UserAlreadyWithdrawn","type":"error"},{"inputs":[],"name":"WithdrawFromNonParticipant","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"battleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"BattleCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"battleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"playerOne","type":"address"},{"indexed":true,"internalType":"address","name":"playerTwo","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"assetEnum","type":"uint256[]"},{"indexed":false,"internalType":"address[]","name":"contractAddr","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"amtOrTokenId","type":"uint256[]"}],"name":"BattleInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"battleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"playerOne","type":"address"},{"indexed":true,"internalType":"address","name":"playerTwo","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"assetEnum","type":"uint256[]"},{"indexed":false,"internalType":"address[]","name":"contractAddr","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"amtOrTokenId","type":"uint256[]"}],"name":"BattleJoined","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"battleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"counterparty","type":"address"}],"name":"BattleNullified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"battleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"winner","type":"address"}],"name":"BattleWon","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"ethFeeNumer","type":"uint256"}],"name":"EthFeeNumerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"feeChanged","type":"uint256"}],"name":"FeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newJudge","type":"address"}],"name":"JudgeChanged","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":true,"internalType":"address","name":"newWithdrawJudge","type":"address"}],"name":"WithdrawJudgeChanged","type":"event"},{"inputs":[],"name":"BLAST","outputs":[{"internalType":"contract IBlast","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"battles","outputs":[{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"bool","name":"matched","type":"bool"},{"internalType":"bool","name":"nullified","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"},{"components":[{"internalType":"bool","name":"isWinner","type":"bool"},{"internalType":"bool","name":"hasWithdrawn","type":"bool"},{"internalType":"address","name":"user","type":"address"},{"components":[{"internalType":"enum IBatchEscrow.AssetType","name":"asset","type":"uint8"},{"internalType":"address","name":"contractAddr","type":"address"},{"internalType":"uint256","name":"amtOrTokenId","type":"uint256"}],"internalType":"struct IBatchEscrow.BatchStake[]","name":"stakes","type":"tuple[]"}],"internalType":"struct IBatchBattle.BattleParticipant","name":"one","type":"tuple"},{"components":[{"internalType":"bool","name":"isWinner","type":"bool"},{"internalType":"bool","name":"hasWithdrawn","type":"bool"},{"internalType":"address","name":"user","type":"address"},{"components":[{"internalType":"enum IBatchEscrow.AssetType","name":"asset","type":"uint8"},{"internalType":"address","name":"contractAddr","type":"address"},{"internalType":"uint256","name":"amtOrTokenId","type":"uint256"}],"internalType":"struct IBatchEscrow.BatchStake[]","name":"stakes","type":"tuple[]"}],"internalType":"struct IBatchBattle.BattleParticipant","name":"two","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"battleId","type":"uint256"}],"name":"calcEthFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"feeNumer","type":"uint256"}],"name":"changeEthFeeNumer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"changeFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newJudge","type":"address"}],"name":"changeJudge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newWithdrawJudge","type":"address"}],"name":"changeWithdrawJudge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"battleId","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"claimProceeds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"battleId","type":"uint256"}],"name":"emergencyRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"payee","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"payee","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"emergencyWithdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"payee","type":"address"},{"internalType":"address","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"emergencyWithdrawERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"escrowAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethFeeNumer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"battleId","type":"uint256"}],"name":"getBattle","outputs":[{"components":[{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"bool","name":"matched","type":"bool"},{"internalType":"bool","name":"nullified","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"},{"components":[{"internalType":"bool","name":"isWinner","type":"bool"},{"internalType":"bool","name":"hasWithdrawn","type":"bool"},{"internalType":"address","name":"user","type":"address"},{"components":[{"internalType":"enum IBatchEscrow.AssetType","name":"asset","type":"uint8"},{"internalType":"address","name":"contractAddr","type":"address"},{"internalType":"uint256","name":"amtOrTokenId","type":"uint256"}],"internalType":"struct IBatchEscrow.BatchStake[]","name":"stakes","type":"tuple[]"}],"internalType":"struct IBatchBattle.BattleParticipant","name":"one","type":"tuple"},{"components":[{"internalType":"bool","name":"isWinner","type":"bool"},{"internalType":"bool","name":"hasWithdrawn","type":"bool"},{"internalType":"address","name":"user","type":"address"},{"components":[{"internalType":"enum IBatchEscrow.AssetType","name":"asset","type":"uint8"},{"internalType":"address","name":"contractAddr","type":"address"},{"internalType":"uint256","name":"amtOrTokenId","type":"uint256"}],"internalType":"struct IBatchEscrow.BatchStake[]","name":"stakes","type":"tuple[]"}],"internalType":"struct IBatchBattle.BattleParticipant","name":"two","type":"tuple"}],"internalType":"struct IBatchBattle.Battle","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"battleId","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"internalType":"struct IBatchBattle.Claim","name":"claim","type":"tuple"}],"name":"getClaimTypedDataHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"challenging","type":"address"},{"components":[{"internalType":"enum IBatchEscrow.AssetType","name":"asset","type":"uint8"},{"internalType":"address","name":"contractAddr","type":"address"},{"internalType":"uint256","name":"amtOrTokenId","type":"uint256"}],"internalType":"struct IBatchEscrow.BatchStake[]","name":"stakes","type":"tuple[]"}],"name":"initBattle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"battleId","type":"uint256"},{"components":[{"internalType":"enum IBatchEscrow.AssetType","name":"asset","type":"uint8"},{"internalType":"address","name":"contractAddr","type":"address"},{"internalType":"uint256","name":"amtOrTokenId","type":"uint256"}],"internalType":"struct IBatchEscrow.BatchStake[]","name":"stakes","type":"tuple[]"}],"name":"joinBattle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"judge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextBattleId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"battleId","type":"uint256"}],"name":"nullifyBattle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawJudge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"battleId","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101a06040523480156200001257600080fd5b5060405162006aa138038062006aa18339810160408190526200003591620004a8565b6040518060400160405280601081526020016f43616d627269614475656c4172656e6160801b815250604051806040016040528060018152602001603160f81b81525060016000819055506200009a620000946200038860201b60201c565b6200038c565b620000b5600283620003de60201b620032891790919060201c565b61012052620000d2816003620003de602090811b6200328917901c565b61014052815160208084019190912060e052815190820120610100524660a0526200016060e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c0526001600160a01b03831615806200018757506001600160a01b038216155b806200019a57506001600160a01b038116155b15620001b9576040516342bcdf7f60e11b815260040160405180910390fd5b82604051620001c8906200047d565b6001600160a01b039091168152602001604051809103906000f080158015620001f5573d6000803e3d6000fd5b506001600160a01b0390811661016081905261018052600480546001600160a01b031990811685841617825560058054909116928416929092179091556040805163784c3b3d60e11b815290517343000000000000000000000000000000000000029263f098767a9280820192600092909182900301818387803b1580156200027d57600080fd5b505af115801562000292573d6000803e3d6000fd5b505050507343000000000000000000000000000000000000026001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b158015620002e657600080fd5b505af1158015620002fb573d6000803e3d6000fd5b5050604051631d70c8d360e31b81526001600160a01b0386166004820152734300000000000000000000000000000000000002925063eb8646989150602401600060405180830381600087803b1580156200035557600080fd5b505af11580156200036a573d6000803e3d6000fd5b505050506200037f836200038c60201b60201c565b505050620006d8565b3390565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602083511015620003fe57620003f6836200042e565b905062000428565b8262000415836200047a60201b620032ba1760201c565b9062000422908262000597565b5060ff90505b92915050565b600080829050601f8151111562000465578260405163305a27a960e01b81526004016200045c919062000663565b60405180910390fd5b80516200047282620006b3565b179392505050565b90565b6119ad80620050f483390190565b80516001600160a01b0381168114620004a357600080fd5b919050565b600080600060608486031215620004be57600080fd5b620004c9846200048b565b9250620004d9602085016200048b565b9150620004e9604085016200048b565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200051d57607f821691505b6020821081036200053e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200059257600081815260208120601f850160051c810160208610156200056d5750805b601f850160051c820191505b818110156200058e5782815560010162000579565b5050505b505050565b81516001600160401b03811115620005b357620005b3620004f2565b620005cb81620005c4845462000508565b8462000544565b602080601f831160018114620006035760008415620005ea5750858301515b600019600386901b1c1916600185901b1785556200058e565b600085815260208120601f198616915b82811015620006345788860151825594840194600190910190840162000613565b5085821015620006535787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083528351808285015260005b81811015620006925785810183015185820160400152820162000674565b506000604082860101526040601f19601f8301168501019250505092915050565b805160208083015191908110156200053e5760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516149576200079d6000396000818161045301528181610b8901528181610cfe0152818161281b0152612981015260008181610db801528181611833015281816118e401528181611b56015281816122880152818161233701528181612a3b0152818161311d01526131cd01526000611bbe01526000611b93015260006138f5015260006138cd01526000613828015260006138520152600061387c01526149576000f3fe6080604052600436106101c25760003560e01c806380d9c5f3116100f7578063b7a2a78111610095578063e0caf57811610064578063e0caf57814610557578063e625215c14610577578063e941fa7814610597578063f2fde38b146105ad57600080fd5b8063b7a2a781146104f1578063ba12121714610504578063cdd7eb5214610524578063ce55803f1461054457600080fd5b80638da5cb5b116100d15780638da5cb5b1461047557806397d7577614610493578063b5462347146104bb578063b72b85a1146104d157600080fd5b806380d9c5f31461040657806384b0196e146104195780638b6cf6681461044157600080fd5b8063606d2e96116101645780636ff1c9bc1161013e5780636ff1c9bc14610391578063701b1e5a146103b157806370e5deb9146103d1578063715018a6146103f157600080fd5b8063606d2e96146103125780636a1db1bf146103445780636dd0ce7a1461036457600080fd5b8063297bf1a5116101a0578063297bf1a5146102a757806331a6ff66146102c957806337d8b79d146102df578063573255f4146102f257600080fd5b8063150b7a02146101c7578063160d6f3c146102415780632828eea814610279575b600080fd5b3480156101d357600080fd5b5061020b6101e2366004613d7b565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b34801561024d57600080fd5b50600554610261906001600160a01b031681565b6040516001600160a01b039091168152602001610238565b34801561028557600080fd5b50610299610294366004613de7565b6105cd565b604051908152602001610238565b3480156102b357600080fd5b506102c76102c2366004613e00565b61066d565b005b3480156102d557600080fd5b5061029960065481565b6102c76102ed366004613e7e565b610760565b3480156102fe57600080fd5b50600454610261906001600160a01b031681565b34801561031e57600080fd5b5061033261032d366004613de7565b610ec6565b60405161023896959493929190613fcd565b34801561035057600080fd5b506102c761035f366004613de7565b6110ec565b34801561037057600080fd5b5061038461037f366004613de7565b611127565b604051610238919061401d565b34801561039d57600080fd5b506102c76103ac36600461408d565b6113d5565b3480156103bd57600080fd5b506102c76103cc36600461408d565b6114c1565b3480156103dd57600080fd5b506102c76103ec366004613de7565b6115b3565b3480156103fd57600080fd5b506102c761194d565b6102c7610414366004613de7565b611961565b34801561042557600080fd5b5061042e611b85565b604051610238979695949392919061412b565b34801561044d57600080fd5b506102617f000000000000000000000000000000000000000000000000000000000000000081565b34801561048157600080fd5b506001546001600160a01b0316610261565b34801561049f57600080fd5b5061026173430000000000000000000000000000000000000281565b3480156104c757600080fd5b5061029960085481565b3480156104dd57600080fd5b506102c76104ec3660046141b5565b611c2a565b6102c76104ff3660046141f6565b611d0e565b34801561051057600080fd5b506102c761051f366004613de7565b6123a1565b34801561053057600080fd5b5061029961053f36600461423d565b612417565b610299610552366004614293565b61248f565b34801561056357600080fd5b506102c761057236600461408d565b612b44565b34801561058357600080fd5b506102c76105923660046141f6565b612c36565b3480156105a357600080fd5b5061029960075481565b3480156105b957600080fd5b506102c76105c836600461408d565b6131fc565b60008160065481106106265760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d75737420657869737421000000000000000000000000000060448201526064015b60405180910390fd5b600083815260096020526040902060010154600854610649576000925050610667565b61271060085461065990836142fe565b6106639190614315565b9250505b50919050565b6106756132bd565b61067d613317565b6001600160a01b0382166106bd576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906000906001600160a01b038316906370a0823190602401602060405180830381865afa15801561071f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107439190614350565b9050610750828583613370565b505061075c6001600055565b5050565b8260065481106107b25760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b6107ba613317565b81806107f2576040517f071e948200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881111561082d576040517f4f87596100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600960205260408120805434929190610100900460ff1615610880576040517f864a886500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805462010000900460ff16156108c2576040517fc3d8a04200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048101546201000090046001600160a01b0316331461090e576040517f87b1f39900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000888152600960205260409020600501805415610958576040517f75fd3c5400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b858110156109b9578189898381811061097657610976614369565b8354600181018555600094855260209094206060909102929092019260020290910190506109a482826143a5565b505080806109b19061445a565b91505061095b565b50600089815260096020526040902081546109d991600501908390613a50565b506000898152600960205260408120805461ff0019166101001781556001018054869290610a08908490614492565b90915550600090505b85811015610db0576000898983818110610a2d57610a2d614369565b610a4392602060609092020190810191506144a5565b6002811115610a5457610a54613eca565b03610aee57888882818110610a6b57610a6b614369565b905060600201604001358514610aad576040517ff601a14400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8315610ae5576040517ff544b27200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60019350610d9e565b6001898983818110610b0257610b02614369565b610b1892602060609092020190810191506144a5565b6002811115610b2957610b29613eca565b03610bcf576000898983818110610b4257610b42614369565b9050606002016020016020810190610b5a919061408d565b9050610b838133308d8d87818110610b7457610b74614369565b905060600201604001356133bf565b610bc9817f00000000000000000000000000000000000000000000000000000000000000008c8c86818110610bba57610bba614369565b9050606002016040013561341c565b50610d9e565b6002898983818110610be357610be3614369565b610bf992602060609092020190810191506144a5565b6002811115610c0a57610c0a613eca565b03610d9e576000898983818110610c2357610c23614369565b9050606002016020016020810190610c3b919061408d565b9050806001600160a01b03166342842e0e33308d8d87818110610c6057610c60614369565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b1681526001600160a01b039687166004820152959094166024860152606002919091019190910135604483015250606401600060405180830381600087803b158015610cd557600080fd5b505af1158015610ce9573d6000803e3d6000fd5b50505050806001600160a01b031663095ea7b37f00000000000000000000000000000000000000000000000000000000000000008c8c86818110610d2f57610d2f614369565b905060600201604001356040518363ffffffff1660e01b8152600401610d6a9291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b158015610d8457600080fd5b505af1158015610d98573d6000803e3d6000fd5b50505050505b80610da88161445a565b915050610a11565b5060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166349373a1988338f8f8f6040518663ffffffff1660e01b8152600401610e0994939291906144c2565b60006040518083038185885af1158015610e27573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052610e5091908101906145dc565b600288015460405193965091945092503391620100009091046001600160a01b0316908e907f09afbfed4f33a53c1bff738c8909e5f07a302af749605de0b786f92e40be97f890610ea6908890889088906146c2565b60405180910390a45050505050505050610ec06001600055565b50505050565b600960209081526000918252604080832080546001820154835160808101855260028401805460ff8181161515845261010080830482161515858b01526001600160a01b03620100009384900416858a01526003880180548a51818d0281018d01909b52808b528389169c92890484169b94909804909216989597969495939460608701949390919084015b82821015610fe257838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff166002811115610f9957610f99613eca565b6002811115610faa57610faa613eca565b8152815461010090046001600160a01b0316602080830191909152600192830154604090920191909152918352929092019101610f52565b505050915250506040805160808101825260048401805460ff808216151584526101008204161515602080850191909152620100009091046001600160a01b0316838501526005860180548551818402810184019096528086529596959394929360608601939260009084015b828210156110df57838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff16600281111561109657611096613eca565b60028111156110a7576110a7613eca565b8152815461010090046001600160a01b031660208083019190915260019283015460409092019190915291835292909201910161104f565b5050505081525050905086565b6110f46132bd565b600781905560405181907f6bbc57480a46553fa4d156ce702beef5f3ad66303b0ed1a5d4cb44966c6584c390600090a250565b61112f613b15565b8160065481106111815760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b6000838152600960209081526040808320815160c081018352815460ff808216151583526101008083048216151584880152620100009283900482161515848701526001850154606080860191909152865160808181018952600288018054808716151584529485049095161515828b01526001600160a01b039590930494909416848801526003860180548851818b0281018b019099528089529598969792890196949593949186019390918a9084015b828210156112c357838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff16600281111561127a5761127a613eca565b600281111561128b5761128b613eca565b8152815461010090046001600160a01b0316602080830191909152600192830154604090920191909152918352929092019101611233565b5050509152505081526040805160808101825260048401805460ff808216151584526101008204161515602080850191909152620100009091046001600160a01b031683850152600586018054855181840281018401909652808652958201959394929360608601939260009084015b828210156113c357838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff16600281111561137a5761137a613eca565b600281111561138b5761138b613eca565b8152815461010090046001600160a01b0316602080830191909152600192830154604090920191909152918352929092019101611333565b50505091525050905250949350505050565b6113dd6132bd565b6113e5613317565b6001600160a01b038116611425576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405147906000906001600160a01b0384169083908381818185875af1925050503d8060008114611472576040519150601f19603f3d011682016040523d82523d6000602084013e611477565b606091505b50509050806114b2576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506114be6001600055565b50565b6114c96132bd565b6001600160a01b038116611509576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004546001600160a01b0390811690821603611551576040517f62dd97a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517fb577a105c65e3df7015d800e52e963b9a45d2ccf117aded28201271748c8832490600090a250565b8060065481106116055760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b61160d6132bd565b611615613317565b6000828152600960205260409020805460ff1661194257805460ff1990811660019081178355600085815260096020526040902080548084168317825584546101009081900460ff9081161515820261ffff19938416178517808555875462010000908190048316151581027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff90921691909117855587860154958501959095556002808801805491860180549284161515988316891781558154859004909316151590930261ff0019979097169316929092179490941780825584546001600160a01b0390859004169093027fffffffffffffffffffff0000000000000000000000000000000000000000ffff9093169290921782556003808501805486959394926117459290860191613ba3565b50505060048281018054918301805460ff938416151560ff19821681178355835461010090819004909516151590940261ff001990941661ffff19909116179290921780835581546001600160a01b03620100009182900416027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909116178255600580850180549293926117dd9286019190613ba3565b5050505060028201546040517fd9caed12000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b03908116600483018190526024830152604482018690527f000000000000000000000000000000000000000000000000000000000000000016915063d9caed1290606401600060405180830381600087803b15801561187857600080fd5b505af115801561188c573d6000803e3d6000fd5b505050506004818101546040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b036201000090920482169281018390526024810192909252604482018590527f0000000000000000000000000000000000000000000000000000000000000000169063d9caed12906064015b600060405180830381600087803b15801561192957600080fd5b505af115801561193d573d6000803e3d6000fd5b505050505b5061075c6001600055565b6119556132bd565b61195f6000613461565b565b8060065481106119b35760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b6119bb613317565b60008281526009602052604090208054610100900460ff1615611a0a576040517f864a886500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805462010000900460ff1615611a4c576040517fc3d8a04200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546201000090046001600160a01b03163314611a98576040517fb3153ae600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054620100007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff9091168117825560048201546040519190046001600160a01b031690339085907f1adcfbcfae7625b5bbaf696c3898a3f28b8d91300b9f0950d5a72abf3af79fc490600090a460028101546040517fd9caed12000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b039081166004830152336024830152604482018590527f0000000000000000000000000000000000000000000000000000000000000000169063d9caed129060640161190f565b600060608082808083611bb97f000000000000000000000000000000000000000000000000000000000000000060026134cb565b611be47f000000000000000000000000000000000000000000000000000000000000000060036134cb565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b611c326132bd565b611c3a613317565b6001600160a01b038316611c7a576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f42842e0e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038481166024830152604482018390528391908216906342842e0e90606401600060405180830381600087803b158015611ce657600080fd5b505af1158015611cfa573d6000803e3d6000fd5b5050505050611d096001600055565b505050565b611d16613317565b816006548110611d685760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b600754341015611da4576040517f732f941300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dad836105cd565b341015611de6576040517f732f941300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526009602052604090205462010000900460ff1615611e35576040517fc3d8a04200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260096020526040902054610100900460ff16611e82576040517f60e178dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526009602052604090205460ff1615611ecb576040517f5f7d9fd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260096020526040902060020154610100900460ff1680611f065750600083815260096020526040902060040154610100900460ff165b15611f3d576040517f8783db4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611f6e611f686040518060400160405280878152602001336001600160a01b0316815250612417565b8461356f565b6004549091506001600160a01b03808316911614611fb8576040517f67e0646f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260096020526040902060028101546201000090046001600160a01b03163303611ff45760028101805460ff19166001179055612054565b60048101546201000090046001600160a01b031633036120225760048101805460ff19166001179055612054565b6040517f5756bdf200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805460ff1990811660019081178355600087815260096020526040902080548084168317825584546101009081900460ff9081161515820261ffff19938416178517808555875462010000908190048316151581027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff90921691909117855587860154958501959095556002808801805491860180549284161515988316891781558154859004909316151590930261ff0019979097169316929092179490941780825584546001600160a01b0390859004169093027fffffffffffffffffffff0000000000000000000000000000000000000000ffff90931692909217825560038085018054869593949261216d9290860191613ba3565b50505060048281018054918301805460ff938416151560ff19821681178355835461010090819004909516151590940261ff001990941661ffff19909116179290921780835581546001600160a01b03620100009182900416027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909116178255600580850180549293926122059286019190613ba3565b50506040513393508892507f5caaae5c6b57b49f652b073fdbcfee86d217e8071f04500c8cd368e57ffa909a9150600090a360028101546040517fd9caed12000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b039081166004830152336024830152604482018790527f0000000000000000000000000000000000000000000000000000000000000000169063d9caed1290606401600060405180830381600087803b1580156122cc57600080fd5b505af11580156122e0573d6000803e3d6000fd5b505050506004818101546040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b0362010000909204821692810192909252336024830152604482018790527f0000000000000000000000000000000000000000000000000000000000000000169063d9caed12906064015b600060405180830381600087803b15801561237c57600080fd5b505af1158015612390573d6000803e3d6000fd5b5050505050505061075c6001600055565b6123a96132bd565b61271081106123e4576040517f6cb2e31100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881905560405181907febd01212c8e07d8dfc99de72a08a3d0f4f8c05806b947a90c3c8e00129b7806590600090a250565b60006124897fe88e9621e199fc30ba59586e4e0bc08a8f9b622445f68a447c0cc0b8366d4047835160208086015160405161246e9493920192835260208301919091526001600160a01b0316604082015260600190565b60405160208183030381529060405280519060200120613593565b92915050565b6000612499613317565b81806124d1576040517f071e948200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881111561250c576040517f4f87596100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516330361254e576040517fbf6f1bf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680543491819060006125618361445a565b909155505060008181526009602052604081206002810180547fffffffffffffffffffff0000000000000000000000000000000000000000ffff163362010000021790556003018054156125e1576040517f75fd3c5400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8581101561264257818989838181106125ff576125ff614369565b83546001810185556000948552602090942060609091029290920192600202909101905061262d82826143a5565b5050808061263a9061445a565b9150506125e4565b506000838152600960205260409020815461266291600301908390613a50565b5060008381526009602052604081206004810180547fffffffffffffffffffff0000000000000000000000000000000000000000ffff16620100006001600160a01b038e16021790556001018590555b85811015612a335760008989838181106126ce576126ce614369565b6126e492602060609092020190810191506144a5565b60028111156126f5576126f5613eca565b0361278f5788888281811061270c5761270c614369565b90506060020160400135851461274e576040517ff601a14400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8215612786576040517ff544b27200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60019250612a21565b60018989838181106127a3576127a3614369565b6127b992602060609092020190810191506144a5565b60028111156127ca576127ca613eca565b036128525760008989838181106127e3576127e3614369565b90506060020160200160208101906127fb919061408d565b90506128158133308d8d87818110610b7457610b74614369565b61284c817f00000000000000000000000000000000000000000000000000000000000000008c8c86818110610bba57610bba614369565b50612a21565b600289898381811061286657612866614369565b61287c92602060609092020190810191506144a5565b600281111561288d5761288d613eca565b03612a215760008989838181106128a6576128a6614369565b90506060020160200160208101906128be919061408d565b9050806001600160a01b03166342842e0e33308d8d878181106128e3576128e3614369565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b1681526001600160a01b039687166004820152959094166024860152606002919091019190910135604483015250606401600060405180830381600087803b15801561295857600080fd5b505af115801561296c573d6000803e3d6000fd5b50505050806001600160a01b031663095ea7b37f00000000000000000000000000000000000000000000000000000000000000008c8c868181106129b2576129b2614369565b905060600201604001356040518363ffffffff1660e01b81526004016129ed9291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b158015612a0757600080fd5b505af1158015612a1b573d6000803e3d6000fd5b50505050505b80612a2b8161445a565b9150506126b2565b5060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166349373a198833898f8f6040518663ffffffff1660e01b8152600401612a8c94939291906144c2565b60006040518083038185885af1158015612aaa573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052612ad391908101906145dc565b9250925092508b6001600160a01b0316336001600160a01b0316877fe856d9c527bc013d9955698be44d4c7e13739fa87594a8933c0d942daf41e483868686604051612b21939291906146c2565b60405180910390a450939650505050505050612b3d6001600055565b9392505050565b612b4c6132bd565b6001600160a01b038116612b8c576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546001600160a01b0390811690821603612bd4576040517f62dd97a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f5ea4303afd5550bc5eb446bc464116608045996cc44a0d3ec3ccfa9650aa56ff90600090a250565b612c3e613317565b816006548110612c905760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b6000838152600960205260409020805462010000900460ff1615612ce0576040517fc3d8a04200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260096020526040902054610100900460ff16612d2d576040517f60e178dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805460ff1615612d69576040517f5f7d9fd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600281015433620100009091046001600160a01b031603612dcd576002810154610100900460ff1615612dc8576040517f8783db4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e5e565b600481015433620100009091046001600160a01b031603612e2c576004810154610100900460ff1615612dc8576040517f8783db4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f38db7f2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612e8f612e896040518060400160405280888152602001336001600160a01b0316815250612417565b8561356f565b6005549091506001600160a01b03808316911614612ed9576040517fb4f0c44f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002808301805461ff0019908116610100908117835560048601805483168217905560008981526009602052604090208654815460ff918216151560ff19808316821785558a5486900484161515860291871661ffff1993841617919091178085558a5462010000908190048516151581027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff90921691909117855560018b81015490860155875498850180549985161515928a16831781558854879004909416151590950295169616959095179290921780855583546001600160a01b0390839004169091027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909116178355600380860180548795939493926130019290860191613ba3565b50505060048281018054918301805460ff938416151560ff19821681178355835461010090819004909516151590940261ff001990941661ffff19909116179290921780835581546001600160a01b03620100009182900416027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909116178255600580850180549293926130999286019190613ba3565b50506040513393508892507f8d7df0ced4aeda0e69d998705dddbf1eac70be8d7fb991edc80ddf6f29424a739150600090a360028201546040517fd9caed12000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b03908116600483018190526024830152604482018790527f0000000000000000000000000000000000000000000000000000000000000000169063d9caed1290606401600060405180830381600087803b15801561316157600080fd5b505af1158015613175573d6000803e3d6000fd5b505050506004828101546040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b036201000090920482169281018390526024810192909252604482018790527f0000000000000000000000000000000000000000000000000000000000000000169063d9caed1290606401612362565b6132046132bd565b6001600160a01b0381166132805760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161061d565b6114be81613461565b60006020835110156132a55761329e836135db565b9050612489565b816132b084826147d0565b5060ff9392505050565b90565b6001546001600160a01b0316331461195f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161061d565b6002600054036133695760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161061d565b6002600055565b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d1560016000511417166133b5576390b8ec186000526004601cfd5b6000603452505050565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d15600160005114171661340e57637939f4246000526004601cfd5b600060605260405250505050565b81601452806034526f095ea7b300000000000000000000000060005260206000604460106000875af13d1560016000511417166133b557633e3f8f736000526004601cfd5b600180546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b606060ff83146134de5761329e83613632565b8180546134ea90614735565b80601f016020809104026020016040519081016040528092919081815260200182805461351690614735565b80156135635780601f1061353857610100808354040283529160200191613563565b820191906000526020600020905b81548152906001019060200180831161354657829003601f168201915b50505050509050612489565b600080600061357e8585613671565b9150915061358b816136b6565b509392505050565b60006124896135a061381b565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b600080829050601f8151111561361f57826040517f305a27a900000000000000000000000000000000000000000000000000000000815260040161061d91906148cc565b805161362a826148df565b179392505050565b6060600061363f8361394b565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b60008082516041036136a75760208301516040840151606085015160001a61369b8782858561398c565b945094505050506136af565b506000905060025b9250929050565b60008160048111156136ca576136ca613eca565b036136d25750565b60018160048111156136e6576136e6613eca565b036137335760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161061d565b600281600481111561374757613747613eca565b036137945760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161061d565b60038160048111156137a8576137a8613eca565b036114be5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015260840161061d565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561387457507f000000000000000000000000000000000000000000000000000000000000000046145b1561389e57507f000000000000000000000000000000000000000000000000000000000000000090565b613946604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b600060ff8216601f811115612489576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156139c35750600090506003613a47565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613a17573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613a4057600060019250925050613a47565b9150600090505b94509492505050565b828054828255906000526020600020906002028101928215613b055760005260206000209160020282015b82811115613b0557825482548491849160ff90911690829060ff19166001836002811115613aab57613aab613eca565b0217905550815481547fffffffffffffffffffffff0000000000000000000000000000000000000000ff16610100918290046001600160a01b03169091021781556001918201549101556002928301929190910190613a7b565b50613b11929150613c58565b5090565b6040518060c0016040528060001515815260200160001515815260200160001515815260200160008152602001613b7a604051806080016040528060001515815260200160001515815260200160006001600160a01b03168152602001606081525090565b815260408051608081018252600080825260208281018290529282015260608082015291015290565b828054828255906000526020600020906002028101928215613b055760005260206000209160020282015b82811115613b0557825482548491849160ff90911690829060ff19166001836002811115613bfe57613bfe613eca565b0217905550815481547fffffffffffffffffffffff0000000000000000000000000000000000000000ff16610100918290046001600160a01b03169091021781556001918201549101556002928301929190910190613bce565b5b80821115613b115780547fffffffffffffffffffffff00000000000000000000000000000000000000000016815560006001820155600201613c59565b6001600160a01b03811681146114be57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613d0357613d03613cab565b604052919050565b600082601f830112613d1c57600080fd5b813567ffffffffffffffff811115613d3657613d36613cab565b613d496020601f19601f84011601613cda565b818152846020838601011115613d5e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613d9157600080fd5b8435613d9c81613c96565b93506020850135613dac81613c96565b925060408501359150606085013567ffffffffffffffff811115613dcf57600080fd5b613ddb87828801613d0b565b91505092959194509250565b600060208284031215613df957600080fd5b5035919050565b60008060408385031215613e1357600080fd5b8235613e1e81613c96565b91506020830135613e2e81613c96565b809150509250929050565b60008083601f840112613e4b57600080fd5b50813567ffffffffffffffff811115613e6357600080fd5b6020830191508360206060830285010111156136af57600080fd5b600080600060408486031215613e9357600080fd5b83359250602084013567ffffffffffffffff811115613eb157600080fd5b613ebd86828701613e39565b9497909650939450505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110613f30577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6000608083018251151584526020808401511515818601526040808501516001600160a01b038082168389015260609150818701516080838a015285815180885260a08b0191508683019750600092505b80831015613fbf578751613f9a838251613ef9565b8088015185168389015286015186830152968601966001929092019190840190613f85565b509998505050505050505050565b86151581528515156020820152841515604082015283606082015260c060808201526000613ffe60c0830185613f34565b82810360a08401526140108185613f34565b9998505050505050505050565b60208152815115156020820152602082015115156040820152604082015115156060820152606082015160808201526000608083015160c060a084015261406760e0840182613f34565b905060a0840151601f198483030160c08501526140848282613f34565b95945050505050565b60006020828403121561409f57600080fd5b8135612b3d81613c96565b6000815180845260005b818110156140d0576020818501810151868301820152016140b4565b506000602082860101526020601f19601f83011685010191505092915050565b600081518084526020808501945080840160005b8381101561412057815187529582019590820190600101614104565b509495945050505050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e06020820152600061416660e08301896140aa565b828103604084015261417881896140aa565b90508660608401526001600160a01b03861660808401528460a084015282810360c08401526141a781856140f0565b9a9950505050505050505050565b6000806000606084860312156141ca57600080fd5b83356141d581613c96565b925060208401356141e581613c96565b929592945050506040919091013590565b6000806040838503121561420957600080fd5b82359150602083013567ffffffffffffffff81111561422757600080fd5b61423385828601613d0b565b9150509250929050565b60006040828403121561424f57600080fd5b6040516040810181811067ffffffffffffffff8211171561427257614272613cab565b60405282358152602083013561428781613c96565b60208201529392505050565b6000806000604084860312156142a857600080fd5b83356142b381613c96565b9250602084013567ffffffffffffffff811115613eb157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417612489576124896142cf565b60008261434b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561436257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600381106114be57600080fd5b81356143b081614398565b600381106143e7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b815460ff821691508160ff198216178355602084013561440681613c96565b74ffffffffffffffffffffffffffffffffffffffff008160081b16837fffffffffffffffffffffff000000000000000000000000000000000000000000841617178455505050604082013560018201555050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361448b5761448b6142cf565b5060010190565b80820180821115612489576124896142cf565b6000602082840312156144b757600080fd5b8135612b3d81614398565b600060608083016001600160a01b03808916855260208881870152604084818801528388855260808801905089945060005b8981101561453d57853561450781614398565b6145118382613ef9565b508386013561451f81613c96565b851682850152858301358383015294860194908601906001016144f4565b509b9a5050505050505050505050565b600067ffffffffffffffff82111561456757614567613cab565b5060051b60200190565b600082601f83011261458257600080fd5b815160206145976145928361454d565b613cda565b82815260059290921b840181019181810190868411156145b657600080fd5b8286015b848110156145d157805183529183019183016145ba565b509695505050505050565b6000806000606084860312156145f157600080fd5b835167ffffffffffffffff8082111561460957600080fd5b61461587838801614571565b945060209150818601518181111561462c57600080fd5b8601601f8101881361463d57600080fd5b805161464b6145928261454d565b81815260059190911b8201840190848101908a83111561466a57600080fd5b928501925b8284101561469157835161468281613c96565b8252928501929085019061466f565b60408a01519097509450505050808211156146ab57600080fd5b506146b886828701614571565b9150509250925092565b6060815260006146d560608301866140f0565b82810360208481019190915285518083528682019282019060005b818110156147155784516001600160a01b0316835293830193918301916001016146f0565b5050848103604086015261472981876140f0565b98975050505050505050565b600181811c9082168061474957607f821691505b602082108103610667577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f821115611d0957600081815260208120601f850160051c810160208610156147a95750805b601f850160051c820191505b818110156147c8578281556001016147b5565b505050505050565b815167ffffffffffffffff8111156147ea576147ea613cab565b6147fe816147f88454614735565b84614782565b602080601f831160018114614851576000841561481b5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556147c8565b600085815260208120601f198616915b8281101561488057888601518255948401946001909101908401614861565b50858210156148bc57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000612b3d60208301846140aa565b80516020808301519190811015610667577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b1691905056fea2646970667358221220156769e0a178c2060aeb8c7d6387738abc8cf9ba62c1a5a21b07bac628e8d48064736f6c6343000812003360806040523480156200001157600080fd5b50604051620019ad380380620019ad8339810160408190526200003491620001ff565b6200003f33620001af565b6001600160a01b03811662000067576040516342bcdf7f60e11b815260040160405180910390fd5b7343000000000000000000000000000000000000026001600160a01b031663f098767a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015620000b757600080fd5b505af1158015620000cc573d6000803e3d6000fd5b505050507343000000000000000000000000000000000000026001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200012057600080fd5b505af115801562000135573d6000803e3d6000fd5b5050604051631d70c8d360e31b81526001600160a01b0384166004820152734300000000000000000000000000000000000002925063eb8646989150602401600060405180830381600087803b1580156200018f57600080fd5b505af1158015620001a4573d6000803e3d6000fd5b505050505062000231565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156200021257600080fd5b81516001600160a01b03811681146200022a57600080fd5b9392505050565b61176c80620002416000396000f3fe60806040526004361061007b5760003560e01c806397d757761161004e57806397d757761461017f578063ae22192e146101a7578063d9caed12146101d4578063f2fde38b146101f457600080fd5b8063150b7a021461008057806349373a19146100fa578063715018a61461011c5780638da5cb5b14610133575b600080fd5b34801561008c57600080fd5b506100c461009b366004611289565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b61010d610108366004611387565b610214565b6040516100f193929190611494565b34801561012857600080fd5b5061013161088c565b005b34801561013f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f1565b34801561018b57600080fd5b5061015a73430000000000000000000000000000000000000281565b3480156101b357600080fd5b506101c76101c23660046114d7565b6108a0565b6040516100f19190611532565b3480156101e057600080fd5b506101316101ef3660046115d8565b610994565b34801561020057600080fd5b5061013161020f366004611619565b610e7b565b6060806060610221610f37565b833460008267ffffffffffffffff81111561023e5761023e61125a565b604051908082528060200260200182016040528015610267578160200160208202803683370190505b50905060008367ffffffffffffffff8111156102855761028561125a565b6040519080825280602002602001820160405280156102ae578160200160208202803683370190505b50905060008467ffffffffffffffff8111156102cc576102cc61125a565b6040519080825280602002602001820160405280156102f5578160200160208202803683370190505b50905060005b858110156105b3578a8a828181106103155761031561163d565b61032b926020606090920201908101915061166c565b600281111561033c5761033c611503565b84828151811061034e5761034e61163d565b6020026020010181815250508a8a8281811061036c5761036c61163d565b90506060020160200160208101906103849190611619565b8382815181106103965761039661163d565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508a8a828181106103e2576103e261163d565b905060600201604001358282815181106103fe576103fe61163d565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff8e1660009081526001825260408082208f835290925281902081516060810190925290808d8d858181106104585761045861163d565b61046e926020606090920201908101915061166c565b600281111561047f5761047f611503565b81526020018d8d858181106104965761049661163d565b90506060020160200160208101906104ae9190611619565b73ffffffffffffffffffffffffffffffffffffffff1681526020018d8d858181106104db576104db61163d565b6060029190910160400135909152508154600180820184556000938452602090932082516002928302909101805493949093919284927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169190849081111561054657610546611503565b02179055506020820151815473ffffffffffffffffffffffffffffffffffffffff909116610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909116178155604090910151600190910155806105ab8161168d565b9150506102fb565b5060005b858110156108255760008b8b838181106105d3576105d361163d565b6105e9926020606090920201908101915061166c565b60028111156105fa576105fa611503565b0361063e5760008511610639576040517fb2d71ce000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610813565b60018b8b838181106106525761065261163d565b610668926020606090920201908101915061166c565b600281111561067957610679611503565b036106d95760008b8b838181106106925761069261163d565b90506060020160200160208101906106aa9190611619565b90506106d38133308f8f878181106106c4576106c461163d565b90506060020160400135610fb8565b50610813565b60028b8b838181106106ed576106ed61163d565b610703926020606090920201908101915061166c565b600281111561071457610714611503565b036108135760008b8b8381811061072d5761072d61163d565b90506060020160200160208101906107459190611619565b90508073ffffffffffffffffffffffffffffffffffffffff166342842e0e33308f8f878181106107775761077761163d565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b16815273ffffffffffffffffffffffffffffffffffffffff9687166004820152959094166024860152606002919091019190910135604483015250606401600060405180830381600087803b1580156107f957600080fd5b505af115801561080d573d6000803e3d6000fd5b50505050505b8061081d8161168d565b9150506105b7565b508b73ffffffffffffffffffffffffffffffffffffffff167fb0107a6f6949cc8456afb31c37416271495e207fc54f9c78060932524721f2388c85858560405161087294939291906116ec565b60405180910390a2919b909a509098509650505050505050565b610894610f37565b61089e6000611015565b565b73ffffffffffffffffffffffffffffffffffffffff821660009081526001602090815260408083208484528252808320805482518185028101850190935280835260609493849084015b8282101561098757838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff16600281111561093157610931611503565b600281111561094257610942611503565b81528154610100900473ffffffffffffffffffffffffffffffffffffffff166020808301919091526001928301546040909201919091529183529290920191016108ea565b5092979650505050505050565b61099c610f37565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600160209081526040808320848452825280832080548251818502810185019093528083529192909190849084015b82821015610a8457838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff166002811115610a2e57610a2e611503565b6002811115610a3f57610a3f611503565b81528154610100900473ffffffffffffffffffffffffffffffffffffffff166020808301919091526001928301546040909201919091529183529290920191016109e7565b50505050905060008151905060008167ffffffffffffffff811115610aab57610aab61125a565b604051908082528060200260200182016040528015610ad4578160200160208202803683370190505b50905060008267ffffffffffffffff811115610af257610af261125a565b604051908082528060200260200182016040528015610b1b578160200160208202803683370190505b50905060008367ffffffffffffffff811115610b3957610b3961125a565b604051908082528060200260200182016040528015610b62578160200160208202803683370190505b50905060005b84811015610e1c5773ffffffffffffffffffffffffffffffffffffffff891660009081526001602090815260408083208a84529091528120805483908110610bb257610bb261163d565b90600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff166002811115610bef57610bef611503565b6002811115610c0057610c00611503565b81528154610100900473ffffffffffffffffffffffffffffffffffffffff1660208201526001909101546040909101529050600081516002811115610c4757610c47611503565b03610c77576040810151610c729073ffffffffffffffffffffffffffffffffffffffff8b169061108a565b610d65565b600181516002811115610c8c57610c8c611503565b03610caf57600081602001519050610ca9818b84604001516111e9565b50610d65565b600281516002811115610cc457610cc4611503565b03610d6557602081015160408083015190517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8c811660248301526044820192909252908216906342842e0e90606401600060405180830381600087803b158015610d4b57600080fd5b505af1158015610d5f573d6000803e3d6000fd5b50505050505b80516002811115610d7857610d78611503565b858381518110610d8a57610d8a61163d565b6020026020010181815250508060200151848381518110610dad57610dad61163d565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060400151838381518110610dfe57610dfe61163d565b60209081029190910101525080610e148161168d565b915050610b68565b508773ffffffffffffffffffffffffffffffffffffffff167f7b224de6515d87d7a66df408bfbcf4050c68efef906081cff527d45bf3fdd39787858585604051610e6994939291906116ec565b60405180910390a25050505050505050565b610e83610f37565b73ffffffffffffffffffffffffffffffffffffffff8116610f2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610f3481611015565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461089e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610f22565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d15600160005114171661100757637939f4246000526004601cfd5b600060605260405250505050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b804710156110f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610f22565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461114e576040519150601f19603f3d011682016040523d82523d6000602084013e611153565b606091505b50509050806111e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610f22565b505050565b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d15600160005114171661122e576390b8ec186000526004601cfd5b6000603452505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610f3457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000806080858703121561129f57600080fd5b84356112aa81611238565b935060208501356112ba81611238565b925060408501359150606085013567ffffffffffffffff808211156112de57600080fd5b818701915087601f8301126112f257600080fd5b8135818111156113045761130461125a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561134a5761134a61125a565b816040528281528a602084870101111561136357600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b6000806000806060858703121561139d57600080fd5b84356113a881611238565b935060208501359250604085013567ffffffffffffffff808211156113cc57600080fd5b818701915087601f8301126113e057600080fd5b8135818111156113ef57600080fd5b88602060608302850101111561140457600080fd5b95989497505060200194505050565b600081518084526020808501945080840160005b8381101561144357815187529582019590820190600101611427565b509495945050505050565b600081518084526020808501945080840160005b8381101561144357815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101611462565b6060815260006114a76060830186611413565b82810360208401526114b9818661144e565b905082810360408401526114cd8185611413565b9695505050505050565b600080604083850312156114ea57600080fd5b82356114f581611238565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208082528251828201819052600091906040908185019086840185805b838110156115ca578251805160038110611591577f4e487b710000000000000000000000000000000000000000000000000000000084526021600452602484fd5b86528088015173ffffffffffffffffffffffffffffffffffffffff16888701528601518686015260609094019391860191600101611550565b509298975050505050505050565b6000806000606084860312156115ed57600080fd5b83356115f881611238565b9250602084013561160881611238565b929592945050506040919091013590565b60006020828403121561162b57600080fd5b813561163681611238565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561167e57600080fd5b81356003811061163657600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036116e5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b8481526080602082015260006117056080830186611413565b8281036040840152611717818661144e565b9050828103606084015261172b8185611413565b97965050505050505056fea2646970667358221220d834dfd547a553535b51f42da9bdbbe3bea884de8554b77e5a39ea8aeead879464736f6c63430008120033000000000000000000000000be16d5c286aa885a2261a6b99a518e5effd2f3880000000000000000000000001d28206358d30e84f985ac6edbc6ae49f25ffa7f000000000000000000000000b0e7d4175be8e83a8075538f2dbe6f87d5a69013
Deployed Bytecode
0x6080604052600436106101c25760003560e01c806380d9c5f3116100f7578063b7a2a78111610095578063e0caf57811610064578063e0caf57814610557578063e625215c14610577578063e941fa7814610597578063f2fde38b146105ad57600080fd5b8063b7a2a781146104f1578063ba12121714610504578063cdd7eb5214610524578063ce55803f1461054457600080fd5b80638da5cb5b116100d15780638da5cb5b1461047557806397d7577614610493578063b5462347146104bb578063b72b85a1146104d157600080fd5b806380d9c5f31461040657806384b0196e146104195780638b6cf6681461044157600080fd5b8063606d2e96116101645780636ff1c9bc1161013e5780636ff1c9bc14610391578063701b1e5a146103b157806370e5deb9146103d1578063715018a6146103f157600080fd5b8063606d2e96146103125780636a1db1bf146103445780636dd0ce7a1461036457600080fd5b8063297bf1a5116101a0578063297bf1a5146102a757806331a6ff66146102c957806337d8b79d146102df578063573255f4146102f257600080fd5b8063150b7a02146101c7578063160d6f3c146102415780632828eea814610279575b600080fd5b3480156101d357600080fd5b5061020b6101e2366004613d7b565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b34801561024d57600080fd5b50600554610261906001600160a01b031681565b6040516001600160a01b039091168152602001610238565b34801561028557600080fd5b50610299610294366004613de7565b6105cd565b604051908152602001610238565b3480156102b357600080fd5b506102c76102c2366004613e00565b61066d565b005b3480156102d557600080fd5b5061029960065481565b6102c76102ed366004613e7e565b610760565b3480156102fe57600080fd5b50600454610261906001600160a01b031681565b34801561031e57600080fd5b5061033261032d366004613de7565b610ec6565b60405161023896959493929190613fcd565b34801561035057600080fd5b506102c761035f366004613de7565b6110ec565b34801561037057600080fd5b5061038461037f366004613de7565b611127565b604051610238919061401d565b34801561039d57600080fd5b506102c76103ac36600461408d565b6113d5565b3480156103bd57600080fd5b506102c76103cc36600461408d565b6114c1565b3480156103dd57600080fd5b506102c76103ec366004613de7565b6115b3565b3480156103fd57600080fd5b506102c761194d565b6102c7610414366004613de7565b611961565b34801561042557600080fd5b5061042e611b85565b604051610238979695949392919061412b565b34801561044d57600080fd5b506102617f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce81565b34801561048157600080fd5b506001546001600160a01b0316610261565b34801561049f57600080fd5b5061026173430000000000000000000000000000000000000281565b3480156104c757600080fd5b5061029960085481565b3480156104dd57600080fd5b506102c76104ec3660046141b5565b611c2a565b6102c76104ff3660046141f6565b611d0e565b34801561051057600080fd5b506102c761051f366004613de7565b6123a1565b34801561053057600080fd5b5061029961053f36600461423d565b612417565b610299610552366004614293565b61248f565b34801561056357600080fd5b506102c761057236600461408d565b612b44565b34801561058357600080fd5b506102c76105923660046141f6565b612c36565b3480156105a357600080fd5b5061029960075481565b3480156105b957600080fd5b506102c76105c836600461408d565b6131fc565b60008160065481106106265760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d75737420657869737421000000000000000000000000000060448201526064015b60405180910390fd5b600083815260096020526040902060010154600854610649576000925050610667565b61271060085461065990836142fe565b6106639190614315565b9250505b50919050565b6106756132bd565b61067d613317565b6001600160a01b0382166106bd576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906000906001600160a01b038316906370a0823190602401602060405180830381865afa15801561071f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107439190614350565b9050610750828583613370565b505061075c6001600055565b5050565b8260065481106107b25760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b6107ba613317565b81806107f2576040517f071e948200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881111561082d576040517f4f87596100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600960205260408120805434929190610100900460ff1615610880576040517f864a886500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805462010000900460ff16156108c2576040517fc3d8a04200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048101546201000090046001600160a01b0316331461090e576040517f87b1f39900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000888152600960205260409020600501805415610958576040517f75fd3c5400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b858110156109b9578189898381811061097657610976614369565b8354600181018555600094855260209094206060909102929092019260020290910190506109a482826143a5565b505080806109b19061445a565b91505061095b565b50600089815260096020526040902081546109d991600501908390613a50565b506000898152600960205260408120805461ff0019166101001781556001018054869290610a08908490614492565b90915550600090505b85811015610db0576000898983818110610a2d57610a2d614369565b610a4392602060609092020190810191506144a5565b6002811115610a5457610a54613eca565b03610aee57888882818110610a6b57610a6b614369565b905060600201604001358514610aad576040517ff601a14400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8315610ae5576040517ff544b27200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60019350610d9e565b6001898983818110610b0257610b02614369565b610b1892602060609092020190810191506144a5565b6002811115610b2957610b29613eca565b03610bcf576000898983818110610b4257610b42614369565b9050606002016020016020810190610b5a919061408d565b9050610b838133308d8d87818110610b7457610b74614369565b905060600201604001356133bf565b610bc9817f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce8c8c86818110610bba57610bba614369565b9050606002016040013561341c565b50610d9e565b6002898983818110610be357610be3614369565b610bf992602060609092020190810191506144a5565b6002811115610c0a57610c0a613eca565b03610d9e576000898983818110610c2357610c23614369565b9050606002016020016020810190610c3b919061408d565b9050806001600160a01b03166342842e0e33308d8d87818110610c6057610c60614369565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b1681526001600160a01b039687166004820152959094166024860152606002919091019190910135604483015250606401600060405180830381600087803b158015610cd557600080fd5b505af1158015610ce9573d6000803e3d6000fd5b50505050806001600160a01b031663095ea7b37f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce8c8c86818110610d2f57610d2f614369565b905060600201604001356040518363ffffffff1660e01b8152600401610d6a9291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b158015610d8457600080fd5b505af1158015610d98573d6000803e3d6000fd5b50505050505b80610da88161445a565b915050610a11565b5060008060007f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce6001600160a01b03166349373a1988338f8f8f6040518663ffffffff1660e01b8152600401610e0994939291906144c2565b60006040518083038185885af1158015610e27573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052610e5091908101906145dc565b600288015460405193965091945092503391620100009091046001600160a01b0316908e907f09afbfed4f33a53c1bff738c8909e5f07a302af749605de0b786f92e40be97f890610ea6908890889088906146c2565b60405180910390a45050505050505050610ec06001600055565b50505050565b600960209081526000918252604080832080546001820154835160808101855260028401805460ff8181161515845261010080830482161515858b01526001600160a01b03620100009384900416858a01526003880180548a51818d0281018d01909b52808b528389169c92890484169b94909804909216989597969495939460608701949390919084015b82821015610fe257838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff166002811115610f9957610f99613eca565b6002811115610faa57610faa613eca565b8152815461010090046001600160a01b0316602080830191909152600192830154604090920191909152918352929092019101610f52565b505050915250506040805160808101825260048401805460ff808216151584526101008204161515602080850191909152620100009091046001600160a01b0316838501526005860180548551818402810184019096528086529596959394929360608601939260009084015b828210156110df57838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff16600281111561109657611096613eca565b60028111156110a7576110a7613eca565b8152815461010090046001600160a01b031660208083019190915260019283015460409092019190915291835292909201910161104f565b5050505081525050905086565b6110f46132bd565b600781905560405181907f6bbc57480a46553fa4d156ce702beef5f3ad66303b0ed1a5d4cb44966c6584c390600090a250565b61112f613b15565b8160065481106111815760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b6000838152600960209081526040808320815160c081018352815460ff808216151583526101008083048216151584880152620100009283900482161515848701526001850154606080860191909152865160808181018952600288018054808716151584529485049095161515828b01526001600160a01b039590930494909416848801526003860180548851818b0281018b019099528089529598969792890196949593949186019390918a9084015b828210156112c357838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff16600281111561127a5761127a613eca565b600281111561128b5761128b613eca565b8152815461010090046001600160a01b0316602080830191909152600192830154604090920191909152918352929092019101611233565b5050509152505081526040805160808101825260048401805460ff808216151584526101008204161515602080850191909152620100009091046001600160a01b031683850152600586018054855181840281018401909652808652958201959394929360608601939260009084015b828210156113c357838290600052602060002090600202016040518060600160405290816000820160009054906101000a900460ff16600281111561137a5761137a613eca565b600281111561138b5761138b613eca565b8152815461010090046001600160a01b0316602080830191909152600192830154604090920191909152918352929092019101611333565b50505091525050905250949350505050565b6113dd6132bd565b6113e5613317565b6001600160a01b038116611425576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405147906000906001600160a01b0384169083908381818185875af1925050503d8060008114611472576040519150601f19603f3d011682016040523d82523d6000602084013e611477565b606091505b50509050806114b2576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506114be6001600055565b50565b6114c96132bd565b6001600160a01b038116611509576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004546001600160a01b0390811690821603611551576040517f62dd97a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517fb577a105c65e3df7015d800e52e963b9a45d2ccf117aded28201271748c8832490600090a250565b8060065481106116055760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b61160d6132bd565b611615613317565b6000828152600960205260409020805460ff1661194257805460ff1990811660019081178355600085815260096020526040902080548084168317825584546101009081900460ff9081161515820261ffff19938416178517808555875462010000908190048316151581027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff90921691909117855587860154958501959095556002808801805491860180549284161515988316891781558154859004909316151590930261ff0019979097169316929092179490941780825584546001600160a01b0390859004169093027fffffffffffffffffffff0000000000000000000000000000000000000000ffff9093169290921782556003808501805486959394926117459290860191613ba3565b50505060048281018054918301805460ff938416151560ff19821681178355835461010090819004909516151590940261ff001990941661ffff19909116179290921780835581546001600160a01b03620100009182900416027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909116178255600580850180549293926117dd9286019190613ba3565b5050505060028201546040517fd9caed12000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b03908116600483018190526024830152604482018690527f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce16915063d9caed1290606401600060405180830381600087803b15801561187857600080fd5b505af115801561188c573d6000803e3d6000fd5b505050506004818101546040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b036201000090920482169281018390526024810192909252604482018590527f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce169063d9caed12906064015b600060405180830381600087803b15801561192957600080fd5b505af115801561193d573d6000803e3d6000fd5b505050505b5061075c6001600055565b6119556132bd565b61195f6000613461565b565b8060065481106119b35760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b6119bb613317565b60008281526009602052604090208054610100900460ff1615611a0a576040517f864a886500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805462010000900460ff1615611a4c576040517fc3d8a04200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546201000090046001600160a01b03163314611a98576040517fb3153ae600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054620100007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff9091168117825560048201546040519190046001600160a01b031690339085907f1adcfbcfae7625b5bbaf696c3898a3f28b8d91300b9f0950d5a72abf3af79fc490600090a460028101546040517fd9caed12000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b039081166004830152336024830152604482018590527f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce169063d9caed129060640161190f565b600060608082808083611bb97f43616d627269614475656c4172656e610000000000000000000000000000001060026134cb565b611be47f310000000000000000000000000000000000000000000000000000000000000160036134cb565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b611c326132bd565b611c3a613317565b6001600160a01b038316611c7a576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f42842e0e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038481166024830152604482018390528391908216906342842e0e90606401600060405180830381600087803b158015611ce657600080fd5b505af1158015611cfa573d6000803e3d6000fd5b5050505050611d096001600055565b505050565b611d16613317565b816006548110611d685760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b600754341015611da4576040517f732f941300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dad836105cd565b341015611de6576040517f732f941300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526009602052604090205462010000900460ff1615611e35576040517fc3d8a04200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260096020526040902054610100900460ff16611e82576040517f60e178dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526009602052604090205460ff1615611ecb576040517f5f7d9fd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260096020526040902060020154610100900460ff1680611f065750600083815260096020526040902060040154610100900460ff165b15611f3d576040517f8783db4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611f6e611f686040518060400160405280878152602001336001600160a01b0316815250612417565b8461356f565b6004549091506001600160a01b03808316911614611fb8576040517f67e0646f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260096020526040902060028101546201000090046001600160a01b03163303611ff45760028101805460ff19166001179055612054565b60048101546201000090046001600160a01b031633036120225760048101805460ff19166001179055612054565b6040517f5756bdf200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805460ff1990811660019081178355600087815260096020526040902080548084168317825584546101009081900460ff9081161515820261ffff19938416178517808555875462010000908190048316151581027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff90921691909117855587860154958501959095556002808801805491860180549284161515988316891781558154859004909316151590930261ff0019979097169316929092179490941780825584546001600160a01b0390859004169093027fffffffffffffffffffff0000000000000000000000000000000000000000ffff90931692909217825560038085018054869593949261216d9290860191613ba3565b50505060048281018054918301805460ff938416151560ff19821681178355835461010090819004909516151590940261ff001990941661ffff19909116179290921780835581546001600160a01b03620100009182900416027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909116178255600580850180549293926122059286019190613ba3565b50506040513393508892507f5caaae5c6b57b49f652b073fdbcfee86d217e8071f04500c8cd368e57ffa909a9150600090a360028101546040517fd9caed12000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b039081166004830152336024830152604482018790527f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce169063d9caed1290606401600060405180830381600087803b1580156122cc57600080fd5b505af11580156122e0573d6000803e3d6000fd5b505050506004818101546040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b0362010000909204821692810192909252336024830152604482018790527f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce169063d9caed12906064015b600060405180830381600087803b15801561237c57600080fd5b505af1158015612390573d6000803e3d6000fd5b5050505050505061075c6001600055565b6123a96132bd565b61271081106123e4576040517f6cb2e31100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881905560405181907febd01212c8e07d8dfc99de72a08a3d0f4f8c05806b947a90c3c8e00129b7806590600090a250565b60006124897fe88e9621e199fc30ba59586e4e0bc08a8f9b622445f68a447c0cc0b8366d4047835160208086015160405161246e9493920192835260208301919091526001600160a01b0316604082015260600190565b60405160208183030381529060405280519060200120613593565b92915050565b6000612499613317565b81806124d1576040517f071e948200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881111561250c576040517f4f87596100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516330361254e576040517fbf6f1bf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680543491819060006125618361445a565b909155505060008181526009602052604081206002810180547fffffffffffffffffffff0000000000000000000000000000000000000000ffff163362010000021790556003018054156125e1576040517f75fd3c5400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8581101561264257818989838181106125ff576125ff614369565b83546001810185556000948552602090942060609091029290920192600202909101905061262d82826143a5565b5050808061263a9061445a565b9150506125e4565b506000838152600960205260409020815461266291600301908390613a50565b5060008381526009602052604081206004810180547fffffffffffffffffffff0000000000000000000000000000000000000000ffff16620100006001600160a01b038e16021790556001018590555b85811015612a335760008989838181106126ce576126ce614369565b6126e492602060609092020190810191506144a5565b60028111156126f5576126f5613eca565b0361278f5788888281811061270c5761270c614369565b90506060020160400135851461274e576040517ff601a14400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8215612786576040517ff544b27200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60019250612a21565b60018989838181106127a3576127a3614369565b6127b992602060609092020190810191506144a5565b60028111156127ca576127ca613eca565b036128525760008989838181106127e3576127e3614369565b90506060020160200160208101906127fb919061408d565b90506128158133308d8d87818110610b7457610b74614369565b61284c817f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce8c8c86818110610bba57610bba614369565b50612a21565b600289898381811061286657612866614369565b61287c92602060609092020190810191506144a5565b600281111561288d5761288d613eca565b03612a215760008989838181106128a6576128a6614369565b90506060020160200160208101906128be919061408d565b9050806001600160a01b03166342842e0e33308d8d878181106128e3576128e3614369565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e089901b1681526001600160a01b039687166004820152959094166024860152606002919091019190910135604483015250606401600060405180830381600087803b15801561295857600080fd5b505af115801561296c573d6000803e3d6000fd5b50505050806001600160a01b031663095ea7b37f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce8c8c868181106129b2576129b2614369565b905060600201604001356040518363ffffffff1660e01b81526004016129ed9291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b158015612a0757600080fd5b505af1158015612a1b573d6000803e3d6000fd5b50505050505b80612a2b8161445a565b9150506126b2565b5060008060007f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce6001600160a01b03166349373a198833898f8f6040518663ffffffff1660e01b8152600401612a8c94939291906144c2565b60006040518083038185885af1158015612aaa573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052612ad391908101906145dc565b9250925092508b6001600160a01b0316336001600160a01b0316877fe856d9c527bc013d9955698be44d4c7e13739fa87594a8933c0d942daf41e483868686604051612b21939291906146c2565b60405180910390a450939650505050505050612b3d6001600055565b9392505050565b612b4c6132bd565b6001600160a01b038116612b8c576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546001600160a01b0390811690821603612bd4576040517f62dd97a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f5ea4303afd5550bc5eb446bc464116608045996cc44a0d3ec3ccfa9650aa56ff90600090a250565b612c3e613317565b816006548110612c905760405162461bcd60e51b815260206004820152601260248201527f426174746c65206d757374206578697374210000000000000000000000000000604482015260640161061d565b6000838152600960205260409020805462010000900460ff1615612ce0576040517fc3d8a04200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260096020526040902054610100900460ff16612d2d576040517f60e178dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805460ff1615612d69576040517f5f7d9fd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600281015433620100009091046001600160a01b031603612dcd576002810154610100900460ff1615612dc8576040517f8783db4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e5e565b600481015433620100009091046001600160a01b031603612e2c576004810154610100900460ff1615612dc8576040517f8783db4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f38db7f2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612e8f612e896040518060400160405280888152602001336001600160a01b0316815250612417565b8561356f565b6005549091506001600160a01b03808316911614612ed9576040517fb4f0c44f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002808301805461ff0019908116610100908117835560048601805483168217905560008981526009602052604090208654815460ff918216151560ff19808316821785558a5486900484161515860291871661ffff1993841617919091178085558a5462010000908190048516151581027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff90921691909117855560018b81015490860155875498850180549985161515928a16831781558854879004909416151590950295169616959095179290921780855583546001600160a01b0390839004169091027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909116178355600380860180548795939493926130019290860191613ba3565b50505060048281018054918301805460ff938416151560ff19821681178355835461010090819004909516151590940261ff001990941661ffff19909116179290921780835581546001600160a01b03620100009182900416027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909116178255600580850180549293926130999286019190613ba3565b50506040513393508892507f8d7df0ced4aeda0e69d998705dddbf1eac70be8d7fb991edc80ddf6f29424a739150600090a360028201546040517fd9caed12000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b03908116600483018190526024830152604482018790527f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce169063d9caed1290606401600060405180830381600087803b15801561316157600080fd5b505af1158015613175573d6000803e3d6000fd5b505050506004828101546040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b036201000090920482169281018390526024810192909252604482018790527f000000000000000000000000c9438f95aa8d9ee1b5edea15c7fa4b2cac723dce169063d9caed1290606401612362565b6132046132bd565b6001600160a01b0381166132805760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161061d565b6114be81613461565b60006020835110156132a55761329e836135db565b9050612489565b816132b084826147d0565b5060ff9392505050565b90565b6001546001600160a01b0316331461195f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161061d565b6002600054036133695760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161061d565b6002600055565b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d1560016000511417166133b5576390b8ec186000526004601cfd5b6000603452505050565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d15600160005114171661340e57637939f4246000526004601cfd5b600060605260405250505050565b81601452806034526f095ea7b300000000000000000000000060005260206000604460106000875af13d1560016000511417166133b557633e3f8f736000526004601cfd5b600180546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b606060ff83146134de5761329e83613632565b8180546134ea90614735565b80601f016020809104026020016040519081016040528092919081815260200182805461351690614735565b80156135635780601f1061353857610100808354040283529160200191613563565b820191906000526020600020905b81548152906001019060200180831161354657829003601f168201915b50505050509050612489565b600080600061357e8585613671565b9150915061358b816136b6565b509392505050565b60006124896135a061381b565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b600080829050601f8151111561361f57826040517f305a27a900000000000000000000000000000000000000000000000000000000815260040161061d91906148cc565b805161362a826148df565b179392505050565b6060600061363f8361394b565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b60008082516041036136a75760208301516040840151606085015160001a61369b8782858561398c565b945094505050506136af565b506000905060025b9250929050565b60008160048111156136ca576136ca613eca565b036136d25750565b60018160048111156136e6576136e6613eca565b036137335760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161061d565b600281600481111561374757613747613eca565b036137945760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161061d565b60038160048111156137a8576137a8613eca565b036114be5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015260840161061d565b6000306001600160a01b037f000000000000000000000000c15568330926e2a6f1519992b0364ca00faf6a7a1614801561387457507f0000000000000000000000000000000000000000000000000000000000013e3146145b1561389e57507fd46e728c38c18eb1a89c4f0a8e89d44a0146840660ab185dfb2d23aa9eb8881790565b613946604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f3ed963a35bd590a6005a9cfd187471e7f8ff4daa48015921ccbad855561c627d918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b600060ff8216601f811115612489576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156139c35750600090506003613a47565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613a17573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613a4057600060019250925050613a47565b9150600090505b94509492505050565b828054828255906000526020600020906002028101928215613b055760005260206000209160020282015b82811115613b0557825482548491849160ff90911690829060ff19166001836002811115613aab57613aab613eca565b0217905550815481547fffffffffffffffffffffff0000000000000000000000000000000000000000ff16610100918290046001600160a01b03169091021781556001918201549101556002928301929190910190613a7b565b50613b11929150613c58565b5090565b6040518060c0016040528060001515815260200160001515815260200160001515815260200160008152602001613b7a604051806080016040528060001515815260200160001515815260200160006001600160a01b03168152602001606081525090565b815260408051608081018252600080825260208281018290529282015260608082015291015290565b828054828255906000526020600020906002028101928215613b055760005260206000209160020282015b82811115613b0557825482548491849160ff90911690829060ff19166001836002811115613bfe57613bfe613eca565b0217905550815481547fffffffffffffffffffffff0000000000000000000000000000000000000000ff16610100918290046001600160a01b03169091021781556001918201549101556002928301929190910190613bce565b5b80821115613b115780547fffffffffffffffffffffff00000000000000000000000000000000000000000016815560006001820155600201613c59565b6001600160a01b03811681146114be57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613d0357613d03613cab565b604052919050565b600082601f830112613d1c57600080fd5b813567ffffffffffffffff811115613d3657613d36613cab565b613d496020601f19601f84011601613cda565b818152846020838601011115613d5e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613d9157600080fd5b8435613d9c81613c96565b93506020850135613dac81613c96565b925060408501359150606085013567ffffffffffffffff811115613dcf57600080fd5b613ddb87828801613d0b565b91505092959194509250565b600060208284031215613df957600080fd5b5035919050565b60008060408385031215613e1357600080fd5b8235613e1e81613c96565b91506020830135613e2e81613c96565b809150509250929050565b60008083601f840112613e4b57600080fd5b50813567ffffffffffffffff811115613e6357600080fd5b6020830191508360206060830285010111156136af57600080fd5b600080600060408486031215613e9357600080fd5b83359250602084013567ffffffffffffffff811115613eb157600080fd5b613ebd86828701613e39565b9497909650939450505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110613f30577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6000608083018251151584526020808401511515818601526040808501516001600160a01b038082168389015260609150818701516080838a015285815180885260a08b0191508683019750600092505b80831015613fbf578751613f9a838251613ef9565b8088015185168389015286015186830152968601966001929092019190840190613f85565b509998505050505050505050565b86151581528515156020820152841515604082015283606082015260c060808201526000613ffe60c0830185613f34565b82810360a08401526140108185613f34565b9998505050505050505050565b60208152815115156020820152602082015115156040820152604082015115156060820152606082015160808201526000608083015160c060a084015261406760e0840182613f34565b905060a0840151601f198483030160c08501526140848282613f34565b95945050505050565b60006020828403121561409f57600080fd5b8135612b3d81613c96565b6000815180845260005b818110156140d0576020818501810151868301820152016140b4565b506000602082860101526020601f19601f83011685010191505092915050565b600081518084526020808501945080840160005b8381101561412057815187529582019590820190600101614104565b509495945050505050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e06020820152600061416660e08301896140aa565b828103604084015261417881896140aa565b90508660608401526001600160a01b03861660808401528460a084015282810360c08401526141a781856140f0565b9a9950505050505050505050565b6000806000606084860312156141ca57600080fd5b83356141d581613c96565b925060208401356141e581613c96565b929592945050506040919091013590565b6000806040838503121561420957600080fd5b82359150602083013567ffffffffffffffff81111561422757600080fd5b61423385828601613d0b565b9150509250929050565b60006040828403121561424f57600080fd5b6040516040810181811067ffffffffffffffff8211171561427257614272613cab565b60405282358152602083013561428781613c96565b60208201529392505050565b6000806000604084860312156142a857600080fd5b83356142b381613c96565b9250602084013567ffffffffffffffff811115613eb157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417612489576124896142cf565b60008261434b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561436257600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600381106114be57600080fd5b81356143b081614398565b600381106143e7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b815460ff821691508160ff198216178355602084013561440681613c96565b74ffffffffffffffffffffffffffffffffffffffff008160081b16837fffffffffffffffffffffff000000000000000000000000000000000000000000841617178455505050604082013560018201555050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361448b5761448b6142cf565b5060010190565b80820180821115612489576124896142cf565b6000602082840312156144b757600080fd5b8135612b3d81614398565b600060608083016001600160a01b03808916855260208881870152604084818801528388855260808801905089945060005b8981101561453d57853561450781614398565b6145118382613ef9565b508386013561451f81613c96565b851682850152858301358383015294860194908601906001016144f4565b509b9a5050505050505050505050565b600067ffffffffffffffff82111561456757614567613cab565b5060051b60200190565b600082601f83011261458257600080fd5b815160206145976145928361454d565b613cda565b82815260059290921b840181019181810190868411156145b657600080fd5b8286015b848110156145d157805183529183019183016145ba565b509695505050505050565b6000806000606084860312156145f157600080fd5b835167ffffffffffffffff8082111561460957600080fd5b61461587838801614571565b945060209150818601518181111561462c57600080fd5b8601601f8101881361463d57600080fd5b805161464b6145928261454d565b81815260059190911b8201840190848101908a83111561466a57600080fd5b928501925b8284101561469157835161468281613c96565b8252928501929085019061466f565b60408a01519097509450505050808211156146ab57600080fd5b506146b886828701614571565b9150509250925092565b6060815260006146d560608301866140f0565b82810360208481019190915285518083528682019282019060005b818110156147155784516001600160a01b0316835293830193918301916001016146f0565b5050848103604086015261472981876140f0565b98975050505050505050565b600181811c9082168061474957607f821691505b602082108103610667577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f821115611d0957600081815260208120601f850160051c810160208610156147a95750805b601f850160051c820191505b818110156147c8578281556001016147b5565b505050505050565b815167ffffffffffffffff8111156147ea576147ea613cab565b6147fe816147f88454614735565b84614782565b602080601f831160018114614851576000841561481b5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556147c8565b600085815260208120601f198616915b8281101561488057888601518255948401946001909101908401614861565b50858210156148bc57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000612b3d60208301846140aa565b80516020808301519190811015610667577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b1691905056fea2646970667358221220156769e0a178c2060aeb8c7d6387738abc8cf9ba62c1a5a21b07bac628e8d48064736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000be16d5c286aa885a2261a6b99a518e5effd2f3880000000000000000000000001d28206358d30e84f985ac6edbc6ae49f25ffa7f000000000000000000000000b0e7d4175be8e83a8075538f2dbe6f87d5a69013
-----Decoded View---------------
Arg [0] : _owner (address): 0xbE16D5c286aa885A2261a6b99A518E5eFFD2f388
Arg [1] : _judge (address): 0x1D28206358d30E84F985ac6EdbC6Ae49F25FfA7F
Arg [2] : _withdrawJudge (address): 0xB0e7d4175BE8E83a8075538f2DBe6F87d5a69013
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000be16d5c286aa885a2261a6b99a518e5effd2f388
Arg [1] : 0000000000000000000000001d28206358d30e84f985ac6edbc6ae49f25ffa7f
Arg [2] : 000000000000000000000000b0e7d4175be8e83a8075538f2dbe6f87d5a69013
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ARB | 49.61% | $2,645.76 | 0.0189 | $49.91 | |
BASE | 31.76% | $2,646.06 | 0.0121 | $31.95 | |
BLAST | 14.94% | $0.992348 | 15.1483 | $15.03 | |
BLAST | 1.13% | $2,648.45 | 0.00042802 | $1.13 | |
ZKSYNC | 1.49% | $2,647.76 | 0.00056485 | $1.5 | |
LINEA | 0.62% | $2,647.76 | 0.00023617 | $0.625312 | |
OP | 0.31% | $2,646 | 0.00011917 | $0.315327 | |
SCROLL | 0.13% | $2,647.76 | 0.00004901 | $0.129771 | |
TAIKO | <0.01% | $2,647.76 | 0.000001 | $0.00265 |
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.