Feature Tip: Add private address tag to any address under My Name Tag !
Latest 25 from a total of 95,275 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Process Rollup | 24324547 | 33 days ago | IN | 0 ETH | 0.00129109 | ||||
| Process Rollup | 24025330 | 75 days ago | IN | 0 ETH | 0.00129617 | ||||
| Process Rollup | 24025318 | 75 days ago | IN | 0 ETH | 0.00132538 | ||||
| Process Rollup | 24025304 | 75 days ago | IN | 0 ETH | 0.0012568 | ||||
| Process Rollup | 24025292 | 75 days ago | IN | 0 ETH | 0.00134031 | ||||
| Process Rollup | 24025039 | 75 days ago | IN | 0 ETH | 0.00129724 | ||||
| Process Rollup | 24025018 | 75 days ago | IN | 0 ETH | 0.00136945 | ||||
| Process Rollup | 24025006 | 75 days ago | IN | 0 ETH | 0.00126991 | ||||
| Process Rollup | 24024998 | 75 days ago | IN | 0 ETH | 0.00124925 | ||||
| Process Rollup | 24024883 | 75 days ago | IN | 0 ETH | 0.00124995 | ||||
| Process Rollup | 24024856 | 75 days ago | IN | 0 ETH | 0.00132748 | ||||
| Process Rollup | 24024844 | 75 days ago | IN | 0 ETH | 0.00132833 | ||||
| Process Rollup | 24024817 | 75 days ago | IN | 0 ETH | 0.00125576 | ||||
| Process Rollup | 24024813 | 75 days ago | IN | 0 ETH | 0.00124958 | ||||
| Process Rollup | 23944202 | 86 days ago | IN | 0 ETH | 0.00128147 | ||||
| Process Rollup | 23944169 | 86 days ago | IN | 0 ETH | 0.0012385 | ||||
| Process Rollup | 23944163 | 86 days ago | IN | 0 ETH | 0.00123161 | ||||
| Process Rollup | 23497979 | 149 days ago | IN | 0 ETH | 0.00199079 | ||||
| Process Rollup | 23497614 | 149 days ago | IN | 0 ETH | 0.00156381 | ||||
| Process Rollup | 23497325 | 149 days ago | IN | 0 ETH | 0.00148996 | ||||
| Process Rollup | 23496872 | 149 days ago | IN | 0 ETH | 0.00137787 | ||||
| Process Rollup | 23490076 | 150 days ago | IN | 0 ETH | 0.00161584 | ||||
| 0x68747470 | 22420811 | 300 days ago | IN | 0 ETH | 0.00001722 | ||||
| 0x68747470 | 22420498 | 300 days ago | IN | 0 ETH | 0.00001722 | ||||
| 0x68747470 | 22420189 | 300 days ago | IN | 0 ETH | 0.00001722 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 24324547 | 33 days ago | 1 ETH | ||||
| Transfer | 24025330 | 75 days ago | 0.01 ETH | ||||
| Transfer | 24025039 | 75 days ago | 0.201 ETH | ||||
| Transfer | 23944202 | 86 days ago | 0.1 ETH | ||||
| Transfer | 23497979 | 149 days ago | 13.043429 ETH | ||||
| Transfer | 23497614 | 149 days ago | 6 ETH | ||||
| Transfer | 23497325 | 149 days ago | 0.3 ETH | ||||
| Transfer | 23496872 | 149 days ago | 0.1 ETH | ||||
| Transfer | 23490076 | 150 days ago | 0.1 ETH | ||||
| Transfer | 21204471 | 469 days ago | 0.19879 ETH | ||||
| Transfer | 20678856 | 543 days ago | 0.010015 ETH | ||||
| Transfer | 20665493 | 545 days ago | 0.01 ETH | ||||
| Transfer | 20665452 | 545 days ago | 0.01092 ETH | ||||
| Transfer | 20665415 | 545 days ago | 0.01724 ETH | ||||
| Transfer | 20665378 | 545 days ago | 0.02223 ETH | ||||
| Transfer | 20665322 | 545 days ago | 0.01 ETH | ||||
| Transfer | 20665277 | 545 days ago | 0.01 ETH | ||||
| Transfer | 20663160 | 545 days ago | 0.1 ETH | ||||
| Transfer | 20635141 | 549 days ago | 0.02092 ETH | ||||
| Transfer | 20635094 | 549 days ago | 0.01 ETH | ||||
| Transfer | 20635042 | 549 days ago | 0.05 ETH | ||||
| Transfer | 20634990 | 549 days ago | 0.01 ETH | ||||
| Transfer | 20634903 | 549 days ago | 0.011146 ETH | ||||
| Transfer | 20634781 | 549 days ago | 0.06613 ETH | ||||
| Transfer | 20634723 | 549 days ago | 0.05 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
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
Contract ABI
API[{"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
Net Worth in USD
$2,437,555.03
Net Worth in ETH
1,234.10435
Token Allocations
ETH
93.77%
DAI
6.16%
RENBTC
0.06%
Others
0.00%
Multichain Portfolio | 33 Chains
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.