Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Multi Chain
Multichain Addresses
13 addresses found via
Latest 25 from a total of 94,917 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Process Rollup | 18233647 | 23 hrs 41 mins ago | IN | 0 ETH | 0.0219384 | ||||
Process Rollup | 18219340 | 2 days 23 hrs ago | IN | 0 ETH | 0.02340426 | ||||
Process Rollup | 18205021 | 4 days 23 hrs ago | IN | 0 ETH | 0.00992126 | ||||
Process Rollup | 18190723 | 6 days 23 hrs ago | IN | 0 ETH | 0.01172484 | ||||
Process Rollup | 18176415 | 9 days 1 min ago | IN | 0 ETH | 0.01582304 | ||||
Deposit Pending ... | 18162716 | 10 days 22 hrs ago | IN | 0.014689 ETH | 0.00055037 | ||||
Process Rollup | 18162126 | 11 days 6 mins ago | IN | 0 ETH | 0.01523709 | ||||
Process Rollup | 18147980 | 13 days 11 mins ago | IN | 0 ETH | 0.01197358 | ||||
Process Rollup | 18123685 | 16 days 10 hrs ago | IN | 0 ETH | 0.01096866 | ||||
Process Rollup | 18109385 | 18 days 10 hrs ago | IN | 0 ETH | 0.0111772 | ||||
Process Rollup | 18084849 | 21 days 20 hrs ago | IN | 0 ETH | 0.01890401 | ||||
Process Rollup | 18070555 | 23 days 20 hrs ago | IN | 0 ETH | 0.01699951 | ||||
Process Rollup | 18053741 | 26 days 5 hrs ago | IN | 0 ETH | 0.0131972 | ||||
Process Rollup | 18038849 | 28 days 7 hrs ago | IN | 0 ETH | 0.01671778 | ||||
Process Rollup | 18024544 | 30 days 7 hrs ago | IN | 0 ETH | 0.02295933 | ||||
Process Rollup | 18010236 | 32 days 7 hrs ago | IN | 0 ETH | 0.0142938 | ||||
Process Rollup | 17991772 | 34 days 21 hrs ago | IN | 0 ETH | 0.02226845 | ||||
Process Rollup | 17977448 | 36 days 21 hrs ago | IN | 0 ETH | 0.01986582 | ||||
Process Rollup | 17963124 | 38 days 21 hrs ago | IN | 0 ETH | 0.02560893 | ||||
Deposit Pending ... | 17960772 | 39 days 5 hrs ago | IN | 0.01683 ETH | 0.00096929 | ||||
Process Rollup | 17948810 | 40 days 21 hrs ago | IN | 0 ETH | 0.01841847 | ||||
Process Rollup | 17921518 | 44 days 17 hrs ago | IN | 0 ETH | 0.03555073 | ||||
Process Rollup | 17907195 | 46 days 17 hrs ago | IN | 0 ETH | 0.02286816 | ||||
Process Rollup | 17892878 | 48 days 17 hrs ago | IN | 0 ETH | 0.03105232 | ||||
Process Rollup | 17866725 | 52 days 9 hrs ago | IN | 0 ETH | 0.0169858 |
Latest 25 internal transactions (View All)
Parent Txn Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
18233647 | 23 hrs 41 mins ago | 0.125811 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.00459 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.014515 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.018265 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.016715 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.013215 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.005515 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.010736 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.008976 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.008413 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.017413 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.009973 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.007413 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.006413 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.039813 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.051913 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.056413 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.045313 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.046513 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.034313 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.04588 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.02718 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.03988 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.00388 ETH | ||||
18233647 | 23 hrs 41 mins ago | 0.03674 ETH |
Loading...
Loading
Contract Name:
RollupProcessor
Compiler Version
v0.6.10+commit.00c0fcaf
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-only // Copyright 2020 Spilsbury Holdings Ltd. pragma solidity >=0.6.10 <0.8.0; import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; import {Pausable} from '@openzeppelin/contracts/utils/Pausable.sol'; import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol'; import {IVerifier} from './interfaces/IVerifier.sol'; import {IRollupProcessor} from './interfaces/IRollupProcessor.sol'; import {IFeeDistributor} from './interfaces/IFeeDistributor.sol'; import {IERC20Permit} from './interfaces/IERC20Permit.sol'; import {Decoder} from './Decoder.sol'; import './libraries/RollupProcessorLibrary.sol'; /** * @title Rollup Processor * @dev Smart contract responsible for processing Aztec zkRollups, including relaying them to a verifier * contract for validation and performing all relevant ERC20 token transfers */ contract RollupProcessor is IRollupProcessor, Decoder, Ownable, Pausable { using SafeMath for uint256; bytes32 public dataRoot = 0x2708a627d38d74d478f645ec3b4e91afa325331acf1acebe9077891146b75e39; bytes32 public nullRoot = 0x2694dbe3c71a25d92213422d392479e7b8ef437add81e1e17244462e6edca9b1; bytes32 public rootRoot = 0x2d264e93dc455751a721aead9dba9ee2a9fef5460921aeede73f63f6210e6851; uint256 public dataSize; uint256 public nextRollupId; IVerifier public verifier; uint256 public constant numberOfAssets = 4; uint256 public constant txNumPubInputs = 12; uint256 public constant rollupNumPubInputs = 10 + numberOfAssets; uint256 public constant txPubInputLength = txNumPubInputs * 32; // public inputs length for of each inner proof tx uint256 public constant rollupPubInputLength = rollupNumPubInputs * 32; uint256 public constant ethAssetId = 0; uint256 public immutable escapeBlockLowerBound; uint256 public immutable escapeBlockUpperBound; event RollupProcessed( uint256 indexed rollupId, bytes32 dataRoot, bytes32 nullRoot, bytes32 rootRoot, uint256 dataSize ); event Deposit(uint256 assetId, address depositorAddress, uint256 depositValue); event Withdraw(uint256 assetId, address withdrawAddress, uint256 withdrawValue); event WithdrawError(bytes errorReason); event AssetAdded(uint256 indexed assetId, address indexed assetAddress); event RollupProviderUpdated(address indexed providerAddress, bool valid); event VerifierUpdated(address indexed verifierAddress); // Array of supported ERC20 token address. address[] public supportedAssets; // Mapping which maps an asset address to a bool, determining whether it supports // permit as according to ERC-2612 mapping(address => bool) assetPermitSupport; // Mapping from assetId to mapping of userAddress to public userBalance stored on this contract mapping(uint256 => mapping(address => uint256)) public userPendingDeposits; mapping(address => mapping(bytes32 => bool)) public depositProofApprovals; mapping(address => bool) public rollupProviders; address public override feeDistributor; // Metrics uint256[] public totalPendingDeposit; uint256[] public totalDeposited; uint256[] public totalWithdrawn; uint256[] public totalFees; constructor( address _verifierAddress, uint256 _escapeBlockLowerBound, uint256 _escapeBlockUpperBound, address _contractOwner ) public { verifier = IVerifier(_verifierAddress); escapeBlockLowerBound = _escapeBlockLowerBound; escapeBlockUpperBound = _escapeBlockUpperBound; rollupProviders[msg.sender] = true; totalPendingDeposit.push(0); totalDeposited.push(0); totalWithdrawn.push(0); totalFees.push(0); transferOwnership(_contractOwner); } function setRollupProvider(address providerAddress, bool valid) public override onlyOwner { rollupProviders[providerAddress] = valid; emit RollupProviderUpdated(providerAddress, valid); } function setVerifier(address _verifierAddress) public override onlyOwner { verifier = IVerifier(_verifierAddress); emit VerifierUpdated(_verifierAddress); } function setFeeDistributor(address feeDistributorAddress) public override onlyOwner { feeDistributor = feeDistributorAddress; } /** * @dev Approve a proofHash for spending a users deposited funds, this is one way and must be called by the owner of the funds * @param _proofHash - keccack256 hash of the inner proof public inputs */ function approveProof(bytes32 _proofHash) public override whenNotPaused { depositProofApprovals[msg.sender][_proofHash] = true; } /** * @dev Get the ERC20 token address of a supported asset, for a given assetId * @param assetId - identifier used to denote a particular asset */ function getSupportedAsset(uint256 assetId) public view override returns (address) { if (assetId == ethAssetId) { return address(0x0); } return supportedAssets[assetId - 1]; } /** * @dev Get the addresses of all supported ERC20 tokens */ function getSupportedAssets() external view override returns (address[] memory) { return supportedAssets; } function getTotalDeposited() external view override returns (uint256[] memory) { return totalDeposited; } function getTotalWithdrawn() external view override returns (uint256[] memory) { return totalWithdrawn; } function getTotalPendingDeposit() external view override returns (uint256[] memory) { return totalPendingDeposit; } function getTotalFees() external view override returns (uint256[] memory) { return totalFees; } /** * @dev Get the status of whether an asset supports the permit ERC-2612 approval flow * @param assetId - unique identifier of the supported asset */ function getAssetPermitSupport(uint256 assetId) external view override returns (bool) { address assetAddress = getSupportedAsset(assetId); return assetPermitSupport[assetAddress]; } /** * @dev Get the status of the escape hatch, specifically retrieve whether the * hatch is open and also the number of blocks until the hatch will switch from * open to closed or vice versa */ function getEscapeHatchStatus() public view override returns (bool, uint256) { uint256 blockNum = block.number; bool isOpen = blockNum % escapeBlockUpperBound >= escapeBlockLowerBound; uint256 blocksRemaining = 0; if (isOpen) { // num blocks escape hatch will remain open for blocksRemaining = escapeBlockUpperBound - (blockNum % escapeBlockUpperBound); } else { // num blocks until escape hatch will be opened blocksRemaining = escapeBlockLowerBound - (blockNum % escapeBlockUpperBound); } return (isOpen, blocksRemaining); } /** * @dev Get the balance of a user, for a particular asset, held on the user's behalf * by this contract * @param assetId - unique identifier of the asset * @param userAddress - Ethereum address of the user who's balance is being queried */ function getUserPendingDeposit(uint256 assetId, address userAddress) external view override returns (uint256) { return userPendingDeposits[assetId][userAddress]; } /** * @dev Increase the userPendingDeposits mapping */ function increasePendingDepositBalance( uint256 assetId, address depositorAddress, uint256 amount ) internal { userPendingDeposits[assetId][depositorAddress] = userPendingDeposits[assetId][depositorAddress].add(amount); totalPendingDeposit[assetId] = totalPendingDeposit[assetId].add(amount); } /** * @dev Decrease the userPendingDeposits mapping */ function decreasePendingDepositBalance( uint256 assetId, address transferFromAddress, uint256 amount ) internal { uint256 userBalance = userPendingDeposits[assetId][transferFromAddress]; require(userBalance >= amount, 'Rollup Processor: INSUFFICIENT_DEPOSIT'); userPendingDeposits[assetId][transferFromAddress] = userBalance.sub(amount); totalPendingDeposit[assetId] = totalPendingDeposit[assetId].sub(amount); totalDeposited[assetId] = totalDeposited[assetId].add(amount); } /** * @dev Set the mapping between an assetId and the address of the linked asset. * Protected by onlyOwner * @param linkedToken - address of the asset * @param supportsPermit - bool determining whether this supports permit */ function setSupportedAsset(address linkedToken, bool supportsPermit) external override onlyOwner { require(linkedToken != address(0x0), 'Rollup Processor: ZERO_ADDRESS'); supportedAssets.push(linkedToken); assetPermitSupport[linkedToken] = supportsPermit; uint256 assetId = supportedAssets.length; require(assetId < numberOfAssets, 'Rollup Processor: MAX_ASSET_REACHED'); totalPendingDeposit.push(0); totalDeposited.push(0); totalWithdrawn.push(0); totalFees.push(0); emit AssetAdded(assetId, linkedToken); } /** * @dev Update the value indicating whether a linked asset supports permit. * Protected by onlyOwner * @param assetId - unique ID of the asset * @param supportsPermit - bool determining whether this supports permit */ function setAssetPermitSupport(uint256 assetId, bool supportsPermit) external override onlyOwner { address assetAddress = getSupportedAsset(assetId); require(assetAddress != address(0x0), 'Rollup Processor: TOKEN_ASSET_NOT_LINKED'); assetPermitSupport[assetAddress] = supportsPermit; } /** * @dev Deposit funds as part of the first stage of the two stage deposit. Non-permit flow * @param assetId - unique ID of the asset * @param amount - number of tokens being deposited * @param depositorAddress - address from which funds are being transferred to the contract */ function depositPendingFunds( uint256 assetId, uint256 amount, address depositorAddress ) external payable override whenNotPaused { if (assetId == ethAssetId) { require(msg.value == amount, 'Rollup Processor: WRONG_AMOUNT'); increasePendingDepositBalance(assetId, depositorAddress, amount); } else { require(msg.value == 0, 'Rollup Processor: WRONG_PAYMENT_TYPE'); address assetAddress = getSupportedAsset(assetId); internalDeposit(assetId, assetAddress, depositorAddress, amount); } } /** * @dev Deposit funds as part of the first stage of the two stage deposit. Permit flow * @param assetId - unique ID of the asset * @param amount - number of tokens being deposited * @param depositorAddress - address from which funds are being transferred to the contract * @param spender - address being granted approval to spend the funds * @param permitApprovalAmount - amount permit signature is approving * @param deadline - when the permit signature expires * @param v - ECDSA sig param * @param r - ECDSA sig param * @param s - ECDSA sig param */ function depositPendingFundsPermit( uint256 assetId, uint256 amount, address depositorAddress, address spender, uint256 permitApprovalAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external override whenNotPaused { address assetAddress = getSupportedAsset(assetId); IERC20Permit(assetAddress).permit(depositorAddress, spender, permitApprovalAmount, deadline, v, r, s); internalDeposit(assetId, assetAddress, depositorAddress, amount); } /** * @dev Deposit funds as part of the first stage of the two stage deposit. Non-permit flow * @param assetId - unique ID of the asset * @param assetAddress - address of the ERC20 asset * @param depositorAddress - address from which funds are being transferred to the contract * @param amount - amount being deposited */ function internalDeposit( uint256 assetId, address assetAddress, address depositorAddress, uint256 amount ) internal { // check user approved contract to transfer funds, so can throw helpful error to user uint256 rollupAllowance = IERC20(assetAddress).allowance(depositorAddress, address(this)); require(rollupAllowance >= amount, 'Rollup Processor: INSUFFICIENT_TOKEN_APPROVAL'); IERC20(assetAddress).transferFrom(depositorAddress, address(this), amount); increasePendingDepositBalance(assetId, depositorAddress, amount); emit Deposit(assetId, depositorAddress, amount); } /** * @dev Process a rollup - decode the rollup, update relevant state variables and * verify the proof * @param proofData - cryptographic proof data associated with a rollup * @param signatures - bytes array of secp256k1 ECDSA signatures, authorising a transfer of tokens * from the publicOwner for the particular inner proof in question. There is a signature for each * inner proof. * * Structure of each signature in the bytes array is: * 0x00 - 0x20 : r * 0x20 - 0x40 : s * 0x40 - 0x60 : v (in form: 0x0000....0001b for example) * * @param viewingKeys - viewingKeys for the notes submitted in the rollup. Note: not used in the logic * of the rollupProcessor contract, but called here as a convenient to place data on chain */ function escapeHatch( bytes calldata proofData, bytes calldata signatures, bytes calldata viewingKeys ) external override whenNotPaused { (bool isOpen, ) = getEscapeHatchStatus(); require(isOpen, 'Rollup Processor: ESCAPE_BLOCK_RANGE_INCORRECT'); processRollupProof(proofData, signatures, viewingKeys); } function processRollup( bytes calldata proofData, bytes calldata signatures, bytes calldata viewingKeys, bytes calldata providerSignature, address provider, address payable feeReceiver, uint256 feeLimit ) external override whenNotPaused { uint256 initialGas = gasleft(); require(rollupProviders[provider], 'Rollup Processor: UNKNOWN_PROVIDER'); bytes memory sigData = abi.encodePacked(proofData[0:rollupPubInputLength], feeReceiver, feeLimit, feeDistributor); RollupProcessorLibrary.validateSignature(keccak256(sigData), providerSignature, provider); processRollupProof(proofData, signatures, viewingKeys); transferFee(proofData); (bool success, ) = feeDistributor.call( abi.encodeWithSignature( 'reimburseGas(uint256,uint256,address)', initialGas - gasleft(), feeLimit, feeReceiver ) ); require(success, 'Rollup Processor: REIMBURSE_GAS_FAILED'); } function processRollupProof( bytes memory proofData, bytes memory signatures, bytes calldata /*viewingKeys*/ ) internal { uint256 numTxs = verifyProofAndUpdateState(proofData); processDepositsAndWithdrawals(proofData, numTxs, signatures); } /** * @dev Verify the zk proof and update the contract state variables with those provided by the rollup. * @param proofData - cryptographic zk proof data. Passed to the verifier for verification. */ function verifyProofAndUpdateState(bytes memory proofData) internal returns (uint256) { ( bytes32 newDataRoot, bytes32 newNullRoot, uint256 rollupId, uint256 rollupSize, bytes32 newRootRoot, uint256 numTxs, uint256 newDataSize ) = validateMerkleRoots(proofData); // Verify the rollup proof. // // We manually call the verifier contract via assembly. This is to prevent a // redundant copy of `proofData` into memory, which costs between 100,000 to 1,000,000 gas // depending on the rollup size! bool proof_verified = false; address verifierAddress; uint256 temp1; uint256 temp2; uint256 temp3; assembly { // Step 1: we need to insert 68 bytes of verifier 'calldata' just prior to proofData // Start by defining the start of our 'calldata'. Also grab the verifier contract address from storage let inputPtr := sub(proofData, 0x44) verifierAddress := sload(verifier_slot) // Step 2: we need to overwrite the memory between `inputPtr` and `inputPtr + 68` // we load the existing 68 bytes of memory into stack variables temp1, temp2, temp3 // Once we have called the verifier contract, we will write this data back into memory temp1 := mload(inputPtr) temp2 := mload(add(inputPtr, 0x20)) temp3 := mload(add(inputPtr, 0x40)) // Step 3: insert our calldata into memory // We call the function `verify(bytes,uint256)` // The function signature is 0xac318c5d // Calldata map is: // 0x00 - 0x04 : 0xac318c5d // 0x04 - 0x24 : 0x40 (number of bytes between 0x04 and the start of the `proofData` array at 0x44) // 0x24 - 0x44 : rollupSize // 0x44 - .... : proofData (already present in memory) mstore8(inputPtr, 0xac) mstore8(add(inputPtr, 0x01), 0x31) mstore8(add(inputPtr, 0x02), 0x8c) mstore8(add(inputPtr, 0x03), 0x5d) mstore(add(inputPtr, 0x04), 0x40) mstore(add(inputPtr, 0x24), rollupSize) // Total calldata size is proofData.length + 96 bytes (the 66 bytes we just wrote, plus the 32 byte 'length' field of proofData) let callSize := add(mload(proofData), 0x64) // Step 4: Call our verifier contract. If does not return any values, but will throw an error if the proof is not valid // i.e. verified == false if proof is not valid proof_verified := staticcall(gas(), verifierAddress, inputPtr, callSize, 0x00, 0x00) // Step 5: Restore the memory we overwrote with our 'calldata' mstore(inputPtr, temp1) mstore(add(inputPtr, 0x20), temp2) mstore(add(inputPtr, 0x40), temp3) } // Check the proof is valid! require(proof_verified, 'proof verification failed'); // Update state variables. dataRoot = newDataRoot; nullRoot = newNullRoot; nextRollupId = rollupId.add(1); rootRoot = newRootRoot; dataSize = newDataSize; emit RollupProcessed(rollupId, dataRoot, nullRoot, rootRoot, dataSize); return numTxs; } /** * @dev Extract public inputs and validate they are inline with current contract state. * @param proofData - Rollup proof data. */ function validateMerkleRoots(bytes memory proofData) internal view returns ( bytes32, bytes32, uint256, uint256, bytes32, uint256, uint256 ) { ( // Stack to deep workaround: // 0: rollupId // 1: rollupSize // 2: dataStartIndex // 3: numTxs uint256[4] memory nums, bytes32 oldDataRoot, bytes32 newDataRoot, bytes32 oldNullRoot, bytes32 newNullRoot, bytes32 oldRootRoot, bytes32 newRootRoot ) = decodeProof(proofData, numberOfAssets); // Escape hatch denominated by a rollup size of 0, which means inserting 2 new entries. nums[3] = nums[1] == 0 ? 1 : nums[1]; // Ensure we are inserting at the next subtree boundary. uint256 toInsert = nums[3].mul(2); if (dataSize % toInsert == 0) { require(nums[2] == dataSize, 'Rollup Processor: INCORRECT_DATA_START_INDEX'); } else { uint256 expected = dataSize + toInsert - (dataSize % toInsert); require(nums[2] == expected, 'Rollup Processor: INCORRECT_DATA_START_INDEX'); } // Data validation checks. require(oldDataRoot == dataRoot, 'Rollup Processor: INCORRECT_DATA_ROOT'); require(oldNullRoot == nullRoot, 'Rollup Processor: INCORRECT_NULL_ROOT'); require(oldRootRoot == rootRoot, 'Rollup Processor: INCORRECT_ROOT_ROOT'); require(nums[0] == nextRollupId, 'Rollup Processor: ID_NOT_SEQUENTIAL'); return (newDataRoot, newNullRoot, nums[0], nums[1], newRootRoot, nums[3], nums[2] + toInsert); } /** * @dev Process deposits and withdrawls. * @param proofData - the proof data * @param numTxs - number of transactions rolled up in the proof * @param signatures - bytes array of secp256k1 ECDSA signatures, authorising a transfer of tokens */ function processDepositsAndWithdrawals( bytes memory proofData, uint256 numTxs, bytes memory signatures ) internal { uint256 sigIndex = 0x00; uint256 proofDataPtr; assembly { proofDataPtr := add(proofData, 0x20) // add 0x20 to skip over 1st field in bytes array (the length field) } proofDataPtr += rollupPubInputLength; // update pointer to skip over rollup public inputs and point to inner tx public inputs uint256 end = proofDataPtr + (numTxs * txPubInputLength); uint256 stepSize = txPubInputLength; // This is a bit of a hot loop, we iterate over every tx to determine whether to process deposits or withdrawals. while (proofDataPtr < end) { // extract the minimum information we need to determine whether to skip this iteration uint256 proofId; uint256 publicInput; uint256 publicOutput; bool txNeedsProcessing; assembly { proofId := mload(proofDataPtr) publicInput := mload(add(proofDataPtr, 0x20)) publicOutput := mload(add(proofDataPtr, 0x40)) // only process deposits and withdrawals iff // the proofId == 0 (not an account proof) and publicInput > 0 OR publicOutput > 0 txNeedsProcessing := and(iszero(proofId), or(not(iszero(publicInput)), not(iszero(publicOutput)))) } if (txNeedsProcessing) { // extract asset Id uint256 assetId; assembly { assetId := mload(add(proofDataPtr, 0x60)) } if (publicInput > 0) { // validate user has approved deposit address inputOwner; bytes32 digest; assembly { inputOwner := mload(add(proofDataPtr, 0x140)) // compute the message digest to check if user has approved tx digest := keccak256(proofDataPtr, stepSize) } if (!depositProofApprovals[inputOwner][digest]) { // extract and validate signature // we can create a bytes memory container for the signature without allocating new memory, // by overwriting the previous 32 bytes in the `signatures` array with the 'length' of our synthetic byte array (92) // we store the memory we overwrite in `temp`, so that we can restore it bytes memory signature; uint256 temp; assembly { // set `signature` to point to 32 bytes less than the desired `r, s, v` values in `signatures` signature := add(signatures, sigIndex) // cache the memory we're about to overwrite temp := mload(signature) // write in a 92-byte 'length' parameter into the `signature` bytes array mstore(signature, 0x60) } // validate the signature RollupProcessorLibrary.validateUnpackedSignature(digest, signature, inputOwner); // restore the memory we overwrote assembly { mstore(signature, temp) sigIndex := add(sigIndex, 0x60) } } decreasePendingDepositBalance(assetId, inputOwner, publicInput); } if (publicOutput > 0) { address outputOwner; assembly { outputOwner := mload(add(proofDataPtr, 0x160)) } withdraw(publicOutput, outputOwner, assetId); } } proofDataPtr += txPubInputLength; } } function transferFee(bytes memory proofData) internal { for (uint256 i = 0; i < numberOfAssets; ++i) { uint256 txFee = extractTotalTxFee(proofData, i); if (txFee > 0) { bool success; if (i == ethAssetId) { (success, ) = payable(feeDistributor).call{value: txFee}(''); } else { address assetAddress = getSupportedAsset(i); IERC20(assetAddress).approve(feeDistributor, txFee); (success, ) = feeDistributor.call(abi.encodeWithSignature('deposit(uint256,uint256)', i, txFee)); } require(success, 'Rollup Processor: DEPOSIT_TX_FEE_FAILED'); totalFees[i] = totalFees[i].add(txFee); } } } /** * @dev Internal utility function to withdraw funds from the contract to a receiver address * @param withdrawValue - value being withdrawn from the contract * @param receiverAddress - address receiving public ERC20 tokens * @param assetId - ID of the asset for which a withdrawl is being performed */ function withdraw( uint256 withdrawValue, address receiverAddress, uint256 assetId ) internal { require(receiverAddress != address(0), 'Rollup Processor: ZERO_ADDRESS'); if (assetId == 0) { // We explicitly do not throw if this call fails, as this opens up the possiblity of // griefing attacks, as engineering a failed withdrawal will invalidate an entire rollup block payable(receiverAddress).call{gas: 30000, value: withdrawValue}(''); } else { address assetAddress = getSupportedAsset(assetId); IERC20(assetAddress).transfer(receiverAddress, withdrawValue); } totalWithdrawn[assetId] = totalWithdrawn[assetId].add(withdrawValue); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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 () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = 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"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor () internal { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: GPL-2.0-only // Copyright 2020 Spilsbury Holdings Ltd pragma solidity >=0.6.10 <0.8.0; interface IVerifier { function verify(bytes memory serialized_proof, uint256 _keyId) external; }
// SPDX-License-Identifier: GPL-2.0-only // Copyright 2020 Spilsbury Holdings Ltd pragma solidity >=0.6.10 <0.8.0; interface IRollupProcessor { function feeDistributor() external view returns (address); function escapeHatch( bytes calldata proofData, bytes calldata signatures, bytes calldata viewingKeys ) external; function processRollup( bytes calldata proofData, bytes calldata signatures, bytes calldata viewingKeys, bytes calldata providerSignature, address provider, address payable feeReceiver, uint256 feeLimit ) external; function depositPendingFunds( uint256 assetId, uint256 amount, address owner ) external payable; function depositPendingFundsPermit( uint256 assetId, uint256 amount, address owner, address spender, uint256 permitApprovalAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function setRollupProvider(address provderAddress, bool valid) external; function approveProof(bytes32 _proofHash) external; function setFeeDistributor(address feeDistributorAddress) external; function setVerifier(address verifierAddress) external; function setSupportedAsset(address linkedToken, bool supportsPermit) external; function setAssetPermitSupport(uint256 assetId, bool supportsPermit) external; function getSupportedAsset(uint256 assetId) external view returns (address); function getSupportedAssets() external view returns (address[] memory); function getTotalDeposited() external view returns (uint256[] memory); function getTotalWithdrawn() external view returns (uint256[] memory); function getTotalPendingDeposit() external view returns (uint256[] memory); function getTotalFees() external view returns (uint256[] memory); function getAssetPermitSupport(uint256 assetId) external view returns (bool); function getEscapeHatchStatus() external view returns (bool, uint256); function getUserPendingDeposit(uint256 assetId, address userAddress) external view returns (uint256); }
// SPDX-License-Identifier: GPL-2.0-only // Copyright 2020 Spilsbury Holdings Ltd pragma solidity >=0.6.10 <0.8.0; interface IFeeDistributor { event FeeReimbursed(address receiver, uint256 amount); function txFeeBalance(uint256 assetId) external view returns (uint256); function deposit(uint256 assetId, uint256 amount) external payable returns (uint256 depositedAmount); function reimburseGas( uint256 gasUsed, uint256 feeLimit, address payable feeReceiver ) external returns (uint256 reimbursement); }
// SPDX-License-Identifier: GPL-2.0-only // Copyright 2020 Spilsbury Holdings Ltd pragma solidity >=0.6.10 <0.8.0; import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; interface IERC20Permit is IERC20 { function nonces(address user) external view returns (uint256); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: GPL-2.0-only // Copyright 2020 Spilsbury Holdings Ltd pragma solidity >=0.6.10 <0.8.0; import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol'; import {Types} from './verifier/cryptography/Types.sol'; import {Bn254Crypto} from './verifier/cryptography/Bn254Crypto.sol'; contract Decoder { using SafeMath for uint256; /** * @dev Decode the public inputs component of proofData. Required to update state variables * @param proofData - cryptographic proofData associated with a rollup */ function decodeProof(bytes memory proofData, uint256 numberOfAssets) internal pure returns ( uint256[4] memory nums, bytes32 oldDataRoot, bytes32 newDataRoot, bytes32 oldNullRoot, bytes32 newNullRoot, bytes32 oldRootRoot, bytes32 newRootRoot ) { uint256 rollupId; uint256 rollupSize; uint256 dataStartIndex; uint256 numTxs; assembly { let dataStart := add(proofData, 0x20) // jump over first word, it's length of data rollupId := mload(dataStart) rollupSize := mload(add(dataStart, 0x20)) dataStartIndex := mload(add(dataStart, 0x40)) oldDataRoot := mload(add(dataStart, 0x60)) newDataRoot := mload(add(dataStart, 0x80)) oldNullRoot := mload(add(dataStart, 0xa0)) newNullRoot := mload(add(dataStart, 0xc0)) oldRootRoot := mload(add(dataStart, 0xe0)) newRootRoot := mload(add(dataStart, 0x100)) numTxs := mload(add(add(dataStart, 0x120), mul(0x20, numberOfAssets))) } return ( [rollupId, rollupSize, dataStartIndex, numTxs], oldDataRoot, newDataRoot, oldNullRoot, newNullRoot, oldRootRoot, newRootRoot ); } function extractTotalTxFee(bytes memory proofData, uint256 assetId) internal pure returns (uint256) { uint256 totalTxFee; assembly { totalTxFee := mload(add(add(proofData, 0x140), mul(0x20, assetId))) } return totalTxFee; } }
// SPDX-License-Identifier: GPL-2.0-only // Copyright 2020 Spilsbury Holdings Ltd pragma solidity >=0.6.10 <0.8.0; library RollupProcessorLibrary { /** * Extracts the address of the signer with ECDSA. Performs checks on `s` and `v` to * to prevent signature malleability based attacks * @param digest - Hashed data being signed over. * @param signature - ECDSA signature over the secp256k1 elliptic curve. * @param signer - Address that signs the signature. */ function validateSignature( bytes32 digest, bytes memory signature, address signer ) internal view { bool result; address recoveredSigner = address(0x0); require(signer != address(0x0), 'validateSignature: ZERO_ADDRESS'); // prepend "\x19Ethereum Signed Message:\n32" to the digest to create the signed message bytes32 message; assembly { mstore(0, "\x19Ethereum Signed Message:\n32") mstore(add(0, 28), digest) message := keccak256(0, 60) } assembly { let mPtr := mload(0x40) let byteLength := mload(signature) // store the signature digest mstore(mPtr, message) // load 'v' - we need it for a condition check // add 0x60 to jump over 3 words - length of bytes array, r and s let v := shr(248, mload(add(signature, 0x60))) // bitshifting, to resemble padLeft let s := mload(add(signature, 0x40)) /** * Original memory map for input to precompile * * signature : signature + 0x20 message * signature + 0x20 : signature + 0x40 r * signature + 0x40 : signature + 0x60 s * signature + 0x60 : signature + 0x80 v * Desired memory map for input to precompile * * signature : signature + 0x20 message * signature + 0x20 : signature + 0x40 v * signature + 0x40 : signature + 0x60 r * signature + 0x60 : signature + 0x80 s */ // store s mstore(add(mPtr, 0x60), s) // store r mstore(add(mPtr, 0x40), mload(add(signature, 0x20))) // store v mstore(add(mPtr, 0x20), v) result := and( and( // validate s is in lower half order lt(s, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1), and( // validate signature length == 0x41 eq(byteLength, 0x41), // validate v == 27 or v == 28 or(eq(v, 27), eq(v, 28)) ) ), // validate call to ecrecover precompile succeeds staticcall(gas(), 0x01, mPtr, 0x80, mPtr, 0x20) ) // save the recoveredSigner only if the first word in signature is not `message` anymore switch eq(message, mload(mPtr)) case 0 { recoveredSigner := mload(mPtr) } mstore(mPtr, byteLength) // and put the byte length back where it belongs // validate that recoveredSigner is not address(0x00) result := and(result, not(iszero(recoveredSigner))) } require(result, 'validateSignature: signature recovery failed'); require(recoveredSigner == signer, 'validateSignature: INVALID_SIGNATURE'); } /** * Extracts the address of the signer with ECDSA. Performs checks on `s` and `v` to * to prevent signature malleability based attacks * This 'Unpacked' version expects 'signature' to be a 92-byte array. * i.e. the `v` parameter occupies a full 32 bytes of memory, not 1 byte * @param digest - Hashed data being signed over. * @param signature - ECDSA signature over the secp256k1 elliptic curve. * @param signer - Address that signs the signature. */ function validateUnpackedSignature( bytes32 digest, bytes memory signature, address signer ) internal view { bool result; address recoveredSigner = address(0x0); require(signer != address(0x0), 'validateSignature: ZERO_ADDRESS'); // prepend "\x19Ethereum Signed Message:\n32" to the digest to create the signed message bytes32 message; assembly { mstore(0, "\x19Ethereum Signed Message:\n32") mstore(28, digest) message := keccak256(0, 60) } assembly { // There's a little trick we can pull. We expect `signature` to be a byte array, of length 0x60, with // 'v', 'r' and 's' located linearly in memory. Preceeding this is the length parameter of `signature`. // We *replace* the length param with the signature msg to get a memory block formatted for the precompile // load length as a temporary variable // N.B. we mutate the signature by re-ordering r, s, and v! let byteLength := mload(signature) // store the signature digest mstore(signature, message) // load 'v' - we need it for a condition check // add 0x60 to jump over 3 words - length of bytes array, r and s let v := mload(add(signature, 0x60)) let s := mload(add(signature, 0x40)) /** * Original memory map for input to precompile * * signature : signature + 0x20 message * signature + 0x20 : signature + 0x40 r * signature + 0x40 : signature + 0x60 s * signature + 0x60 : signature + 0x80 v * Desired memory map for input to precompile * * signature : signature + 0x20 message * signature + 0x20 : signature + 0x40 v * signature + 0x40 : signature + 0x60 r * signature + 0x60 : signature + 0x80 s */ // move s to v position mstore(add(signature, 0x60), s) // move r to s position mstore(add(signature, 0x40), mload(add(signature, 0x20))) // move v to r position mstore(add(signature, 0x20), v) result := and( and( // validate s is in lower half order lt(s, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1), and( // validate signature length == 0x60 (unpacked) eq(byteLength, 0x60), // validate v == 27 or v == 28 or(eq(v, 27), eq(v, 28)) ) ), // validate call to ecrecover precompile succeeds staticcall(gas(), 0x01, signature, 0x80, signature, 0x20) ) // save the recoveredSigner only if the first word in signature is not `message` anymore switch eq(message, mload(signature)) case 0 { recoveredSigner := mload(signature) } mstore(signature, byteLength) // and put the byte length back where it belongs // validate that recoveredSigner is not address(0x00) result := and(result, not(iszero(recoveredSigner))) } require(result, 'validateSignature: signature recovery failed'); require(recoveredSigner == signer, 'validateSignature: INVALID_SIGNATURE'); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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 GSN 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 payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: GPL-2.0-only // Copyright 2020 Spilsbury Holdings Ltd pragma solidity >=0.6.0 <0.8.0; pragma experimental ABIEncoderV2; /** * @title Bn254Crypto library used for the fr, g1 and g2 point types * @dev Used to manipulate fr, g1, g2 types, perform modular arithmetic on them and call * the precompiles add, scalar mul and pairing * * Notes on optimisations * 1) Perform addmod, mulmod etc. in assembly - removes the check that Solidity performs to confirm that * the supplied modulus is not 0. This is safe as the modulus's used (r_mod, q_mod) are hard coded * inside the contract and not supplied by the user */ library Types { uint256 constant PROGRAM_WIDTH = 4; uint256 constant NUM_NU_CHALLENGES = 11; uint256 constant coset_generator0 = 0x0000000000000000000000000000000000000000000000000000000000000005; uint256 constant coset_generator1 = 0x0000000000000000000000000000000000000000000000000000000000000006; uint256 constant coset_generator2 = 0x0000000000000000000000000000000000000000000000000000000000000007; // TODO: add external_coset_generator() method to compute this uint256 constant coset_generator7 = 0x000000000000000000000000000000000000000000000000000000000000000c; struct G1Point { uint256 x; uint256 y; } // G2 group element where x \in Fq2 = x0 * z + x1 struct G2Point { uint256 x0; uint256 x1; uint256 y0; uint256 y1; } // N>B. Do not re-order these fields! They must appear in the same order as they // appear in the proof data struct Proof { G1Point W1; G1Point W2; G1Point W3; G1Point W4; G1Point Z; G1Point T1; G1Point T2; G1Point T3; G1Point T4; uint256 w1; uint256 w2; uint256 w3; uint256 w4; uint256 sigma1; uint256 sigma2; uint256 sigma3; uint256 q_arith; uint256 q_ecc; uint256 q_c; uint256 linearization_polynomial; uint256 grand_product_at_z_omega; uint256 w1_omega; uint256 w2_omega; uint256 w3_omega; uint256 w4_omega; G1Point PI_Z; G1Point PI_Z_OMEGA; G1Point recursive_P1; G1Point recursive_P2; uint256 quotient_polynomial_eval; } struct ChallengeTranscript { uint256 alpha_base; uint256 alpha; uint256 zeta; uint256 beta; uint256 gamma; uint256 u; uint256 v0; uint256 v1; uint256 v2; uint256 v3; uint256 v4; uint256 v5; uint256 v6; uint256 v7; uint256 v8; uint256 v9; uint256 v10; } struct VerificationKey { uint256 circuit_size; uint256 num_inputs; uint256 work_root; uint256 domain_inverse; uint256 work_root_inverse; G1Point Q1; G1Point Q2; G1Point Q3; G1Point Q4; G1Point Q5; G1Point QM; G1Point QC; G1Point QARITH; G1Point QECC; G1Point QRANGE; G1Point QLOGIC; G1Point SIGMA1; G1Point SIGMA2; G1Point SIGMA3; G1Point SIGMA4; bool contains_recursive_proof; uint256 recursive_proof_indices; G2Point g2_x; // zeta challenge raised to the power of the circuit size. // Not actually part of the verification key, but we put it here to prevent stack depth errors uint256 zeta_pow_n; } }
// SPDX-License-Identifier: GPL-2.0-only // Copyright 2020 Spilsbury Holdings Ltd pragma solidity >=0.6.0 <0.8.0; pragma experimental ABIEncoderV2; import {Types} from "./Types.sol"; /** * @title Bn254 elliptic curve crypto * @dev Provides some basic methods to compute bilinear pairings, construct group elements and misc numerical methods */ library Bn254Crypto { uint256 constant p_mod = 21888242871839275222246405745257275088696311157297823662689037894645226208583; uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Perform a modular exponentiation. This method is ideal for small exponents (~64 bits or less), as // it is cheaper than using the pow precompile function pow_small( uint256 base, uint256 exponent, uint256 modulus ) internal pure returns (uint256) { uint256 result = 1; uint256 input = base; uint256 count = 1; assembly { let endpoint := add(exponent, 0x01) for {} lt(count, endpoint) { count := add(count, count) } { if and(exponent, count) { result := mulmod(result, input, modulus) } input := mulmod(input, input, modulus) } } return result; } function invert(uint256 fr) internal view returns (uint256) { uint256 output; bool success; uint256 p = r_mod; assembly { let mPtr := mload(0x40) mstore(mPtr, 0x20) mstore(add(mPtr, 0x20), 0x20) mstore(add(mPtr, 0x40), 0x20) mstore(add(mPtr, 0x60), fr) mstore(add(mPtr, 0x80), sub(p, 2)) mstore(add(mPtr, 0xa0), p) success := staticcall(gas(), 0x05, mPtr, 0xc0, 0x00, 0x20) output := mload(0x00) } require(success, "pow precompile call failed!"); return output; } function new_g1(uint256 x, uint256 y) internal pure returns (Types.G1Point memory) { uint256 xValue; uint256 yValue; assembly { xValue := mod(x, r_mod) yValue := mod(y, r_mod) } return Types.G1Point(xValue, yValue); } function new_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1) internal pure returns (Types.G2Point memory) { return Types.G2Point(x0, x1, y0, y1); } function P1() internal pure returns (Types.G1Point memory) { return Types.G1Point(1, 2); } function P2() internal pure returns (Types.G2Point memory) { return Types.G2Point({ x0: 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2, x1: 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed, y0: 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b, y1: 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa }); } /// Evaluate the following pairing product: /// e(a1, a2).e(-b1, b2) == 1 function pairingProd2( Types.G1Point memory a1, Types.G2Point memory a2, Types.G1Point memory b1, Types.G2Point memory b2 ) internal view returns (bool) { validateG1Point(a1); validateG1Point(b1); bool success; uint256 out; assembly { let mPtr := mload(0x40) mstore(mPtr, mload(a1)) mstore(add(mPtr, 0x20), mload(add(a1, 0x20))) mstore(add(mPtr, 0x40), mload(a2)) mstore(add(mPtr, 0x60), mload(add(a2, 0x20))) mstore(add(mPtr, 0x80), mload(add(a2, 0x40))) mstore(add(mPtr, 0xa0), mload(add(a2, 0x60))) mstore(add(mPtr, 0xc0), mload(b1)) mstore(add(mPtr, 0xe0), mload(add(b1, 0x20))) mstore(add(mPtr, 0x100), mload(b2)) mstore(add(mPtr, 0x120), mload(add(b2, 0x20))) mstore(add(mPtr, 0x140), mload(add(b2, 0x40))) mstore(add(mPtr, 0x160), mload(add(b2, 0x60))) success := staticcall( gas(), 8, mPtr, 0x180, 0x00, 0x20 ) out := mload(0x00) } require(success, "Pairing check failed!"); return (out != 0); } /** * validate the following: * x != 0 * y != 0 * x < p * y < p * y^2 = x^3 + 3 mod p */ function validateG1Point(Types.G1Point memory point) internal pure { bool is_well_formed; uint256 p = p_mod; assembly { let x := mload(point) let y := mload(add(point, 0x20)) is_well_formed := and( and( and(lt(x, p), lt(y, p)), not(or(iszero(x), iszero(y))) ), eq(mulmod(y, y, p), addmod(mulmod(x, mulmod(x, x, p), p), 3, p)) ) } require(is_well_formed, "Bn254: G1 point not on curve, or is malformed"); } }
{ "evmVersion": "istanbul", "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_verifierAddress","type":"address"},{"internalType":"uint256","name":"_escapeBlockLowerBound","type":"uint256"},{"internalType":"uint256","name":"_escapeBlockUpperBound","type":"uint256"},{"internalType":"address","name":"_contractOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"}],"name":"AssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":false,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositValue","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rollupId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"dataRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"nullRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"rootRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"dataSize","type":"uint256"}],"name":"RollupProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"providerAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"valid","type":"bool"}],"name":"RollupProviderUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"verifierAddress","type":"address"}],"name":"VerifierUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":false,"internalType":"address","name":"withdrawAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawValue","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"errorReason","type":"bytes"}],"name":"WithdrawError","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_proofHash","type":"bytes32"}],"name":"approveProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dataRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dataSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"depositorAddress","type":"address"}],"name":"depositPendingFunds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"depositorAddress","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"permitApprovalAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"depositPendingFundsPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"depositProofApprovals","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"escapeBlockLowerBound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"escapeBlockUpperBound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"proofData","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"internalType":"bytes","name":"viewingKeys","type":"bytes"}],"name":"escapeHatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ethAssetId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeDistributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"}],"name":"getAssetPermitSupport","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEscapeHatchStatus","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"}],"name":"getSupportedAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedAssets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalDeposited","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFees","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalPendingDeposit","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalWithdrawn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"address","name":"userAddress","type":"address"}],"name":"getUserPendingDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextRollupId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nullRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numberOfAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"proofData","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"internalType":"bytes","name":"viewingKeys","type":"bytes"},{"internalType":"bytes","name":"providerSignature","type":"bytes"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"address payable","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeLimit","type":"uint256"}],"name":"processRollup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollupNumPubInputs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rollupProviders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rollupPubInputLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"bool","name":"supportsPermit","type":"bool"}],"name":"setAssetPermitSupport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeDistributorAddress","type":"address"}],"name":"setFeeDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"providerAddress","type":"address"},{"internalType":"bool","name":"valid","type":"bool"}],"name":"setRollupProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"linkedToken","type":"address"},{"internalType":"bool","name":"supportsPermit","type":"bool"}],"name":"setSupportedAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_verifierAddress","type":"address"}],"name":"setVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"supportedAssets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalDeposited","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalPendingDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalWithdrawn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"txNumPubInputs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"txPubInputLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userPendingDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"contract IVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040527f2708a627d38d74d478f645ec3b4e91afa325331acf1acebe9077891146b75e396001557f2694dbe3c71a25d92213422d392479e7b8ef437add81e1e17244462e6edca9b16002557f2d264e93dc455751a721aead9dba9ee2a9fef5460921aeede73f63f6210e68516003553480156200007d57600080fd5b50604051620036763803806200367683398181016040526080811015620000a357600080fd5b50805160208201516040830151606090930151919290916000620000cf6001600160e01b036200022416565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062003656833981519152908290a3506000805460ff60a01b19168155600680546001600160a01b0319166001600160a01b038716179055608084905260a0839052338152600b60205260408120805460ff19166001908117909155600d80548083019091557fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb501829055600e80548083019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01829055600f80548083019091557f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac8020182905560108054918201815582527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae67201556200021a8162000228565b5050505062000353565b3390565b6200023b6001600160e01b036200022416565b6001600160a01b0316620002576001600160e01b036200034416565b6001600160a01b031614620002b3576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116620002fa5760405162461bcd60e51b8152600401808060200182810382526026815260200180620036306026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216916000805160206200365683398151915291a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031690565b60805160a05161329b6200039560003980611651528061168752806116b152806116da5280611a4f5250806115b152806116305280611704525061329b6000f3fe60806040526004361061027d5760003560e01c806394401d751161014f578063d1d2d95e116100c1578063e5406dbf1161007a578063e5406dbf14610b13578063e70626e614610b28578063edf49c0914610b3d578063ef76e2ee14610b52578063f0e7e29b14610b8d578063f2fde38b14610ba25761027d565b8063d1d2d95e14610a39578063d28bbda514610a6b578063d6ae328414610a95578063d8ba363714610abf578063e059d80714610ad4578063e393635514610ae95761027d565b8063b68ef55911610113578063b68ef55914610852578063be71f8a414610867578063c68dbb3714610897578063c6c62390146108c1578063ccfc2e8d146108eb578063d1c652641461091e5761027d565b806394401d75146107b0578063a009f7e4146107c5578063a3d205f4146107ef578063ae35bfc214610828578063b045009c1461083d5761027d565b80635437988d116101f35780636dff3584116101ac5780636dff3584146106e8578063715018a6146106fd578063781e04321461071257806389404a791461074b5780638da5cb5b1461076057806391dfe78f146107755761027d565b80635437988d146106055780635ad1def3146106385780635c975abb1461067f57806360a8b18a14610694578063626e1ae7146106be57806366535f30146106d35761027d565b806336ce0a921161024557806336ce0a92146104e1578063408ccbdf1461051a57806344c5125214610544578063479b3d951461055957806347a695a71461058b57806349ce468d146105f05761027d565b8063018892ac1461028257806306011a46146102f05780630d43e8ad146104745780632b7ac3f3146104a55780633248295f146104ba575b600080fd5b34801561028e57600080fd5b506102ee60048036036101208110156102a657600080fd5b508035906020810135906001600160a01b03604082013581169160608101359091169060808101359060a08101359060ff60c0820135169060e0810135906101000135610bd5565b005b3480156102fc57600080fd5b506102ee600480360360e081101561031357600080fd5b810190602081018135600160201b81111561032d57600080fd5b82018360208201111561033f57600080fd5b803590602001918460018302840111600160201b8311171561036057600080fd5b919390929091602081019035600160201b81111561037d57600080fd5b82018360208201111561038f57600080fd5b803590602001918460018302840111600160201b831117156103b057600080fd5b919390929091602081019035600160201b8111156103cd57600080fd5b8201836020820111156103df57600080fd5b803590602001918460018302840111600160201b8311171561040057600080fd5b919390929091602081019035600160201b81111561041d57600080fd5b82018360208201111561042f57600080fd5b803590602001918460018302840111600160201b8311171561045057600080fd5b91935091506001600160a01b03813581169160208101359091169060400135610cd8565b34801561048057600080fd5b5061048961106c565b604080516001600160a01b039092168252519081900360200190f35b3480156104b157600080fd5b5061048961107b565b3480156104c657600080fd5b506104cf61108a565b60408051918252519081900360200190f35b3480156104ed57600080fd5b506104cf6004803603604081101561050457600080fd5b50803590602001356001600160a01b0316611090565b34801561052657600080fd5b506104cf6004803603602081101561053d57600080fd5b50356110ad565b34801561055057600080fd5b506104cf6110cb565b34801561056557600080fd5b506102ee6004803603604081101561057c57600080fd5b508035906020013515156110d0565b34801561059757600080fd5b506105a06111ad565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156105dc5781810151838201526020016105c4565b505050509050019250505060405180910390f35b3480156105fc57600080fd5b506104cf611205565b34801561061157600080fd5b506102ee6004803603602081101561062857600080fd5b50356001600160a01b031661120b565b34801561064457600080fd5b5061066b6004803603602081101561065b57600080fd5b50356001600160a01b03166112b7565b604080519115158252519081900360200190f35b34801561068b57600080fd5b5061066b6112cc565b3480156106a057600080fd5b50610489600480360360208110156106b757600080fd5b50356112dc565b3480156106ca57600080fd5b506105a0611318565b3480156106df57600080fd5b506104cf61136e565b3480156106f457600080fd5b506104cf611374565b34801561070957600080fd5b506102ee61137a565b34801561071e57600080fd5b5061066b6004803603604081101561073557600080fd5b506001600160a01b038135169060200135611426565b34801561075757600080fd5b506105a0611446565b34801561076c57600080fd5b5061048961149c565b34801561078157600080fd5b506102ee6004803603604081101561079857600080fd5b506001600160a01b03813516906020013515156114ab565b3480156107bc57600080fd5b506104cf61156d565b3480156107d157600080fd5b506104cf600480360360208110156107e857600080fd5b5035611573565b3480156107fb57600080fd5b506104cf6004803603604081101561081257600080fd5b50803590602001356001600160a01b0316611580565b34801561083457600080fd5b506104cf6115aa565b34801561084957600080fd5b506104cf6115af565b34801561085e57600080fd5b506105a06115d3565b34801561087357600080fd5b5061087c611629565b60408051921515835260208301919091528051918290030190f35b3480156108a357600080fd5b50610489600480360360208110156108ba57600080fd5b5035611731565b3480156108cd57600080fd5b506104cf600480360360208110156108e457600080fd5b5035611758565b3480156108f757600080fd5b506102ee6004803603602081101561090e57600080fd5b50356001600160a01b0316611765565b34801561092a57600080fd5b506102ee6004803603606081101561094157600080fd5b810190602081018135600160201b81111561095b57600080fd5b82018360208201111561096d57600080fd5b803590602001918460018302840111600160201b8311171561098e57600080fd5b919390929091602081019035600160201b8111156109ab57600080fd5b8201836020820111156109bd57600080fd5b803590602001918460018302840111600160201b831117156109de57600080fd5b919390929091602081019035600160201b8111156109fb57600080fd5b820183602082011115610a0d57600080fd5b803590602001918460018302840111600160201b83111715610a2e57600080fd5b5090925090506117e9565b6102ee60048036036060811015610a4f57600080fd5b50803590602081013590604001356001600160a01b03166118ff565b348015610a7757600080fd5b5061066b60048036036020811015610a8e57600080fd5b5035611a12565b348015610aa157600080fd5b506104cf60048036036020811015610ab857600080fd5b5035611a40565b348015610acb57600080fd5b506104cf611a4d565b348015610ae057600080fd5b506104cf611a71565b348015610af557600080fd5b506102ee60048036036020811015610b0c57600080fd5b5035611a77565b348015610b1f57600080fd5b506105a0611aea565b348015610b3457600080fd5b506104cf611b4b565b348015610b4957600080fd5b506104cf611b50565b348015610b5e57600080fd5b506102ee60048036036040811015610b7557600080fd5b506001600160a01b0381351690602001351515611b55565b348015610b9957600080fd5b506104cf611db2565b348015610bae57600080fd5b506102ee60048036036020811015610bc557600080fd5b50356001600160a01b0316611db8565b610bdd6112cc565b15610c22576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000610c2d8a6112dc565b6040805163d505accf60e01b81526001600160a01b038b811660048301528a81166024830152604482018a90526064820189905260ff8816608483015260a4820187905260c4820186905291519293509083169163d505accf9160e48082019260009290919082900301818387803b158015610ca857600080fd5b505af1158015610cbc573d6000803e3d6000fd5b50505050610ccc8a828a8c611eba565b50505050505050505050565b610ce06112cc565b15610d25576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60005a6001600160a01b0385166000908152600b602052604090205490915060ff16610d825760405162461bcd60e51b815260040180806020018281038252602281526020018061302f6022913960400191505060405180910390fd5b60608c8c6000906004600a0160200292610d9e93929190612f69565b600c54604051879187916001600160a01b03909116906020018086868082843780830192505050846001600160a01b03166001600160a01b031660601b8152601401838152602001826001600160a01b03166001600160a01b031660601b8152601401955050505050506040516020818303038152906040529050610e62818051906020012088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612058915050565b610eea8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508d91506122019050565b610f298d8d8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061222092505050565b600c546000906001600160a01b03165a604080519186036024830152604482018790526001600160a01b03881660648084019190915281518084039091018152608490920181526020820180516001600160e01b03166356aa719960e01b17815290518251909182918083835b60208310610fb55780518252601f199092019160209182019101610f96565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611017576040519150601f19603f3d011682016040523d82523d6000602084013e61101c565b606091505b505090508061105c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612fe66026913960400191505060405180910390fd5b5050505050505050505050505050565b600c546001600160a01b031681565b6006546001600160a01b031681565b60035481565b600960209081526000928352604080842090915290825290205481565b601081815481106110ba57fe5b600091825260209091200154905081565b600e81565b6110d86124ab565b6001600160a01b03166110e961149c565b6001600160a01b031614611132576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600061113d836112dc565b90506001600160a01b0381166111845760405162461bcd60e51b81526004018080602001828103825260288152602001806130a96028913960400191505060405180910390fd5b6001600160a01b03166000908152600860205260409020805460ff191691151591909117905550565b6060600d8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020905b8154815260200190600101908083116111e7575b5050505050905090565b60045481565b6112136124ab565b6001600160a01b031661122461149c565b6001600160a01b03161461126d576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600680546001600160a01b0319166001600160a01b0383169081179091556040517fd24015cc99cc1700cafca3042840a1d8ac1e3964fd2e0e37ea29c654056ee32790600090a250565b600b6020526000908152604090205460ff1681565b600054600160a01b900460ff1690565b6000816112eb57506000611313565b600760018303815481106112fb57fe5b6000918252602090912001546001600160a01b031690505b919050565b606060108054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b61018081565b60015481565b6113826124ab565b6001600160a01b031661139361149c565b6001600160a01b0316146113dc576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600a60209081526000928352604080842090915290825290205460ff1681565b6060600f8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b6000546001600160a01b031690565b6114b36124ab565b6001600160a01b03166114c461149c565b6001600160a01b03161461150d576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152600b6020908152604091829020805460ff1916851515908117909155825190815291517f46359ce9dbb6c7f9a375b44072210287916d3de725fc8927a8e762047e4a84249281900390910190a25050565b60025481565b600f81815481106110ba57fe5b60008281526009602090815260408083206001600160a01b03851684529091529020545b92915050565b600c81565b7f000000000000000000000000000000000000000000000000000000000000000081565b6060600e8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b60008043817f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000838161167857fe5b0610801591506000906116d8577f000000000000000000000000000000000000000000000000000000000000000083816116ae57fe5b067f0000000000000000000000000000000000000000000000000000000000000000039050611727565b7f0000000000000000000000000000000000000000000000000000000000000000838161170157fe5b067f00000000000000000000000000000000000000000000000000000000000000000390505b9093509150509091565b6007818154811061173e57fe5b6000918252602090912001546001600160a01b0316905081565b600e81815481106110ba57fe5b61176d6124ab565b6001600160a01b031661177e61149c565b6001600160a01b0316146117c7576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6117f16112cc565b15611836576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000611840611629565b5090508061187f5760405162461bcd60e51b815260040180806020018281038252602e815260200180612fb8602e913960400191505060405180910390fd5b6118f687878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284376000920191909152508892508791506122019050565b50505050505050565b6119076112cc565b1561194c576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b826119b5578134146119a5576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a2057524f4e475f414d4f554e540000604482015290519081900360640190fd5b6119b08382846124af565b611a0d565b34156119f25760405162461bcd60e51b81526004018080602001828103825260248152602001806132426024913960400191505060405180910390fd5b60006119fd846112dc565b9050611a0b84828486611eba565b505b505050565b600080611a1e836112dc565b6001600160a01b031660009081526008602052604090205460ff169392505050565b600d81815481106110ba57fe5b7f000000000000000000000000000000000000000000000000000000000000000081565b60055481565b611a7f6112cc565b15611ac4576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b336000908152600a6020908152604080832093835292905220805460ff19166001179055565b606060078054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b24575050505050905090565b600081565b600481565b611b5d6124ab565b6001600160a01b0316611b6e61149c565b6001600160a01b031614611bb7576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b038216611c12576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a205a45524f5f414444524553530000604482015290519081900360640190fd5b600780546001810182557fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b0319166001600160a01b0385169081179091556000908152600860205260409020805460ff19168315151790555460048110611cb45760405162461bcd60e51b81526004018080602001828103825260238152602001806131a76023913960400191505060405180910390fd5b600d8054600181810190925560007fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909101819055600e80548084019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01819055600f80548084019091557f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac8020181905560108054928301815581527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6729091018190556040516001600160a01b0385169183917fc53536963369dbfa4c398238ebb9b09fce3943a140928bd25d3052a8a9cacdaf9190a3505050565b6101c081565b611dc06124ab565b6001600160a01b0316611dd161149c565b6001600160a01b031614611e1a576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b038116611e5f5760405162461bcd60e51b8152600401808060200182810382526026815260200180612f926026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60408051636eb1769f60e11b81526001600160a01b038481166004830152306024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b158015611f0b57600080fd5b505afa158015611f1f573d6000803e3d6000fd5b505050506040513d6020811015611f3557600080fd5b5051905081811015611f785760405162461bcd60e51b815260040180806020018281038252602d8152602001806131ef602d913960400191505060405180910390fd5b604080516323b872dd60e01b81526001600160a01b038581166004830152306024830152604482018590529151918616916323b872dd916064808201926020929091908290030181600087803b158015611fd157600080fd5b505af1158015611fe5573d6000803e3d6000fd5b505050506040513d6020811015611ffb57600080fd5b5061200990508584846124af565b604080518681526001600160a01b038516602082015280820184905290517feaa18152488ce5959073c9c79c88ca90b3d96c00de1f118cfaad664c3dab06b99181900360600190a15050505050565b6000806001600160a01b0383166120b6576040805162461bcd60e51b815260206004820152601f60248201527f76616c69646174655369676e61747572653a205a45524f5f4144445245535300604482015290519081900360640190fd5b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005285601c60000152603c60002090506040518551828252606087015160f81c60408801518060608501526020890151604085015281602085015260208460808660015afa601c8314601b84141760418514166fa2a8918ca85bafe22016d0b997e4df5f600160ff1b038310161696505050815183146000811461215d57612162565b825194505b5090528115199290921691826121a95760405162461bcd60e51b815260040180806020018281038252602c815260200180613051602c913960400191505060405180910390fd5b836001600160a01b0316826001600160a01b0316146121f95760405162461bcd60e51b815260040180806020018281038252602481526020018061315e6024913960400191505060405180910390fd5b505050505050565b600061220c85612537565b90506122198582866126a2565b5050505050565b60005b60048110156124a75760006122388383612773565b9050801561249e576000826122a457600c546040516001600160a01b03909116908390600081818185875af1925050503d8060008114612294576040519150601f19603f3d011682016040523d82523d6000602084013e612299565b606091505b50508091505061241d565b60006122af846112dc565b600c546040805163095ea7b360e01b81526001600160a01b0392831660048201526024810187905290519293509083169163095ea7b3916044808201926020929091908290030181600087803b15801561230857600080fd5b505af115801561231c573d6000803e3d6000fd5b505050506040513d602081101561233257600080fd5b5050600c546040805160248101879052604480820187905282518083039091018152606490910182526020810180516001600160e01b0316631c57762b60e31b178152915181516001600160a01b0390941693919290918291908083835b602083106123af5780518252601f199092019160209182019101612390565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612411576040519150601f19603f3d011682016040523d82523d6000602084013e612416565b606091505b5090925050505b806124595760405162461bcd60e51b81526004018080602001828103825260278152602001806131376027913960400191505060405180910390fd5b612483826010858154811061246a57fe5b906000526020600020015461278490919063ffffffff16565b6010848154811061249057fe5b600091825260209091200155505b50600101612223565b5050565b3390565b60008381526009602090815260408083206001600160a01b03861684529091529020546124e2908263ffffffff61278416565b60008481526009602090815260408083206001600160a01b0387168452909152902055600d80546125199183918690811061246a57fe5b600d848154811061252657fe5b600091825260209091200155505050565b60008060008060008060008061254c896127e5565b9650965096509650965096509650600080905060008060008060448e03600654945080519350602081015192506040810151915060ac815360316001820153608c6002820153605d60038201536040600482015289602482015260648f51016000808284895afa9650508381528260208201528160408201525084612618576040805162461bcd60e51b815260206004820152601960248201527f70726f6f6620766572696669636174696f6e206661696c656400000000000000604482015290519081900360640190fd5b60018c815560028c9055612633908b9063ffffffff61278416565b600555600388905560048690556001546002546040805192835260208301919091528181018a905260608201889052518b917ff1034928243e3365c0bf101598066f51439bb2a8763ec84cf7902d8917fb974f919081900360800190a250949c9b505050505050505050505050565b60006101e0808501906101808581028701909101905b818310156118f6578251602084015160408501518215821519821519171680156127625760608701518315612747576101408801518689206001600160a01b0382166000908152600a6020908152604080832084845290915290205460ff16612739578b8b0180516060825261272f838386612a5c565b905260609a909a01995b612744838388612ba4565b50505b82156127605761016088015161275e848284612cb1565b505b505b5050506101809390930192506126b8565b602081028201610140015192915050565b6000828201838110156127de576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60008060008060008060006127f8612f4b565b60008060008060008061280c8f6004612e25565b96509650965096509650965096508660016004811061282757fe5b60200201511561283b57602087015161283e565b60015b60608801819052600090612853906002612e95565b9050806004548161286057fe5b066128ae576004546040890151146128a95760405162461bcd60e51b815260040180806020018281038252602c81526020018061307d602c913960400191505060405180910390fd5b612915565b600081600454816128bb57fe5b06826004540103905080896002600481106128d257fe5b6020020151146129135760405162461bcd60e51b815260040180806020018281038252602c81526020018061307d602c913960400191505060405180910390fd5b505b60015487146129555760405162461bcd60e51b81526004018080602001828103825260258152602001806131ca6025913960400191505060405180910390fd5b60025485146129955760405162461bcd60e51b81526004018080602001828103825260258152602001806131826025913960400191505060405180910390fd5b60035483146129d55760405162461bcd60e51b81526004018080602001828103825260258152602001806130d16025913960400191505060405180910390fd5b600554885114612a165760405162461bcd60e51b815260040180806020018281038252602381526020018061300c6023913960400191505060405180910390fd5b858489600060200201518a60016020020151858c60036020020151868e60026020020151019e509e509e509e509e509e509e505050505050505050919395979092949650565b6000806001600160a01b038316612aba576040805162461bcd60e51b815260206004820152601f60248201527f76616c69646174655369676e61747572653a205a45524f5f4144445245535300604482015290519081900360640190fd5b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005285601c52603c60002090508451818652606086015160408701518060608901526020880151604089015281602089015260208860808a60015afa601c8314601b84141760608514166fa2a8918ca85bafe22016d0b997e4df5f600160ff1b0383101616955050508551821460008114612b5857612b5d565b865193505b5085528115199290921691826121a95760405162461bcd60e51b815260040180806020018281038252602c815260200180613051602c913960400191505060405180910390fd5b60008381526009602090815260408083206001600160a01b038616845290915290205481811015612c065760405162461bcd60e51b815260040180806020018281038252602681526020018061321c6026913960400191505060405180910390fd5b612c16818363ffffffff612eee16565b60008581526009602090815260408083206001600160a01b0388168452909152902055600d8054612c6691849187908110612c4d57fe5b9060005260206000200154612eee90919063ffffffff16565b600d8581548110612c7357fe5b9060005260206000200181905550612c9282600e868154811061246a57fe5b600e8581548110612c9f57fe5b60009182526020909120015550505050565b6001600160a01b038216612d0c576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a205a45524f5f414444524553530000604482015290519081900360640190fd5b80612d6c576040516001600160a01b038316906175309085906000818181858888f193505050503d8060008114612d5f576040519150601f19603f3d011682016040523d82523d6000602084013e612d64565b606091505b505050612e07565b6000612d77826112dc565b9050806001600160a01b031663a9059cbb84866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612dd957600080fd5b505af1158015612ded573d6000803e3d6000fd5b505050506040513d6020811015612e0357600080fd5b5050505b612e1883600f838154811061246a57fe5b600f828154811061252657fe5b612e2d612f4b565b5060208281015160408085015160608087015160808089015160a08a015160c08b015160e08c01516101008d01516101208e01519c8c02909d01610140015189519586018a529985529984019690965295820192909252918201949094529692959194909392565b600082612ea4575060006115a4565b82820282848281612eb157fe5b04146127de5760405162461bcd60e51b81526004018080602001828103825260218152602001806130f66021913960400191505060405180910390fd5b600082821115612f45576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60405180608001604052806004906020820280368337509192915050565b60008085851115612f78578182fd5b83861115612f84578182fd5b505082019391909203915056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373526f6c6c75702050726f636573736f723a204553434150455f424c4f434b5f52414e47455f494e434f5252454354526f6c6c75702050726f636573736f723a205245494d42555253455f4741535f4641494c4544526f6c6c75702050726f636573736f723a2049445f4e4f545f53455155454e5449414c526f6c6c75702050726f636573736f723a20554e4b4e4f574e5f50524f564944455276616c69646174655369676e61747572653a207369676e6174757265207265636f76657279206661696c6564526f6c6c75702050726f636573736f723a20494e434f52524543545f444154415f53544152545f494e444558526f6c6c75702050726f636573736f723a20544f4b454e5f41535345545f4e4f545f4c494e4b4544526f6c6c75702050726f636573736f723a20494e434f52524543545f524f4f545f524f4f54536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572526f6c6c75702050726f636573736f723a204445504f5349545f54585f4645455f4641494c454476616c69646174655369676e61747572653a20494e56414c49445f5349474e4154555245526f6c6c75702050726f636573736f723a20494e434f52524543545f4e554c4c5f524f4f54526f6c6c75702050726f636573736f723a204d41585f41535345545f52454143484544526f6c6c75702050726f636573736f723a20494e434f52524543545f444154415f524f4f54526f6c6c75702050726f636573736f723a20494e53554646494349454e545f544f4b454e5f415050524f56414c526f6c6c75702050726f636573736f723a20494e53554646494349454e545f4445504f534954526f6c6c75702050726f636573736f723a2057524f4e475f5041594d454e545f54595045a26469706673582212202fd47ddc29f53f6efddfd5689a51af7ae006998ca8597c21d3ffbbc3cd7da41f64736f6c634300060a00334f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573738be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0000000000000000000000000dcc80db987bf63f01b7bafced6230de5002ef87400000000000000000000000000000000000000000000000000000000000011d000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000fcf75295f242c4e87203abb5d7c9bbeda90a8895
Deployed Bytecode
0x60806040526004361061027d5760003560e01c806394401d751161014f578063d1d2d95e116100c1578063e5406dbf1161007a578063e5406dbf14610b13578063e70626e614610b28578063edf49c0914610b3d578063ef76e2ee14610b52578063f0e7e29b14610b8d578063f2fde38b14610ba25761027d565b8063d1d2d95e14610a39578063d28bbda514610a6b578063d6ae328414610a95578063d8ba363714610abf578063e059d80714610ad4578063e393635514610ae95761027d565b8063b68ef55911610113578063b68ef55914610852578063be71f8a414610867578063c68dbb3714610897578063c6c62390146108c1578063ccfc2e8d146108eb578063d1c652641461091e5761027d565b806394401d75146107b0578063a009f7e4146107c5578063a3d205f4146107ef578063ae35bfc214610828578063b045009c1461083d5761027d565b80635437988d116101f35780636dff3584116101ac5780636dff3584146106e8578063715018a6146106fd578063781e04321461071257806389404a791461074b5780638da5cb5b1461076057806391dfe78f146107755761027d565b80635437988d146106055780635ad1def3146106385780635c975abb1461067f57806360a8b18a14610694578063626e1ae7146106be57806366535f30146106d35761027d565b806336ce0a921161024557806336ce0a92146104e1578063408ccbdf1461051a57806344c5125214610544578063479b3d951461055957806347a695a71461058b57806349ce468d146105f05761027d565b8063018892ac1461028257806306011a46146102f05780630d43e8ad146104745780632b7ac3f3146104a55780633248295f146104ba575b600080fd5b34801561028e57600080fd5b506102ee60048036036101208110156102a657600080fd5b508035906020810135906001600160a01b03604082013581169160608101359091169060808101359060a08101359060ff60c0820135169060e0810135906101000135610bd5565b005b3480156102fc57600080fd5b506102ee600480360360e081101561031357600080fd5b810190602081018135600160201b81111561032d57600080fd5b82018360208201111561033f57600080fd5b803590602001918460018302840111600160201b8311171561036057600080fd5b919390929091602081019035600160201b81111561037d57600080fd5b82018360208201111561038f57600080fd5b803590602001918460018302840111600160201b831117156103b057600080fd5b919390929091602081019035600160201b8111156103cd57600080fd5b8201836020820111156103df57600080fd5b803590602001918460018302840111600160201b8311171561040057600080fd5b919390929091602081019035600160201b81111561041d57600080fd5b82018360208201111561042f57600080fd5b803590602001918460018302840111600160201b8311171561045057600080fd5b91935091506001600160a01b03813581169160208101359091169060400135610cd8565b34801561048057600080fd5b5061048961106c565b604080516001600160a01b039092168252519081900360200190f35b3480156104b157600080fd5b5061048961107b565b3480156104c657600080fd5b506104cf61108a565b60408051918252519081900360200190f35b3480156104ed57600080fd5b506104cf6004803603604081101561050457600080fd5b50803590602001356001600160a01b0316611090565b34801561052657600080fd5b506104cf6004803603602081101561053d57600080fd5b50356110ad565b34801561055057600080fd5b506104cf6110cb565b34801561056557600080fd5b506102ee6004803603604081101561057c57600080fd5b508035906020013515156110d0565b34801561059757600080fd5b506105a06111ad565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156105dc5781810151838201526020016105c4565b505050509050019250505060405180910390f35b3480156105fc57600080fd5b506104cf611205565b34801561061157600080fd5b506102ee6004803603602081101561062857600080fd5b50356001600160a01b031661120b565b34801561064457600080fd5b5061066b6004803603602081101561065b57600080fd5b50356001600160a01b03166112b7565b604080519115158252519081900360200190f35b34801561068b57600080fd5b5061066b6112cc565b3480156106a057600080fd5b50610489600480360360208110156106b757600080fd5b50356112dc565b3480156106ca57600080fd5b506105a0611318565b3480156106df57600080fd5b506104cf61136e565b3480156106f457600080fd5b506104cf611374565b34801561070957600080fd5b506102ee61137a565b34801561071e57600080fd5b5061066b6004803603604081101561073557600080fd5b506001600160a01b038135169060200135611426565b34801561075757600080fd5b506105a0611446565b34801561076c57600080fd5b5061048961149c565b34801561078157600080fd5b506102ee6004803603604081101561079857600080fd5b506001600160a01b03813516906020013515156114ab565b3480156107bc57600080fd5b506104cf61156d565b3480156107d157600080fd5b506104cf600480360360208110156107e857600080fd5b5035611573565b3480156107fb57600080fd5b506104cf6004803603604081101561081257600080fd5b50803590602001356001600160a01b0316611580565b34801561083457600080fd5b506104cf6115aa565b34801561084957600080fd5b506104cf6115af565b34801561085e57600080fd5b506105a06115d3565b34801561087357600080fd5b5061087c611629565b60408051921515835260208301919091528051918290030190f35b3480156108a357600080fd5b50610489600480360360208110156108ba57600080fd5b5035611731565b3480156108cd57600080fd5b506104cf600480360360208110156108e457600080fd5b5035611758565b3480156108f757600080fd5b506102ee6004803603602081101561090e57600080fd5b50356001600160a01b0316611765565b34801561092a57600080fd5b506102ee6004803603606081101561094157600080fd5b810190602081018135600160201b81111561095b57600080fd5b82018360208201111561096d57600080fd5b803590602001918460018302840111600160201b8311171561098e57600080fd5b919390929091602081019035600160201b8111156109ab57600080fd5b8201836020820111156109bd57600080fd5b803590602001918460018302840111600160201b831117156109de57600080fd5b919390929091602081019035600160201b8111156109fb57600080fd5b820183602082011115610a0d57600080fd5b803590602001918460018302840111600160201b83111715610a2e57600080fd5b5090925090506117e9565b6102ee60048036036060811015610a4f57600080fd5b50803590602081013590604001356001600160a01b03166118ff565b348015610a7757600080fd5b5061066b60048036036020811015610a8e57600080fd5b5035611a12565b348015610aa157600080fd5b506104cf60048036036020811015610ab857600080fd5b5035611a40565b348015610acb57600080fd5b506104cf611a4d565b348015610ae057600080fd5b506104cf611a71565b348015610af557600080fd5b506102ee60048036036020811015610b0c57600080fd5b5035611a77565b348015610b1f57600080fd5b506105a0611aea565b348015610b3457600080fd5b506104cf611b4b565b348015610b4957600080fd5b506104cf611b50565b348015610b5e57600080fd5b506102ee60048036036040811015610b7557600080fd5b506001600160a01b0381351690602001351515611b55565b348015610b9957600080fd5b506104cf611db2565b348015610bae57600080fd5b506102ee60048036036020811015610bc557600080fd5b50356001600160a01b0316611db8565b610bdd6112cc565b15610c22576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000610c2d8a6112dc565b6040805163d505accf60e01b81526001600160a01b038b811660048301528a81166024830152604482018a90526064820189905260ff8816608483015260a4820187905260c4820186905291519293509083169163d505accf9160e48082019260009290919082900301818387803b158015610ca857600080fd5b505af1158015610cbc573d6000803e3d6000fd5b50505050610ccc8a828a8c611eba565b50505050505050505050565b610ce06112cc565b15610d25576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60005a6001600160a01b0385166000908152600b602052604090205490915060ff16610d825760405162461bcd60e51b815260040180806020018281038252602281526020018061302f6022913960400191505060405180910390fd5b60608c8c6000906004600a0160200292610d9e93929190612f69565b600c54604051879187916001600160a01b03909116906020018086868082843780830192505050846001600160a01b03166001600160a01b031660601b8152601401838152602001826001600160a01b03166001600160a01b031660601b8152601401955050505050506040516020818303038152906040529050610e62818051906020012088888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612058915050565b610eea8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508d91506122019050565b610f298d8d8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061222092505050565b600c546000906001600160a01b03165a604080519186036024830152604482018790526001600160a01b03881660648084019190915281518084039091018152608490920181526020820180516001600160e01b03166356aa719960e01b17815290518251909182918083835b60208310610fb55780518252601f199092019160209182019101610f96565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611017576040519150601f19603f3d011682016040523d82523d6000602084013e61101c565b606091505b505090508061105c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612fe66026913960400191505060405180910390fd5b5050505050505050505050505050565b600c546001600160a01b031681565b6006546001600160a01b031681565b60035481565b600960209081526000928352604080842090915290825290205481565b601081815481106110ba57fe5b600091825260209091200154905081565b600e81565b6110d86124ab565b6001600160a01b03166110e961149c565b6001600160a01b031614611132576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600061113d836112dc565b90506001600160a01b0381166111845760405162461bcd60e51b81526004018080602001828103825260288152602001806130a96028913960400191505060405180910390fd5b6001600160a01b03166000908152600860205260409020805460ff191691151591909117905550565b6060600d8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020905b8154815260200190600101908083116111e7575b5050505050905090565b60045481565b6112136124ab565b6001600160a01b031661122461149c565b6001600160a01b03161461126d576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600680546001600160a01b0319166001600160a01b0383169081179091556040517fd24015cc99cc1700cafca3042840a1d8ac1e3964fd2e0e37ea29c654056ee32790600090a250565b600b6020526000908152604090205460ff1681565b600054600160a01b900460ff1690565b6000816112eb57506000611313565b600760018303815481106112fb57fe5b6000918252602090912001546001600160a01b031690505b919050565b606060108054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b61018081565b60015481565b6113826124ab565b6001600160a01b031661139361149c565b6001600160a01b0316146113dc576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600a60209081526000928352604080842090915290825290205460ff1681565b6060600f8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b6000546001600160a01b031690565b6114b36124ab565b6001600160a01b03166114c461149c565b6001600160a01b03161461150d576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152600b6020908152604091829020805460ff1916851515908117909155825190815291517f46359ce9dbb6c7f9a375b44072210287916d3de725fc8927a8e762047e4a84249281900390910190a25050565b60025481565b600f81815481106110ba57fe5b60008281526009602090815260408083206001600160a01b03851684529091529020545b92915050565b600c81565b7f00000000000000000000000000000000000000000000000000000000000011d081565b6060600e8054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020908154815260200190600101908083116111e7575050505050905090565b60008043817f00000000000000000000000000000000000000000000000000000000000011d07f00000000000000000000000000000000000000000000000000000000000012c0838161167857fe5b0610801591506000906116d8577f00000000000000000000000000000000000000000000000000000000000012c083816116ae57fe5b067f00000000000000000000000000000000000000000000000000000000000012c0039050611727565b7f00000000000000000000000000000000000000000000000000000000000012c0838161170157fe5b067f00000000000000000000000000000000000000000000000000000000000011d00390505b9093509150509091565b6007818154811061173e57fe5b6000918252602090912001546001600160a01b0316905081565b600e81815481106110ba57fe5b61176d6124ab565b6001600160a01b031661177e61149c565b6001600160a01b0316146117c7576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6117f16112cc565b15611836576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000611840611629565b5090508061187f5760405162461bcd60e51b815260040180806020018281038252602e815260200180612fb8602e913960400191505060405180910390fd5b6118f687878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284376000920191909152508892508791506122019050565b50505050505050565b6119076112cc565b1561194c576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b826119b5578134146119a5576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a2057524f4e475f414d4f554e540000604482015290519081900360640190fd5b6119b08382846124af565b611a0d565b34156119f25760405162461bcd60e51b81526004018080602001828103825260248152602001806132426024913960400191505060405180910390fd5b60006119fd846112dc565b9050611a0b84828486611eba565b505b505050565b600080611a1e836112dc565b6001600160a01b031660009081526008602052604090205460ff169392505050565b600d81815481106110ba57fe5b7f00000000000000000000000000000000000000000000000000000000000012c081565b60055481565b611a7f6112cc565b15611ac4576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b336000908152600a6020908152604080832093835292905220805460ff19166001179055565b606060078054806020026020016040519081016040528092919081815260200182805480156111fb57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b24575050505050905090565b600081565b600481565b611b5d6124ab565b6001600160a01b0316611b6e61149c565b6001600160a01b031614611bb7576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b038216611c12576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a205a45524f5f414444524553530000604482015290519081900360640190fd5b600780546001810182557fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b0319166001600160a01b0385169081179091556000908152600860205260409020805460ff19168315151790555460048110611cb45760405162461bcd60e51b81526004018080602001828103825260238152602001806131a76023913960400191505060405180910390fd5b600d8054600181810190925560007fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909101819055600e80548084019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01819055600f80548084019091557f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac8020181905560108054928301815581527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6729091018190556040516001600160a01b0385169183917fc53536963369dbfa4c398238ebb9b09fce3943a140928bd25d3052a8a9cacdaf9190a3505050565b6101c081565b611dc06124ab565b6001600160a01b0316611dd161149c565b6001600160a01b031614611e1a576040805162461bcd60e51b81526020600482018190526024820152600080516020613117833981519152604482015290519081900360640190fd5b6001600160a01b038116611e5f5760405162461bcd60e51b8152600401808060200182810382526026815260200180612f926026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60408051636eb1769f60e11b81526001600160a01b038481166004830152306024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b158015611f0b57600080fd5b505afa158015611f1f573d6000803e3d6000fd5b505050506040513d6020811015611f3557600080fd5b5051905081811015611f785760405162461bcd60e51b815260040180806020018281038252602d8152602001806131ef602d913960400191505060405180910390fd5b604080516323b872dd60e01b81526001600160a01b038581166004830152306024830152604482018590529151918616916323b872dd916064808201926020929091908290030181600087803b158015611fd157600080fd5b505af1158015611fe5573d6000803e3d6000fd5b505050506040513d6020811015611ffb57600080fd5b5061200990508584846124af565b604080518681526001600160a01b038516602082015280820184905290517feaa18152488ce5959073c9c79c88ca90b3d96c00de1f118cfaad664c3dab06b99181900360600190a15050505050565b6000806001600160a01b0383166120b6576040805162461bcd60e51b815260206004820152601f60248201527f76616c69646174655369676e61747572653a205a45524f5f4144445245535300604482015290519081900360640190fd5b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005285601c60000152603c60002090506040518551828252606087015160f81c60408801518060608501526020890151604085015281602085015260208460808660015afa601c8314601b84141760418514166fa2a8918ca85bafe22016d0b997e4df5f600160ff1b038310161696505050815183146000811461215d57612162565b825194505b5090528115199290921691826121a95760405162461bcd60e51b815260040180806020018281038252602c815260200180613051602c913960400191505060405180910390fd5b836001600160a01b0316826001600160a01b0316146121f95760405162461bcd60e51b815260040180806020018281038252602481526020018061315e6024913960400191505060405180910390fd5b505050505050565b600061220c85612537565b90506122198582866126a2565b5050505050565b60005b60048110156124a75760006122388383612773565b9050801561249e576000826122a457600c546040516001600160a01b03909116908390600081818185875af1925050503d8060008114612294576040519150601f19603f3d011682016040523d82523d6000602084013e612299565b606091505b50508091505061241d565b60006122af846112dc565b600c546040805163095ea7b360e01b81526001600160a01b0392831660048201526024810187905290519293509083169163095ea7b3916044808201926020929091908290030181600087803b15801561230857600080fd5b505af115801561231c573d6000803e3d6000fd5b505050506040513d602081101561233257600080fd5b5050600c546040805160248101879052604480820187905282518083039091018152606490910182526020810180516001600160e01b0316631c57762b60e31b178152915181516001600160a01b0390941693919290918291908083835b602083106123af5780518252601f199092019160209182019101612390565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612411576040519150601f19603f3d011682016040523d82523d6000602084013e612416565b606091505b5090925050505b806124595760405162461bcd60e51b81526004018080602001828103825260278152602001806131376027913960400191505060405180910390fd5b612483826010858154811061246a57fe5b906000526020600020015461278490919063ffffffff16565b6010848154811061249057fe5b600091825260209091200155505b50600101612223565b5050565b3390565b60008381526009602090815260408083206001600160a01b03861684529091529020546124e2908263ffffffff61278416565b60008481526009602090815260408083206001600160a01b0387168452909152902055600d80546125199183918690811061246a57fe5b600d848154811061252657fe5b600091825260209091200155505050565b60008060008060008060008061254c896127e5565b9650965096509650965096509650600080905060008060008060448e03600654945080519350602081015192506040810151915060ac815360316001820153608c6002820153605d60038201536040600482015289602482015260648f51016000808284895afa9650508381528260208201528160408201525084612618576040805162461bcd60e51b815260206004820152601960248201527f70726f6f6620766572696669636174696f6e206661696c656400000000000000604482015290519081900360640190fd5b60018c815560028c9055612633908b9063ffffffff61278416565b600555600388905560048690556001546002546040805192835260208301919091528181018a905260608201889052518b917ff1034928243e3365c0bf101598066f51439bb2a8763ec84cf7902d8917fb974f919081900360800190a250949c9b505050505050505050505050565b60006101e0808501906101808581028701909101905b818310156118f6578251602084015160408501518215821519821519171680156127625760608701518315612747576101408801518689206001600160a01b0382166000908152600a6020908152604080832084845290915290205460ff16612739578b8b0180516060825261272f838386612a5c565b905260609a909a01995b612744838388612ba4565b50505b82156127605761016088015161275e848284612cb1565b505b505b5050506101809390930192506126b8565b602081028201610140015192915050565b6000828201838110156127de576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60008060008060008060006127f8612f4b565b60008060008060008061280c8f6004612e25565b96509650965096509650965096508660016004811061282757fe5b60200201511561283b57602087015161283e565b60015b60608801819052600090612853906002612e95565b9050806004548161286057fe5b066128ae576004546040890151146128a95760405162461bcd60e51b815260040180806020018281038252602c81526020018061307d602c913960400191505060405180910390fd5b612915565b600081600454816128bb57fe5b06826004540103905080896002600481106128d257fe5b6020020151146129135760405162461bcd60e51b815260040180806020018281038252602c81526020018061307d602c913960400191505060405180910390fd5b505b60015487146129555760405162461bcd60e51b81526004018080602001828103825260258152602001806131ca6025913960400191505060405180910390fd5b60025485146129955760405162461bcd60e51b81526004018080602001828103825260258152602001806131826025913960400191505060405180910390fd5b60035483146129d55760405162461bcd60e51b81526004018080602001828103825260258152602001806130d16025913960400191505060405180910390fd5b600554885114612a165760405162461bcd60e51b815260040180806020018281038252602381526020018061300c6023913960400191505060405180910390fd5b858489600060200201518a60016020020151858c60036020020151868e60026020020151019e509e509e509e509e509e509e505050505050505050919395979092949650565b6000806001600160a01b038316612aba576040805162461bcd60e51b815260206004820152601f60248201527f76616c69646174655369676e61747572653a205a45524f5f4144445245535300604482015290519081900360640190fd5b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005285601c52603c60002090508451818652606086015160408701518060608901526020880151604089015281602089015260208860808a60015afa601c8314601b84141760608514166fa2a8918ca85bafe22016d0b997e4df5f600160ff1b0383101616955050508551821460008114612b5857612b5d565b865193505b5085528115199290921691826121a95760405162461bcd60e51b815260040180806020018281038252602c815260200180613051602c913960400191505060405180910390fd5b60008381526009602090815260408083206001600160a01b038616845290915290205481811015612c065760405162461bcd60e51b815260040180806020018281038252602681526020018061321c6026913960400191505060405180910390fd5b612c16818363ffffffff612eee16565b60008581526009602090815260408083206001600160a01b0388168452909152902055600d8054612c6691849187908110612c4d57fe5b9060005260206000200154612eee90919063ffffffff16565b600d8581548110612c7357fe5b9060005260206000200181905550612c9282600e868154811061246a57fe5b600e8581548110612c9f57fe5b60009182526020909120015550505050565b6001600160a01b038216612d0c576040805162461bcd60e51b815260206004820152601e60248201527f526f6c6c75702050726f636573736f723a205a45524f5f414444524553530000604482015290519081900360640190fd5b80612d6c576040516001600160a01b038316906175309085906000818181858888f193505050503d8060008114612d5f576040519150601f19603f3d011682016040523d82523d6000602084013e612d64565b606091505b505050612e07565b6000612d77826112dc565b9050806001600160a01b031663a9059cbb84866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612dd957600080fd5b505af1158015612ded573d6000803e3d6000fd5b505050506040513d6020811015612e0357600080fd5b5050505b612e1883600f838154811061246a57fe5b600f828154811061252657fe5b612e2d612f4b565b5060208281015160408085015160608087015160808089015160a08a015160c08b015160e08c01516101008d01516101208e01519c8c02909d01610140015189519586018a529985529984019690965295820192909252918201949094529692959194909392565b600082612ea4575060006115a4565b82820282848281612eb157fe5b04146127de5760405162461bcd60e51b81526004018080602001828103825260218152602001806130f66021913960400191505060405180910390fd5b600082821115612f45576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60405180608001604052806004906020820280368337509192915050565b60008085851115612f78578182fd5b83861115612f84578182fd5b505082019391909203915056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373526f6c6c75702050726f636573736f723a204553434150455f424c4f434b5f52414e47455f494e434f5252454354526f6c6c75702050726f636573736f723a205245494d42555253455f4741535f4641494c4544526f6c6c75702050726f636573736f723a2049445f4e4f545f53455155454e5449414c526f6c6c75702050726f636573736f723a20554e4b4e4f574e5f50524f564944455276616c69646174655369676e61747572653a207369676e6174757265207265636f76657279206661696c6564526f6c6c75702050726f636573736f723a20494e434f52524543545f444154415f53544152545f494e444558526f6c6c75702050726f636573736f723a20544f4b454e5f41535345545f4e4f545f4c494e4b4544526f6c6c75702050726f636573736f723a20494e434f52524543545f524f4f545f524f4f54536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572526f6c6c75702050726f636573736f723a204445504f5349545f54585f4645455f4641494c454476616c69646174655369676e61747572653a20494e56414c49445f5349474e4154555245526f6c6c75702050726f636573736f723a20494e434f52524543545f4e554c4c5f524f4f54526f6c6c75702050726f636573736f723a204d41585f41535345545f52454143484544526f6c6c75702050726f636573736f723a20494e434f52524543545f444154415f524f4f54526f6c6c75702050726f636573736f723a20494e53554646494349454e545f544f4b454e5f415050524f56414c526f6c6c75702050726f636573736f723a20494e53554646494349454e545f4445504f534954526f6c6c75702050726f636573736f723a2057524f4e475f5041594d454e545f54595045a26469706673582212202fd47ddc29f53f6efddfd5689a51af7ae006998ca8597c21d3ffbbc3cd7da41f64736f6c634300060a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000dcc80db987bf63f01b7bafced6230de5002ef87400000000000000000000000000000000000000000000000000000000000011d000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000fcf75295f242c4e87203abb5d7c9bbeda90a8895
-----Decoded View---------------
Arg [0] : _verifierAddress (address): 0xDCC80dB987bf63f01b7bafCED6230DE5002eF874
Arg [1] : _escapeBlockLowerBound (uint256): 4560
Arg [2] : _escapeBlockUpperBound (uint256): 4800
Arg [3] : _contractOwner (address): 0xFcF75295f242C4E87203Abb5d7C9BbEda90a8895
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000dcc80db987bf63f01b7bafced6230de5002ef874
Arg [1] : 00000000000000000000000000000000000000000000000000000000000011d0
Arg [2] : 00000000000000000000000000000000000000000000000000000000000012c0
Arg [3] : 000000000000000000000000fcf75295f242c4e87203abb5d7c9bbeda90a8895
Loading...
Loading
Loading...
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.
[ 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.